mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-10 01:33:54 +01:00
Almost done converting blade to react.
This commit is contained in:
parent
cc8de58cff
commit
4865563f26
@ -89,6 +89,32 @@ import {
|
||||
completeAction,
|
||||
processAction,
|
||||
startAction,
|
||||
calculateStaminaGainPerSecond,
|
||||
calculateMaxStamina,
|
||||
create,
|
||||
prestige,
|
||||
storeCycles,
|
||||
getCurrentCity,
|
||||
upgradeSkill,
|
||||
postToConsole,
|
||||
log,
|
||||
calculateStaminaPenalty,
|
||||
getTypeAndNameFromActionId,
|
||||
getContractNamesNetscriptFn,
|
||||
getOperationNamesNetscriptFn,
|
||||
getBlackOpNamesNetscriptFn,
|
||||
getGeneralActionNamesNetscriptFn,
|
||||
getSkillNamesNetscriptFn,
|
||||
startActionNetscriptFn,
|
||||
getActionTimeNetscriptFn,
|
||||
getActionEstimatedSuccessChanceNetscriptFn,
|
||||
getActionCountRemainingNetscriptFn,
|
||||
getSkillLevelNetscriptFn,
|
||||
getSkillUpgradeCostNetscriptFn,
|
||||
upgradeSkillNetscriptFn,
|
||||
getTeamSizeNetscriptFn,
|
||||
setTeamSizeNetscriptFn,
|
||||
joinBladeburnerFactionNetscriptFn,
|
||||
} from "./Bladeburner/Bladeburner";
|
||||
|
||||
function Bladeburner(params={}) {
|
||||
@ -130,7 +156,7 @@ function Bladeburner(params={}) {
|
||||
// Max Stamina is based on stats and Bladeburner-specific bonuses
|
||||
this.staminaBonus = 0; // Gained from training
|
||||
this.maxStamina = 0;
|
||||
this.calculateMaxStamina();
|
||||
calculateMaxStamina(this, Player);
|
||||
this.stamina = this.maxStamina;
|
||||
|
||||
/**
|
||||
@ -168,622 +194,40 @@ function Bladeburner(params={}) {
|
||||
];
|
||||
|
||||
// Initialization
|
||||
if (params.new) {this.create();}
|
||||
if (params.new) create(this);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.prestige = function() {
|
||||
resetAction(this);
|
||||
var bladeburnerFac = Factions["Bladeburners"];
|
||||
if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
|
||||
joinFaction(bladeburnerFac);
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.create = function() {
|
||||
this.contracts["Tracking"] = new Contract({
|
||||
name:"Tracking",
|
||||
desc:"Identify and locate Synthoids. This contract involves reconnaissance " +
|
||||
"and information-gathering ONLY. Do NOT engage. Stealth is of the utmost importance.<br><br>" +
|
||||
"Successfully completing Tracking contracts will slightly improve your Synthoid population estimate for " +
|
||||
"whatever city you are currently in.",
|
||||
baseDifficulty:125,difficultyFac:1.02,rewardFac:1.041,
|
||||
rankGain:0.3, hpLoss:0.5,
|
||||
count:getRandomInt(25, 150), countGrowth:getRandomInt(5, 75)/10,
|
||||
weights:{hack:0,str:0.05,def:0.05,dex:0.35,agi:0.35,cha:0.1, int:0.05},
|
||||
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.9, int:1},
|
||||
isStealth:true,
|
||||
});
|
||||
this.contracts["Bounty Hunter"] = new Contract({
|
||||
name:"Bounty Hunter",
|
||||
desc:"Hunt down and capture fugitive Synthoids. These Synthoids are wanted alive.<br><br>" +
|
||||
"Successfully completing a Bounty Hunter contract will lower the population in your " +
|
||||
"current city, and will also increase its chaos level.",
|
||||
baseDifficulty:250, difficultyFac:1.04,rewardFac:1.085,
|
||||
rankGain:0.9, hpLoss:1,
|
||||
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10,
|
||||
weights:{hack:0,str:0.15,def:0.15,dex:0.25,agi:0.25,cha:0.1, int:0.1},
|
||||
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
|
||||
isKill:true,
|
||||
});
|
||||
this.contracts["Retirement"] = new Contract({
|
||||
name:"Retirement",
|
||||
desc:"Hunt down and retire (kill) rogue Synthoids.<br><br>" +
|
||||
"Successfully completing a Retirement contract will lower the population in your current " +
|
||||
"city, and will also increase its chaos level.",
|
||||
baseDifficulty:200, difficultyFac:1.03, rewardFac:1.065,
|
||||
rankGain:0.6, hpLoss:1,
|
||||
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10,
|
||||
weights:{hack:0,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0.1, int:0.1},
|
||||
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
|
||||
isKill:true,
|
||||
});
|
||||
|
||||
this.operations["Investigation"] = new Operation({
|
||||
name:"Investigation",
|
||||
desc:"As a field agent, investigate and identify Synthoid " +
|
||||
"populations, movements, and operations.<br><br>Successful " +
|
||||
"Investigation ops will increase the accuracy of your " +
|
||||
"synthoid data.<br><br>" +
|
||||
"You will NOT lose HP from failed Investigation ops.",
|
||||
baseDifficulty:400, difficultyFac:1.03,rewardFac:1.07,reqdRank:25,
|
||||
rankGain:2.2, rankLoss:0.2,
|
||||
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10,
|
||||
weights:{hack:0.25,str:0.05,def:0.05,dex:0.2,agi:0.1,cha:0.25, int:0.1},
|
||||
decays:{hack:0.85,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
|
||||
isStealth:true,
|
||||
});
|
||||
this.operations["Undercover Operation"] = new Operation({
|
||||
name:"Undercover Operation",
|
||||
desc:"Conduct undercover operations to identify hidden " +
|
||||
"and underground Synthoid communities and organizations.<br><br>" +
|
||||
"Successful Undercover ops will increase the accuracy of your synthoid " +
|
||||
"data.",
|
||||
baseDifficulty:500, difficultyFac:1.04, rewardFac:1.09, reqdRank:100,
|
||||
rankGain:4.4, rankLoss:0.4, hpLoss:2,
|
||||
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10,
|
||||
weights:{hack:0.2,str:0.05,def:0.05,dex:0.2,agi:0.2,cha:0.2, int:0.1},
|
||||
decays:{hack:0.8,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
|
||||
isStealth:true,
|
||||
});
|
||||
this.operations["Sting Operation"] = new Operation({
|
||||
name:"Sting Operation",
|
||||
desc:"Conduct a sting operation to bait and capture particularly " +
|
||||
"notorious Synthoid criminals.",
|
||||
baseDifficulty:650, difficultyFac:1.04, rewardFac:1.095, reqdRank:500,
|
||||
rankGain:5.5, rankLoss:0.5, hpLoss:2.5,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(3, 40)/10,
|
||||
weights:{hack:0.25,str:0.05,def:0.05,dex:0.25,agi:0.1,cha:0.2, int:0.1},
|
||||
decays:{hack:0.8,str:0.85,def:0.85,dex:0.85,agi:0.85,cha:0.7, int:0.9},
|
||||
isStealth:true,
|
||||
});
|
||||
this.operations["Raid"] = new Operation({
|
||||
name:"Raid",
|
||||
desc:"Lead an assault on a known Synthoid community. Note that " +
|
||||
"there must be an existing Synthoid community in your current city " +
|
||||
"in order for this Operation to be successful.",
|
||||
baseDifficulty:800, difficultyFac:1.045, rewardFac:1.1, reqdRank:3000,
|
||||
rankGain:55,rankLoss:2.5,hpLoss:50,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(2, 40)/10,
|
||||
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
|
||||
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
|
||||
isKill:true,
|
||||
});
|
||||
this.operations["Stealth Retirement Operation"] = new Operation({
|
||||
name:"Stealth Retirement Operation",
|
||||
desc:"Lead a covert operation to retire Synthoids. The " +
|
||||
"objective is to complete the task without " +
|
||||
"drawing any attention. Stealth and discretion are key.",
|
||||
baseDifficulty:1000, difficultyFac:1.05, rewardFac:1.11, reqdRank:20e3,
|
||||
rankGain:22, rankLoss:2, hpLoss:10,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10,
|
||||
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
|
||||
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
|
||||
isStealth:true, isKill:true,
|
||||
});
|
||||
this.operations["Assassination"] = new Operation({
|
||||
name:"Assassination",
|
||||
desc:"Assassinate Synthoids that have been identified as " +
|
||||
"important, high-profile social and political leaders " +
|
||||
"in the Synthoid communities.",
|
||||
baseDifficulty:1500, difficultyFac:1.06, rewardFac:1.14, reqdRank:50e3,
|
||||
rankGain:44, rankLoss:4, hpLoss:5,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10,
|
||||
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
|
||||
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.8},
|
||||
isStealth:true, isKill:true,
|
||||
});
|
||||
}
|
||||
|
||||
Bladeburner.prototype.storeCycles = function(numCycles=1) {
|
||||
this.storedCycles += numCycles;
|
||||
}
|
||||
|
||||
Bladeburner.prototype.process = function() {
|
||||
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
|
||||
if (redPillFlag === false && this.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
return hackWorldDaemon(Player.bitNodeN);
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
if (Augmentations[AugmentationNames.BladesSimulacrum].owned === false && Player.isWorking) {
|
||||
if (this.action.type !== ActionTypes["Idle"]) {
|
||||
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
|
||||
if (this.automateEnabled) {
|
||||
msg += `<br><br>Your automation was disabled as well. You will have to re-enable it through the Bladeburner console`
|
||||
this.automateEnabled = false;
|
||||
}
|
||||
if (!Settings.SuppressBladeburnerPopup) {
|
||||
dialogBoxCreate(msg);
|
||||
}
|
||||
}
|
||||
resetAction(this);
|
||||
}
|
||||
|
||||
// If the Player has no Stamina, set action to idle
|
||||
if (this.stamina <= 0) {
|
||||
this.log("Your Bladeburner action was cancelled because your stamina hit 0");
|
||||
resetAction(this);
|
||||
}
|
||||
|
||||
// A 'tick' for this mechanic is one second (= 5 game cycles)
|
||||
if (this.storedCycles >= BladeburnerConstants.CyclesPerSecond) {
|
||||
var seconds = Math.floor(this.storedCycles / BladeburnerConstants.CyclesPerSecond);
|
||||
seconds = Math.min(seconds, 5); // Max of 5 'ticks'
|
||||
this.storedCycles -= seconds * BladeburnerConstants.CyclesPerSecond;
|
||||
|
||||
// Stamina
|
||||
this.calculateMaxStamina();
|
||||
this.stamina += (this.calculateStaminaGainPerSecond() * seconds);
|
||||
this.stamina = Math.min(this.maxStamina, this.stamina);
|
||||
|
||||
// Count increase for contracts/operations
|
||||
for (let contract of Object.values(this.contracts)) {
|
||||
contract.count += (seconds * contract.countGrowth/BladeburnerConstants.ActionCountGrowthPeriod);
|
||||
}
|
||||
for (let op of Object.values(this.operations)) {
|
||||
op.count += (seconds * op.countGrowth/BladeburnerConstants.ActionCountGrowthPeriod);
|
||||
}
|
||||
|
||||
// Chaos goes down very slowly
|
||||
for (let cityName of BladeburnerConstants.CityNames) {
|
||||
var city = this.cities[cityName];
|
||||
if (!(city instanceof City)) {throw new Error("Invalid City object when processing passive chaos reduction in Bladeburner.process");}
|
||||
city.chaos -= (0.0001 * seconds);
|
||||
city.chaos = Math.max(0, city.chaos);
|
||||
}
|
||||
|
||||
// Random Events
|
||||
this.randomEventCounter -= seconds;
|
||||
if (this.randomEventCounter <= 0) {
|
||||
randomEvent(this);
|
||||
// Add instead of setting because we might have gone over the required time for the event
|
||||
this.randomEventCounter += getRandomInt(240, 600);
|
||||
}
|
||||
|
||||
processAction(this, Player, seconds);
|
||||
|
||||
// Automation
|
||||
if (this.automateEnabled) {
|
||||
// Note: Do NOT set this.action = this.automateActionHigh/Low since it creates a reference
|
||||
if (this.stamina <= this.automateThreshLow) {
|
||||
if (this.action.name !== this.automateActionLow.name || this.action.type !== this.automateActionLow.type) {
|
||||
this.action = new ActionIdentifier({type: this.automateActionLow.type, name: this.automateActionLow.name});
|
||||
startAction(this, Player, this.action);
|
||||
}
|
||||
} else if (this.stamina >= this.automateThreshHigh) {
|
||||
if (this.action.name !== this.automateActionHigh.name || this.action.type !== this.automateActionHigh.type) {
|
||||
this.action = new ActionIdentifier({type: this.automateActionHigh.type, name: this.automateActionHigh.name});
|
||||
startAction(this, Player, this.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.calculateMaxStamina = function() {
|
||||
const effAgility = Player.agility * this.skillMultipliers.effAgi;
|
||||
let maxStamina = (Math.pow(effAgility, 0.8) + this.staminaBonus) *
|
||||
this.skillMultipliers.stamina *
|
||||
Player.bladeburner_max_stamina_mult;
|
||||
if (this.maxStamina !== maxStamina) {
|
||||
const oldMax = this.maxStamina;
|
||||
this.maxStamina = maxStamina;
|
||||
this.stamina = this.maxStamina * this.stamina / oldMax;
|
||||
}
|
||||
if (isNaN(maxStamina)) {throw new Error("Max Stamina calculated to be NaN in Bladeburner.calculateMaxStamina()");}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.calculateStaminaGainPerSecond = function() {
|
||||
var effAgility = Player.agility * this.skillMultipliers.effAgi;
|
||||
var maxStaminaBonus = this.maxStamina / BladeburnerConstants.MaxStaminaToGainFactor;
|
||||
var gain = (BladeburnerConstants.StaminaGainPerSecond + maxStaminaBonus) * Math.pow(effAgility, 0.17);
|
||||
return gain * (this.skillMultipliers.stamina * Player.bladeburner_stamina_gain_mult);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.calculateStaminaPenalty = function() {
|
||||
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getCurrentCity = function() {
|
||||
var city = this.cities[this.city];
|
||||
if (!(city instanceof City)) {
|
||||
throw new Error("Bladeburner.getCurrentCity() did not properly return a City object");
|
||||
}
|
||||
return city;
|
||||
}
|
||||
|
||||
Bladeburner.prototype.upgradeSkill = function(skill) {
|
||||
// This does NOT handle deduction of skill points
|
||||
var skillName = skill.name;
|
||||
if (this.skills[skillName]) {
|
||||
++this.skills[skillName];
|
||||
} else {
|
||||
this.skills[skillName] = 1;
|
||||
}
|
||||
if (isNaN(this.skills[skillName]) || this.skills[skillName] < 0) {
|
||||
throw new Error("Level of Skill " + skillName + " is invalid: " + this.skills[skillName]);
|
||||
}
|
||||
updateSkillMultipliers(this);
|
||||
}
|
||||
|
||||
// Sets the player to the "IDLE" action
|
||||
Bladeburner.prototype.resetAction = function() {
|
||||
this.action = new ActionIdentifier({type:ActionTypes.Idle});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////// Unconvertable for now /////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Bladeburner.prototype.prestige = function() { prestige(this); }
|
||||
Bladeburner.prototype.storeCycles = function(numCycles=1) { storeCycles(this, numCycles); }
|
||||
Bladeburner.prototype.calculateStaminaPenalty = function() { return calculateStaminaPenalty(this); }
|
||||
Bladeburner.prototype.getCurrentCity = function() { return getCurrentCity(this); }
|
||||
Bladeburner.prototype.upgradeSkill = function(skill) { upgradeSkill(this, skill); }
|
||||
// Bladeburner Console Window
|
||||
Bladeburner.prototype.postToConsole = function(input, saveToLogs=true) {
|
||||
const MaxConsoleEntries = 100;
|
||||
if (saveToLogs) {
|
||||
this.consoleLogs.push(input);
|
||||
if (this.consoleLogs.length > MaxConsoleEntries) {
|
||||
this.consoleLogs.shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.log = function(input) {
|
||||
// Adds a timestamp and then just calls postToConsole
|
||||
this.postToConsole(`[${getTimestamp()}] ${input}`);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.postToConsole = function(input, saveToLogs=true) { postToConsole(this, input, saveToLogs); }
|
||||
Bladeburner.prototype.log = function(input) { log(this, input); }
|
||||
// Handles a potential series of commands (comm1; comm2; comm3;)
|
||||
Bladeburner.prototype.executeConsoleCommands = function(commands) {
|
||||
executeConsoleCommands(this, commands);
|
||||
}
|
||||
Bladeburner.prototype.executeConsoleCommands = function(commands) { executeConsoleCommands(this, Player, commands); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Netscript Fns /////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Bladeburner.prototype.getTypeAndNameFromActionId = function(actionId) {
|
||||
var res = {};
|
||||
let types = Object.keys(ActionTypes);
|
||||
for (let i = 0; i < types.length; ++i) {
|
||||
if (actionId.type === ActionTypes[types[i]]) {
|
||||
res.type = types[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res.type == null) {res.type = "Idle";}
|
||||
|
||||
res.name = actionId.name != null ? actionId.name : "Idle";
|
||||
return res;
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getContractNamesNetscriptFn = function() {
|
||||
return Object.keys(this.contracts);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getOperationNamesNetscriptFn = function() {
|
||||
return Object.keys(this.operations);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getBlackOpNamesNetscriptFn = function() {
|
||||
return Object.keys(BlackOperations);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getGeneralActionNamesNetscriptFn = function() {
|
||||
return Object.keys(GeneralActions);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getSkillNamesNetscriptFn = function() {
|
||||
return Object.keys(Skills);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(this, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.startAction", errorLogText);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special logic for Black Ops
|
||||
if (actionId.type === ActionTypes["BlackOp"]) {
|
||||
// Can't start a BlackOp if you don't have the required rank
|
||||
let action = getActionObject(this, actionId);
|
||||
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
|
||||
var 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
|
||||
});
|
||||
|
||||
let 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;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
startAction(this, Player, actionId);
|
||||
workerScript.log("bladeburner.startAction", `Starting bladeburner action with type '${type}' and name ${name}"`);
|
||||
return true;
|
||||
} catch(e) {
|
||||
resetAction(this);
|
||||
workerScript.log("bladeburner.startAction", errorLogText);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`
|
||||
const actionId = getActionIdFromTypeAndName(this, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(this, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]:
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
return actionObj.getActionTime(this);
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["Field Analysis"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
return 30;
|
||||
case ActionTypes["Recruitment"]:
|
||||
return getRecruitmentTime(this, Player);
|
||||
case ActionTypes["Diplomacy"]:
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
return 60;
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getActionEstimatedSuccessChanceNetscriptFn = function(type, name, workerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`
|
||||
const actionId = getActionIdFromTypeAndName(this, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(this, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]:
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
return actionObj.getSuccessChance(this, {est:true});
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["Field Analysis"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
return 1;
|
||||
case ActionTypes["Recruitment"]:
|
||||
return getRecruitmentSuccessChance(this, Player);
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name, workerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(this, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(this, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]:
|
||||
return Math.floor( actionObj.count );
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
if (this.blackops[name] != null) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["Field Analysis"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
return Infinity;
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getSkillLevelNetscriptFn = function(skillName, workerScript) {
|
||||
if (skillName === "" || !Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log("bladeburner.getSkillLevel", `Invalid skill: '${skillName}'`);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this.skills[skillName] == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return this.skills[skillName];
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getSkillUpgradeCostNetscriptFn = function(skillName, workerScript) {
|
||||
if (skillName === "" || !Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log("bladeburner.getSkillUpgradeCost", `Invalid skill: '${skillName}'`);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const skill = Skills[skillName];
|
||||
if (this.skills[skillName] == null) {
|
||||
return skill.calculateCost(0);
|
||||
} else {
|
||||
return skill.calculateCost(this.skills[skillName]);
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.upgradeSkillNetscriptFn = function(skillName, workerScript) {
|
||||
const errorLogText = `Invalid skill: '${skillName}'`;
|
||||
if (!Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log("bladeburner.upgradeSkill", errorLogText);
|
||||
return false;
|
||||
}
|
||||
|
||||
const skill = Skills[skillName];
|
||||
let currentLevel = 0;
|
||||
if (this.skills[skillName] && !isNaN(this.skills[skillName])) {
|
||||
currentLevel = this.skills[skillName];
|
||||
}
|
||||
const cost = skill.calculateCost(currentLevel);
|
||||
|
||||
if(skill.maxLvl && currentLevel >= skill.maxLvl) {
|
||||
workerScript.log("bladeburner.upgradeSkill", `Skill '${skillName}' is already maxed.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.skillPoints < cost) {
|
||||
workerScript.log("bladeburner.upgradeSkill", `You do not have enough skill points to upgrade ${skillName} (You have ${this.skillPoints}, you need ${cost})`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.skillPoints -= cost;
|
||||
this.upgradeSkill(skill);
|
||||
workerScript.log("bladeburner.upgradeSkill", `'${skillName}' upgraded to level ${this.skills[skillName]}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getTeamSizeNetscriptFn = function(type, name, workerScript) {
|
||||
if (type === "" && name === "") {
|
||||
return this.teamSize;
|
||||
}
|
||||
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(this, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(this, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (actionId.type === ActionTypes["Operation"] ||
|
||||
actionId.type === ActionTypes["BlackOp"] ||
|
||||
actionId.type === ActionTypes["BlackOperation"]) {
|
||||
return actionObj.teamCount;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, workerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(this, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.setTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (actionId.type !== ActionTypes["Operation"] &&
|
||||
actionId.type !== ActionTypes["BlackOp"] &&
|
||||
actionId.type !== ActionTypes["BlackOperation"]) {
|
||||
workerScript.log("bladeburner.setTeamSize", "Only valid for 'Operations' and 'BlackOps'");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(this, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.setTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
let sanitizedSize = Math.round(size);
|
||||
if (isNaN(sanitizedSize) || sanitizedSize < 0) {
|
||||
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`);
|
||||
return -1;
|
||||
}
|
||||
if (this.teamSize < sanitizedSize) {sanitizedSize = this.teamSize;}
|
||||
actionObj.teamCount = sanitizedSize;
|
||||
workerScript.log("bladeburner.setTeamSize", `Team size for '${name}' set to ${sanitizedSize}.`);
|
||||
return sanitizedSize;
|
||||
}
|
||||
|
||||
Bladeburner.prototype.joinBladeburnerFactionNetscriptFn = function(workerScript) {
|
||||
var bladeburnerFac = Factions["Bladeburners"];
|
||||
if (bladeburnerFac.isMember) {
|
||||
return true;
|
||||
} else if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
|
||||
joinFaction(bladeburnerFac);
|
||||
workerScript.log("bladeburner.joinBladeburnerFaction", "Joined Bladeburners faction.");
|
||||
return true;
|
||||
} else {
|
||||
workerScript.log("bladeburner.joinBladeburnerFaction", `You do not have the required rank (${this.rank}/${BladeburnerConstants.RankNeededForFaction}).`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Bladeburner.prototype.getTypeAndNameFromActionId = function(actionId) { getTypeAndNameFromActionId(this, actionId); }
|
||||
Bladeburner.prototype.getContractNamesNetscriptFn = function() { getContractNamesNetscriptFn(this); }
|
||||
Bladeburner.prototype.getOperationNamesNetscriptFn = function() { getOperationNamesNetscriptFn(this); }
|
||||
Bladeburner.prototype.getBlackOpNamesNetscriptFn = function() { getBlackOpNamesNetscriptFn(this); }
|
||||
Bladeburner.prototype.getGeneralActionNamesNetscriptFn = function() { getGeneralActionNamesNetscriptFn(this); }
|
||||
Bladeburner.prototype.getSkillNamesNetscriptFn = function() { getSkillNamesNetscriptFn(this); }
|
||||
Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript) { startActionNetscriptFn(this, Player, type, name, workerScript); }
|
||||
Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScript) { getActionTimeNetscriptFn(this, Player, type, name, workerScript); }
|
||||
Bladeburner.prototype.getActionEstimatedSuccessChanceNetscriptFn = function(type, name, workerScript) { getActionEstimatedSuccessChanceNetscriptFn(this, Player, type, name, workerScript); }
|
||||
Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name, workerScript) { getActionCountRemainingNetscriptFn(this, Player, type, name, workerScript); }
|
||||
Bladeburner.prototype.getSkillLevelNetscriptFn = function(skillName, workerScript) { getSkillLevelNetscriptFn(this, skillName, workerScript); }
|
||||
Bladeburner.prototype.getSkillUpgradeCostNetscriptFn = function(skillName, workerScript) { getSkillUpgradeCostNetscriptFn(this, skillName, workerScript); }
|
||||
Bladeburner.prototype.upgradeSkillNetscriptFn = function(skillName, workerScript) { upgradeSkillNetscriptFn(this, skillName, workerScript); }
|
||||
Bladeburner.prototype.getTeamSizeNetscriptFn = function(type, name, workerScript) { getTeamSizeNetscriptFn(this, type, name, workerScript); }
|
||||
Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, workerScript) { setTeamSizeNetscriptFn(this, type, name, size, workerScript); }
|
||||
Bladeburner.prototype.joinBladeburnerFactionNetscriptFn = function(workerScript) { joinBladeburnerFactionNetscriptFn(this, workerScript); }
|
||||
|
||||
Bladeburner.prototype.toJSON = function() {
|
||||
return Generic_toJSON("Bladeburner", this);
|
||||
|
@ -8,6 +8,8 @@ import { ActionIdentifier } from "./ActionIdentifier";
|
||||
import { ActionTypes } from "./data/ActionTypes";
|
||||
import { BlackOperations } from "./BlackOperations";
|
||||
import { BlackOperation } from "./BlackOperation";
|
||||
import { Operation } from "./Operation";
|
||||
import { Contract } from "./Contract";
|
||||
import { GeneralActions } from "./GeneralActions";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import { Skills } from "./Skills";
|
||||
@ -25,7 +27,14 @@ import { addOffset } from "../../utils/helpers/addOffset";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { calculateHospitalizationCost } from "../Hospital/Hospital";
|
||||
import { hackWorldDaemon } from "../RedPill";
|
||||
import { hackWorldDaemon, redPillFlag } from "../RedPill";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { getTimestamp } from "../../utils/helpers/getTimestamp";
|
||||
import { joinFaction } from "../Faction/FactionHelpers";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
|
||||
export function getActionIdFromTypeAndName(bladeburner: IBladeburner, type: string = "", name: string = ""): IActionIdentifier | null {
|
||||
if (type === "" || name === "") {return null;}
|
||||
@ -548,7 +557,7 @@ export function executeConsoleCommand(bladeburner: IBladeburner, player: IPlayer
|
||||
executeStartConsoleCommand(bladeburner, player, args);
|
||||
break;
|
||||
case "stop":
|
||||
bladeburner.resetAction();
|
||||
resetAction(bladeburner);
|
||||
break;
|
||||
default:
|
||||
bladeburner.postToConsole("Invalid console command");
|
||||
@ -1310,4 +1319,597 @@ export function startAction(bladeburner: IBladeburner, player: IPlayer, actionId
|
||||
throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateStaminaPenalty(bladeburner: IBladeburner): number {
|
||||
return Math.min(1, bladeburner.stamina / (0.5 * bladeburner.maxStamina));
|
||||
}
|
||||
|
||||
export function calculateStaminaGainPerSecond(bladeburner: IBladeburner, player: IPlayer): number {
|
||||
const effAgility = player.agility * bladeburner.skillMultipliers.effAgi;
|
||||
const maxStaminaBonus = bladeburner.maxStamina / BladeburnerConstants.MaxStaminaToGainFactor;
|
||||
const gain = (BladeburnerConstants.StaminaGainPerSecond + maxStaminaBonus) * Math.pow(effAgility, 0.17);
|
||||
return gain * (bladeburner.skillMultipliers.stamina * player.bladeburner_stamina_gain_mult);
|
||||
}
|
||||
|
||||
export function calculateMaxStamina(bladeburner: IBladeburner, player: IPlayer) {
|
||||
const effAgility = player.agility * bladeburner.skillMultipliers.effAgi;
|
||||
let maxStamina = (Math.pow(effAgility, 0.8) + bladeburner.staminaBonus) *
|
||||
bladeburner.skillMultipliers.stamina *
|
||||
player.bladeburner_max_stamina_mult;
|
||||
if (bladeburner.maxStamina !== maxStamina) {
|
||||
const oldMax = bladeburner.maxStamina;
|
||||
bladeburner.maxStamina = maxStamina;
|
||||
bladeburner.stamina = bladeburner.maxStamina * bladeburner.stamina / oldMax;
|
||||
}
|
||||
if (isNaN(maxStamina)) {throw new Error("Max Stamina calculated to be NaN in Bladeburner.calculateMaxStamina()");}
|
||||
}
|
||||
|
||||
export function create(bladeburner: IBladeburner): void {
|
||||
bladeburner.contracts["Tracking"] = new Contract({
|
||||
name:"Tracking",
|
||||
desc:"Identify and locate Synthoids. This contract involves reconnaissance " +
|
||||
"and information-gathering ONLY. Do NOT engage. Stealth is of the utmost importance.<br><br>" +
|
||||
"Successfully completing Tracking contracts will slightly improve your Synthoid population estimate for " +
|
||||
"whatever city you are currently in.",
|
||||
baseDifficulty:125,difficultyFac:1.02,rewardFac:1.041,
|
||||
rankGain:0.3, hpLoss:0.5,
|
||||
count:getRandomInt(25, 150), countGrowth:getRandomInt(5, 75)/10,
|
||||
weights:{hack:0,str:0.05,def:0.05,dex:0.35,agi:0.35,cha:0.1, int:0.05},
|
||||
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.9, int:1},
|
||||
isStealth:true,
|
||||
});
|
||||
bladeburner.contracts["Bounty Hunter"] = new Contract({
|
||||
name:"Bounty Hunter",
|
||||
desc:"Hunt down and capture fugitive Synthoids. These Synthoids are wanted alive.<br><br>" +
|
||||
"Successfully completing a Bounty Hunter contract will lower the population in your " +
|
||||
"current city, and will also increase its chaos level.",
|
||||
baseDifficulty:250, difficultyFac:1.04,rewardFac:1.085,
|
||||
rankGain:0.9, hpLoss:1,
|
||||
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10,
|
||||
weights:{hack:0,str:0.15,def:0.15,dex:0.25,agi:0.25,cha:0.1, int:0.1},
|
||||
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
|
||||
isKill:true,
|
||||
});
|
||||
bladeburner.contracts["Retirement"] = new Contract({
|
||||
name:"Retirement",
|
||||
desc:"Hunt down and retire (kill) rogue Synthoids.<br><br>" +
|
||||
"Successfully completing a Retirement contract will lower the population in your current " +
|
||||
"city, and will also increase its chaos level.",
|
||||
baseDifficulty:200, difficultyFac:1.03, rewardFac:1.065,
|
||||
rankGain:0.6, hpLoss:1,
|
||||
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10,
|
||||
weights:{hack:0,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0.1, int:0.1},
|
||||
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
|
||||
isKill:true,
|
||||
});
|
||||
|
||||
bladeburner.operations["Investigation"] = new Operation({
|
||||
name:"Investigation",
|
||||
desc:"As a field agent, investigate and identify Synthoid " +
|
||||
"populations, movements, and operations.<br><br>Successful " +
|
||||
"Investigation ops will increase the accuracy of your " +
|
||||
"synthoid data.<br><br>" +
|
||||
"You will NOT lose HP from failed Investigation ops.",
|
||||
baseDifficulty:400, difficultyFac:1.03,rewardFac:1.07,reqdRank:25,
|
||||
rankGain:2.2, rankLoss:0.2,
|
||||
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10,
|
||||
weights:{hack:0.25,str:0.05,def:0.05,dex:0.2,agi:0.1,cha:0.25, int:0.1},
|
||||
decays:{hack:0.85,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
|
||||
isStealth:true,
|
||||
});
|
||||
bladeburner.operations["Undercover Operation"] = new Operation({
|
||||
name:"Undercover Operation",
|
||||
desc:"Conduct undercover operations to identify hidden " +
|
||||
"and underground Synthoid communities and organizations.<br><br>" +
|
||||
"Successful Undercover ops will increase the accuracy of your synthoid " +
|
||||
"data.",
|
||||
baseDifficulty:500, difficultyFac:1.04, rewardFac:1.09, reqdRank:100,
|
||||
rankGain:4.4, rankLoss:0.4, hpLoss:2,
|
||||
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10,
|
||||
weights:{hack:0.2,str:0.05,def:0.05,dex:0.2,agi:0.2,cha:0.2, int:0.1},
|
||||
decays:{hack:0.8,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
|
||||
isStealth:true,
|
||||
});
|
||||
bladeburner.operations["Sting Operation"] = new Operation({
|
||||
name:"Sting Operation",
|
||||
desc:"Conduct a sting operation to bait and capture particularly " +
|
||||
"notorious Synthoid criminals.",
|
||||
baseDifficulty:650, difficultyFac:1.04, rewardFac:1.095, reqdRank:500,
|
||||
rankGain:5.5, rankLoss:0.5, hpLoss:2.5,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(3, 40)/10,
|
||||
weights:{hack:0.25,str:0.05,def:0.05,dex:0.25,agi:0.1,cha:0.2, int:0.1},
|
||||
decays:{hack:0.8,str:0.85,def:0.85,dex:0.85,agi:0.85,cha:0.7, int:0.9},
|
||||
isStealth:true,
|
||||
});
|
||||
bladeburner.operations["Raid"] = new Operation({
|
||||
name:"Raid",
|
||||
desc:"Lead an assault on a known Synthoid community. Note that " +
|
||||
"there must be an existing Synthoid community in your current city " +
|
||||
"in order for this Operation to be successful.",
|
||||
baseDifficulty:800, difficultyFac:1.045, rewardFac:1.1, reqdRank:3000,
|
||||
rankGain:55,rankLoss:2.5,hpLoss:50,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(2, 40)/10,
|
||||
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
|
||||
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
|
||||
isKill:true,
|
||||
});
|
||||
bladeburner.operations["Stealth Retirement Operation"] = new Operation({
|
||||
name:"Stealth Retirement Operation",
|
||||
desc:"Lead a covert operation to retire Synthoids. The " +
|
||||
"objective is to complete the task without " +
|
||||
"drawing any attention. Stealth and discretion are key.",
|
||||
baseDifficulty:1000, difficultyFac:1.05, rewardFac:1.11, reqdRank:20e3,
|
||||
rankGain:22, rankLoss:2, hpLoss:10,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10,
|
||||
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
|
||||
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
|
||||
isStealth:true, isKill:true,
|
||||
});
|
||||
bladeburner.operations["Assassination"] = new Operation({
|
||||
name:"Assassination",
|
||||
desc:"Assassinate Synthoids that have been identified as " +
|
||||
"important, high-profile social and political leaders " +
|
||||
"in the Synthoid communities.",
|
||||
baseDifficulty:1500, difficultyFac:1.06, rewardFac:1.14, reqdRank:50e3,
|
||||
rankGain:44, rankLoss:4, hpLoss:5,
|
||||
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10,
|
||||
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
|
||||
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.8},
|
||||
isStealth:true, isKill:true,
|
||||
});
|
||||
}
|
||||
|
||||
export function process(bladeburner: IBladeburner, player: IPlayer): void {
|
||||
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
|
||||
if (redPillFlag === false && bladeburner.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
return hackWorldDaemon(player.bitNodeN);
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
if (Augmentations[AugmentationNames.BladesSimulacrum].owned === false && player.isWorking) {
|
||||
if (bladeburner.action.type !== ActionTypes["Idle"]) {
|
||||
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
|
||||
if (bladeburner.automateEnabled) {
|
||||
msg += `<br><br>Your automation was disabled as well. You will have to re-enable it through the Bladeburner console`
|
||||
bladeburner.automateEnabled = false;
|
||||
}
|
||||
if (!Settings.SuppressBladeburnerPopup) {
|
||||
dialogBoxCreate(msg);
|
||||
}
|
||||
}
|
||||
resetAction(bladeburner);
|
||||
}
|
||||
|
||||
// If the Player has no Stamina, set action to idle
|
||||
if (bladeburner.stamina <= 0) {
|
||||
bladeburner.log("Your Bladeburner action was cancelled because your stamina hit 0");
|
||||
resetAction(bladeburner);
|
||||
}
|
||||
|
||||
// A 'tick' for this mechanic is one second (= 5 game cycles)
|
||||
if (bladeburner.storedCycles >= BladeburnerConstants.CyclesPerSecond) {
|
||||
let seconds = Math.floor(bladeburner.storedCycles / BladeburnerConstants.CyclesPerSecond);
|
||||
seconds = Math.min(seconds, 5); // Max of 5 'ticks'
|
||||
bladeburner.storedCycles -= seconds * BladeburnerConstants.CyclesPerSecond;
|
||||
|
||||
// Stamina
|
||||
calculateMaxStamina(bladeburner, player);
|
||||
bladeburner.stamina += (calculateStaminaGainPerSecond(bladeburner, player) * seconds);
|
||||
bladeburner.stamina = Math.min(bladeburner.maxStamina, bladeburner.stamina);
|
||||
|
||||
// Count increase for contracts/operations
|
||||
for (const contract of (Object.values(bladeburner.contracts) as Contract[])) {
|
||||
contract.count += (seconds * contract.countGrowth/BladeburnerConstants.ActionCountGrowthPeriod);
|
||||
}
|
||||
for (const op of (Object.values(bladeburner.operations) as Operation[])) {
|
||||
op.count += (seconds * op.countGrowth/BladeburnerConstants.ActionCountGrowthPeriod);
|
||||
}
|
||||
|
||||
// Chaos goes down very slowly
|
||||
for (const cityName of BladeburnerConstants.CityNames) {
|
||||
const city = bladeburner.cities[cityName];
|
||||
if (!(city instanceof City)) {throw new Error("Invalid City object when processing passive chaos reduction in Bladeburner.process");}
|
||||
city.chaos -= (0.0001 * seconds);
|
||||
city.chaos = Math.max(0, city.chaos);
|
||||
}
|
||||
|
||||
// Random Events
|
||||
bladeburner.randomEventCounter -= seconds;
|
||||
if (bladeburner.randomEventCounter <= 0) {
|
||||
randomEvent(bladeburner);
|
||||
// Add instead of setting because we might have gone over the required time for the event
|
||||
bladeburner.randomEventCounter += getRandomInt(240, 600);
|
||||
}
|
||||
|
||||
processAction(bladeburner, player, seconds);
|
||||
|
||||
// Automation
|
||||
if (bladeburner.automateEnabled) {
|
||||
// Note: Do NOT set bladeburner.action = bladeburner.automateActionHigh/Low since it creates a reference
|
||||
if (bladeburner.stamina <= bladeburner.automateThreshLow) {
|
||||
if (bladeburner.action.name !== bladeburner.automateActionLow.name || bladeburner.action.type !== bladeburner.automateActionLow.type) {
|
||||
bladeburner.action = new ActionIdentifier({type: bladeburner.automateActionLow.type, name: bladeburner.automateActionLow.name});
|
||||
startAction(bladeburner, player, bladeburner.action);
|
||||
}
|
||||
} else if (bladeburner.stamina >= bladeburner.automateThreshHigh) {
|
||||
if (bladeburner.action.name !== bladeburner.automateActionHigh.name || bladeburner.action.type !== bladeburner.automateActionHigh.type) {
|
||||
bladeburner.action = new ActionIdentifier({type: bladeburner.automateActionHigh.type, name: bladeburner.automateActionHigh.name});
|
||||
startAction(bladeburner, player, bladeburner.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export function prestige(bladeburner: IBladeburner): void {
|
||||
resetAction(bladeburner);
|
||||
const bladeburnerFac = Factions["Bladeburners"];
|
||||
if (bladeburner.rank >= BladeburnerConstants.RankNeededForFaction) {
|
||||
joinFaction(bladeburnerFac);
|
||||
}
|
||||
}
|
||||
|
||||
export function storeCycles(bladeburner: IBladeburner, numCycles: number = 1): void {
|
||||
bladeburner.storedCycles += numCycles;
|
||||
}
|
||||
|
||||
export function getCurrentCity(bladeburner: IBladeburner): City {
|
||||
const city = bladeburner.cities[bladeburner.city];
|
||||
if (!(city instanceof City)) {
|
||||
throw new Error("Bladeburner.getCurrentCity() did not properly return a City object");
|
||||
}
|
||||
return city;
|
||||
}
|
||||
|
||||
export function upgradeSkill(bladeburner: IBladeburner, skill: Skill) {
|
||||
// This does NOT handle deduction of skill points
|
||||
const skillName = skill.name;
|
||||
if (bladeburner.skills[skillName]) {
|
||||
++bladeburner.skills[skillName];
|
||||
} else {
|
||||
bladeburner.skills[skillName] = 1;
|
||||
}
|
||||
if (isNaN(bladeburner.skills[skillName]) || bladeburner.skills[skillName] < 0) {
|
||||
throw new Error("Level of Skill " + skillName + " is invalid: " + bladeburner.skills[skillName]);
|
||||
}
|
||||
updateSkillMultipliers(bladeburner);
|
||||
}
|
||||
|
||||
// Bladeburner Console Window
|
||||
export function postToConsole(bladeburner: IBladeburner, input: string, saveToLogs: boolean = true) {
|
||||
const MaxConsoleEntries = 100;
|
||||
if (saveToLogs) {
|
||||
bladeburner.consoleLogs.push(input);
|
||||
if (bladeburner.consoleLogs.length > MaxConsoleEntries) {
|
||||
bladeburner.consoleLogs.shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function log(bladeburner: IBladeburner, input: string) {
|
||||
// Adds a timestamp and then just calls postToConsole
|
||||
bladeburner.postToConsole(`[${getTimestamp()}] ${input}`);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Netscript Fns /////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
export function getTypeAndNameFromActionId(bladeburner: IBladeburner, actionId: IActionIdentifier) {
|
||||
const res = {type: '', name: ''};
|
||||
const types = Object.keys(ActionTypes);
|
||||
for (let i = 0; i < types.length; ++i) {
|
||||
if (actionId.type === ActionTypes[types[i]]) {
|
||||
res.type = types[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res.type == null) {res.type = "Idle";}
|
||||
|
||||
res.name = actionId.name != null ? actionId.name : "Idle";
|
||||
return res;
|
||||
}
|
||||
export function getContractNamesNetscriptFn(bladeburner: IBladeburner) {
|
||||
return Object.keys(bladeburner.contracts);
|
||||
}
|
||||
export function getOperationNamesNetscriptFn(bladeburner: IBladeburner) {
|
||||
return Object.keys(bladeburner.operations);
|
||||
}
|
||||
export function getBlackOpNamesNetscriptFn(bladeburner: IBladeburner) {
|
||||
return Object.keys(BlackOperations);
|
||||
}
|
||||
export function getGeneralActionNamesNetscriptFn(bladeburner: IBladeburner) {
|
||||
return Object.keys(GeneralActions);
|
||||
}
|
||||
export function getSkillNamesNetscriptFn(bladeburner: IBladeburner) {
|
||||
return Object.keys(Skills);
|
||||
}
|
||||
export function startActionNetscriptFn(bladeburner: IBladeburner, player: IPlayer, type: string, name: string, workerScript: WorkerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(bladeburner, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.startAction", errorLogText);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special logic for Black Ops
|
||||
if (actionId.type === ActionTypes["BlackOp"]) {
|
||||
// Can't start a BlackOp if you don't have the required rank
|
||||
const action = getActionObject(bladeburner, actionId);
|
||||
if(action == null) throw new Error('Action not found ${actionId.type}, ${actionId.name}');
|
||||
if(!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
|
||||
const blackOp = (action as BlackOperation);
|
||||
if (action.reqdRank > bladeburner.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 (bladeburner.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
|
||||
var 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
|
||||
});
|
||||
|
||||
let i = blackops.indexOf(actionId.name);
|
||||
if (i === -1) {
|
||||
workerScript.log("bladeburner.startAction", `Invalid Black Op: '${name}'`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i > 0 && bladeburner.blackops[blackops[i-1]] == null) {
|
||||
workerScript.log("bladeburner.startAction", `Preceding Black Op must be completed before starting '${actionId.name}'.`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
startAction(bladeburner, player, actionId);
|
||||
workerScript.log("bladeburner.startAction", `Starting bladeburner action with type '${type}' and name ${name}"`);
|
||||
return true;
|
||||
} catch(e) {
|
||||
resetAction(bladeburner);
|
||||
workerScript.log("bladeburner.startAction", errorLogText);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function getActionTimeNetscriptFn(bladeburner: IBladeburner, player: IPlayer, type: string, name: string, workerScript: WorkerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`
|
||||
const actionId = getActionIdFromTypeAndName(bladeburner, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(bladeburner, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]:
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
return actionObj.getActionTime(bladeburner);
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["Field Analysis"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
return 30;
|
||||
case ActionTypes["Recruitment"]:
|
||||
return getRecruitmentTime(bladeburner, player);
|
||||
case ActionTypes["Diplomacy"]:
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
return 60;
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
export function getActionEstimatedSuccessChanceNetscriptFn(bladeburner: IBladeburner, player: IPlayer, type: string, name: string, workerScript: WorkerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`
|
||||
const actionId = getActionIdFromTypeAndName(bladeburner, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(bladeburner, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]:
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
return actionObj.getSuccessChance(bladeburner, {est:true});
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["Field Analysis"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
return 1;
|
||||
case ActionTypes["Recruitment"]:
|
||||
return getRecruitmentSuccessChance(bladeburner, player);
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
export function getActionCountRemainingNetscriptFn(bladeburner: IBladeburner, type: string, name: string, workerScript: WorkerScript) {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(bladeburner, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(bladeburner, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]:
|
||||
return Math.floor( actionObj.count );
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
if (bladeburner.blackops[name] != null) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
case ActionTypes["Training"]:
|
||||
case ActionTypes["Field Analysis"]:
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
return Infinity;
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
export function getSkillLevelNetscriptFn(bladeburner: IBladeburner, skillName: string, workerScript: WorkerScript) {
|
||||
if (skillName === "" || !Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log("bladeburner.getSkillLevel", `Invalid skill: '${skillName}'`);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bladeburner.skills[skillName] == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return bladeburner.skills[skillName];
|
||||
}
|
||||
}
|
||||
export function getSkillUpgradeCostNetscriptFn(bladeburner: IBladeburner, skillName: string, workerScript: WorkerScript) {
|
||||
if (skillName === "" || !Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log("bladeburner.getSkillUpgradeCost", `Invalid skill: '${skillName}'`);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const skill = Skills[skillName];
|
||||
if (bladeburner.skills[skillName] == null) {
|
||||
return skill.calculateCost(0);
|
||||
} else {
|
||||
return skill.calculateCost(bladeburner.skills[skillName]);
|
||||
}
|
||||
}
|
||||
export function upgradeSkillNetscriptFn(bladeburner: IBladeburner, skillName: string, workerScript: WorkerScript) {
|
||||
const errorLogText = `Invalid skill: '${skillName}'`;
|
||||
if (!Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log("bladeburner.upgradeSkill", errorLogText);
|
||||
return false;
|
||||
}
|
||||
|
||||
const skill = Skills[skillName];
|
||||
let currentLevel = 0;
|
||||
if (bladeburner.skills[skillName] && !isNaN(bladeburner.skills[skillName])) {
|
||||
currentLevel = bladeburner.skills[skillName];
|
||||
}
|
||||
const cost = skill.calculateCost(currentLevel);
|
||||
|
||||
if(skill.maxLvl && currentLevel >= skill.maxLvl) {
|
||||
workerScript.log("bladeburner.upgradeSkill", `Skill '${skillName}' is already maxed.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bladeburner.skillPoints < cost) {
|
||||
workerScript.log("bladeburner.upgradeSkill", `You do not have enough skill points to upgrade ${skillName} (You have ${bladeburner.skillPoints}, you need ${cost})`);
|
||||
return false;
|
||||
}
|
||||
|
||||
bladeburner.skillPoints -= cost;
|
||||
bladeburner.upgradeSkill(skill);
|
||||
workerScript.log("bladeburner.upgradeSkill", `'${skillName}' upgraded to level ${bladeburner.skills[skillName]}`);
|
||||
return true;
|
||||
}
|
||||
export function getTeamSizeNetscriptFn(bladeburner: IBladeburner, type: string, name: string, workerScript: WorkerScript): number {
|
||||
if (type === "" && name === "") {
|
||||
return bladeburner.teamSize;
|
||||
}
|
||||
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(bladeburner, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.getTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(bladeburner, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.getTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (actionId.type === ActionTypes["Operation"] ||
|
||||
actionId.type === ActionTypes["BlackOp"] ||
|
||||
actionId.type === ActionTypes["BlackOperation"]) {
|
||||
return actionObj.teamCount;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
export function setTeamSizeNetscriptFn(bladeburner: IBladeburner, type: string, name: string, size: number, workerScript: WorkerScript): number {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
const actionId = getActionIdFromTypeAndName(bladeburner, type, name);
|
||||
if (actionId == null) {
|
||||
workerScript.log("bladeburner.setTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (actionId.type !== ActionTypes["Operation"] &&
|
||||
actionId.type !== ActionTypes["BlackOp"] &&
|
||||
actionId.type !== ActionTypes["BlackOperation"]) {
|
||||
workerScript.log("bladeburner.setTeamSize", "Only valid for 'Operations' and 'BlackOps'");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const actionObj = getActionObject(bladeburner, actionId);
|
||||
if (actionObj == null) {
|
||||
workerScript.log("bladeburner.setTeamSize", errorLogText);
|
||||
return -1;
|
||||
}
|
||||
|
||||
let sanitizedSize = Math.round(size);
|
||||
if (isNaN(sanitizedSize) || sanitizedSize < 0) {
|
||||
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`);
|
||||
return -1;
|
||||
}
|
||||
if (bladeburner.teamSize < sanitizedSize) {sanitizedSize = bladeburner.teamSize;}
|
||||
actionObj.teamCount = sanitizedSize;
|
||||
workerScript.log("bladeburner.setTeamSize", `Team size for '${name}' set to ${sanitizedSize}.`);
|
||||
return sanitizedSize;
|
||||
}
|
||||
export function joinBladeburnerFactionNetscriptFn(bladeburner: IBladeburner, workerScript: WorkerScript): boolean {
|
||||
var bladeburnerFac = Factions["Bladeburners"];
|
||||
if (bladeburnerFac.isMember) {
|
||||
return true;
|
||||
} else if (bladeburner.rank >= BladeburnerConstants.RankNeededForFaction) {
|
||||
joinFaction(bladeburnerFac);
|
||||
workerScript.log("bladeburner.joinBladeburnerFaction", "Joined Bladeburners faction.");
|
||||
return true;
|
||||
} else {
|
||||
workerScript.log("bladeburner.joinBladeburnerFaction", `You do not have the required rank (${bladeburner.rank}/${BladeburnerConstants.RankNeededForFaction}).`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ export interface IPlayer {
|
||||
homeComputer: string;
|
||||
hp: number;
|
||||
jobs: IMap<string>;
|
||||
isWorking: boolean;
|
||||
karma: number;
|
||||
location: LocationName;
|
||||
max_hp: number;
|
||||
|
1
src/RedPill.d.ts
vendored
1
src/RedPill.d.ts
vendored
@ -1 +1,2 @@
|
||||
export declare let redPillFlag: boolean;
|
||||
export declare function hackWorldDaemon(currentNodeNumber: number, flume: boolean = false, quick: boolean = false): void;
|
@ -18,6 +18,7 @@ import {
|
||||
initBitNodeMultipliers,
|
||||
} from "./BitNode/BitNode";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { process as ProcessBladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { CharacterOverviewComponent } from "./ui/React/CharacterOverview";
|
||||
import { cinematicTextFlag } from "./CinematicText";
|
||||
import { generateRandomContract } from "./CodingContractGenerator";
|
||||
@ -883,7 +884,7 @@ const Engine = {
|
||||
}
|
||||
if (Player.bladeburner instanceof Bladeburner) {
|
||||
try {
|
||||
Player.bladeburner.process();
|
||||
ProcessBladeburner(Player.bladeburner, Player);
|
||||
} catch(e) {
|
||||
exceptionAlert("Exception caught in Bladeburner.process(): " + e);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user