From cc8de58cff0947edb5832017627af23e50214612 Mon Sep 17 00:00:00 2001
From: Olivier Gagnon
Date: Mon, 16 Aug 2021 01:35:05 -0400
Subject: [PATCH] More converting blade to react.
---
src/Bladeburner.jsx | 591 ++---------------------
src/Bladeburner/Bladeburner.ts | 587 +++++++++++++++++++++-
src/Bladeburner/City.ts | 16 +-
src/Bladeburner/IBladeburner.ts | 1 +
src/Bladeburner/Skill.ts | 23 +
src/Bladeburner/ui/AllPages.tsx | 10 +-
src/Bladeburner/ui/BlackOpElem.tsx | 5 +-
src/Bladeburner/ui/BlackOpList.tsx | 4 +-
src/Bladeburner/ui/BlackOpPage.tsx | 4 +-
src/Bladeburner/ui/Console.tsx | 3 +
src/Bladeburner/ui/ContractElem.tsx | 9 +-
src/Bladeburner/ui/ContractList.tsx | 4 +-
src/Bladeburner/ui/ContractPage.tsx | 4 +-
src/Bladeburner/ui/GeneralActionElem.tsx | 6 +-
src/Bladeburner/ui/GeneralActionList.tsx | 4 +-
src/Bladeburner/ui/GeneralActionPage.tsx | 4 +-
src/Bladeburner/ui/OperationElem.tsx | 9 +-
src/Bladeburner/ui/OperationList.tsx | 4 +-
src/Bladeburner/ui/OperationPage.tsx | 4 +-
src/Bladeburner/ui/Root.tsx | 4 +-
src/RedPill.d.ts | 1 +
21 files changed, 694 insertions(+), 603 deletions(-)
create mode 100644 src/RedPill.d.ts
diff --git a/src/Bladeburner.jsx b/src/Bladeburner.jsx
index 6b21e5f7f..850715e1c 100644
--- a/src/Bladeburner.jsx
+++ b/src/Bladeburner.jsx
@@ -80,6 +80,15 @@ import {
getDiplomacyEffectiveness,
getRecruitmentSuccessChance,
getRecruitmentTime,
+ resetSkillMultipliers,
+ updateSkillMultipliers,
+ resetAction,
+ getActionObject,
+ completeOperation,
+ completeContract,
+ completeAction,
+ processAction,
+ startAction,
} from "./Bladeburner/Bladeburner";
function Bladeburner(params={}) {
@@ -116,7 +125,7 @@ function Bladeburner(params={}) {
// Map of SkillNames -> level
this.skills = {};
this.skillMultipliers = {};
- this.updateSkillMultipliers(); // Calls resetSkillMultipliers()
+ updateSkillMultipliers(this); // Calls resetSkillMultipliers()
// Max Stamina is based on stats and Bladeburner-specific bonuses
this.staminaBonus = 0; // Gained from training
@@ -163,7 +172,7 @@ function Bladeburner(params={}) {
}
Bladeburner.prototype.prestige = function() {
- this.resetAction();
+ resetAction(this);
var bladeburnerFac = Factions["Bladeburners"];
if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(bladeburnerFac);
@@ -289,7 +298,6 @@ 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")) {
@@ -308,13 +316,13 @@ Bladeburner.prototype.process = function() {
dialogBoxCreate(msg);
}
}
- this.resetAction();
+ 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");
- this.resetAction();
+ resetAction(this);
}
// A 'tick' for this mechanic is one second (= 5 game cycles)
@@ -352,7 +360,7 @@ Bladeburner.prototype.process = function() {
this.randomEventCounter += getRandomInt(240, 600);
}
- this.processAction(seconds);
+ processAction(this, Player, seconds);
// Automation
if (this.automateEnabled) {
@@ -360,12 +368,12 @@ Bladeburner.prototype.process = function() {
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});
- this.startAction(this.action);
+ 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});
- this.startAction(this.action);
+ startAction(this, Player, this.action);
}
}
}
@@ -397,34 +405,6 @@ Bladeburner.prototype.calculateStaminaPenalty = function() {
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
}
-Bladeburner.prototype.changeRank = function(change) {
- if (isNaN(change)) {throw new Error("NaN passed into Bladeburner.changeRank()");}
- this.rank += change;
- if (this.rank < 0) {this.rank = 0;}
- this.maxRank = Math.max(this.rank, this.maxRank);
-
- var bladeburnersFactionName = "Bladeburners";
- if (factionExists(bladeburnersFactionName)) {
- var bladeburnerFac = Factions[bladeburnersFactionName];
- if (!(bladeburnerFac instanceof Faction)) {
- throw new Error("Could not properly get Bladeburner Faction object in Bladeburner UI Overview Faction button");
- }
- if (bladeburnerFac.isMember) {
- var favorBonus = 1 + (bladeburnerFac.favor / 100);
- bladeburnerFac.playerReputation += (BladeburnerConstants.RankToFactionRepFactor * change * Player.faction_rep_mult * favorBonus);
- }
- }
-
- // Gain skill points
- var rankNeededForSp = (this.totalSkillPoints+1) * BladeburnerConstants.RanksPerSkillPoint;
- if (this.maxRank >= rankNeededForSp) {
- // Calculate how many skill points to gain
- var gainedSkillPoints = Math.floor((this.maxRank - rankNeededForSp) / BladeburnerConstants.RanksPerSkillPoint + 1);
- this.skillPoints += gainedSkillPoints;
- this.totalSkillPoints += gainedSkillPoints;
- }
-}
-
Bladeburner.prototype.getCurrentCity = function() {
var city = this.cities[this.city];
if (!(city instanceof City)) {
@@ -433,55 +413,6 @@ Bladeburner.prototype.getCurrentCity = function() {
return city;
}
-Bladeburner.prototype.resetSkillMultipliers = function() {
- this.skillMultipliers = {
- successChanceAll: 1,
- successChanceStealth: 1,
- successChanceKill: 1,
- successChanceContract: 1,
- successChanceOperation: 1,
- successChanceEstimate: 1,
- actionTime: 1,
- effHack: 1,
- effStr: 1,
- effDef: 1,
- effDex: 1,
- effAgi: 1,
- effCha: 1,
- effInt: 1,
- stamina: 1,
- money: 1,
- expGain: 1,
- };
-}
-
-Bladeburner.prototype.updateSkillMultipliers = function() {
- this.resetSkillMultipliers();
- for (var skillName in this.skills) {
- if (this.skills.hasOwnProperty(skillName)) {
- var skill = Skills[skillName];
- if (skill == null) {
- throw new Error("Could not find Skill Object for: " + skillName);
- }
- var level = this.skills[skillName];
- if (level == null || level <= 0) {continue;} //Not upgraded
-
- var multiplierNames = Object.keys(this.skillMultipliers);
- for (var i = 0; i < multiplierNames.length; ++i) {
- var multiplierName = multiplierNames[i];
- if (skill[multiplierName] != null && !isNaN(skill[multiplierName])) {
- var value = skill[multiplierName] * level;
- var multiplierValue = 1 + (value / 100);
- if (multiplierName === "actionTime") {
- multiplierValue = 1 - (value / 100);
- }
- this.skillMultipliers[multiplierName] *= multiplierValue;
- }
- }
- }
- }
-}
-
Bladeburner.prototype.upgradeSkill = function(skill) {
// This does NOT handle deduction of skill points
var skillName = skill.name;
@@ -493,35 +424,7 @@ Bladeburner.prototype.upgradeSkill = function(skill) {
if (isNaN(this.skills[skillName]) || this.skills[skillName] < 0) {
throw new Error("Level of Skill " + skillName + " is invalid: " + this.skills[skillName]);
}
- this.updateSkillMultipliers();
-}
-
-Bladeburner.prototype.getActionObject = function(actionId) {
- /**
- * Given an ActionIdentifier object, returns the corresponding
- * GeneralAction, Contract, Operation, or BlackOperation object
- */
- switch (actionId.type) {
- case ActionTypes["Contract"]:
- return this.contracts[actionId.name];
- case ActionTypes["Operation"]:
- return this.operations[actionId.name];
- case ActionTypes["BlackOp"]:
- case ActionTypes["BlackOperation"]:
- return BlackOperations[actionId.name];
- case ActionTypes["Training"]:
- return GeneralActions["Training"];
- case ActionTypes["Field Analysis"]:
- return GeneralActions["Field Analysis"];
- case ActionTypes["Recruitment"]:
- return GeneralActions["Recruitment"];
- case ActionTypes["Diplomacy"]:
- return GeneralActions["Diplomacy"];
- case ActionTypes["Hyperbolic Regeneration Chamber"]:
- return GeneralActions["Hyperbolic Regeneration Chamber"];
- default:
- return null;
- }
+ updateSkillMultipliers(this);
}
// Sets the player to the "IDLE" action
@@ -529,448 +432,8 @@ Bladeburner.prototype.resetAction = function() {
this.action = new ActionIdentifier({type:ActionTypes.Idle});
}
-Bladeburner.prototype.startAction = function(actionId) {
- if (actionId == null) {return;}
- this.action = actionId;
- this.actionTimeCurrent = 0;
- switch (actionId.type) {
- case ActionTypes["Idle"]:
- this.actionTimeToComplete = 0;
- break;
- case ActionTypes["Contract"]:
- try {
- var action = this.getActionObject(actionId);
- if (action == null) {
- throw new Error("Failed to get Contract Object for: " + actionId.name);
- }
- if (action.count < 1) {return this.resetAction();}
- this.actionTimeToComplete = action.getActionTime(this);
- } catch(e) {
- exceptionAlert(e);
- }
- break;
- case ActionTypes["Operation"]:
- try {
- var action = this.getActionObject(actionId);
- if (action == null) {
- throw new Error ("Failed to get Operation Object for: " + actionId.name);
- }
- if (action.count < 1) {return this.resetAction();}
- if (actionId.name === "Raid" && this.getCurrentCity().commsEst === 0) {return this.resetAction();}
- this.actionTimeToComplete = action.getActionTime(this);
- } catch(e) {
- exceptionAlert(e);
- }
- break;
- case ActionTypes["BlackOp"]:
- case ActionTypes["BlackOperation"]:
- try {
- // Safety measure - don't repeat BlackOps that are already done
- if (this.blackops[actionId.name] != null) {
- this.resetAction();
- this.log("Error: Tried to start a Black Operation that had already been completed");
- break;
- }
-
- var 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) {
- exceptionAlert(e);
- }
- break;
- case ActionTypes["Recruitment"]:
- this.actionTimeToComplete = getRecruitmentTime(this, Player);
- break;
- case ActionTypes["Training"]:
- case ActionTypes["FieldAnalysis"]:
- case ActionTypes["Field Analysis"]:
- this.actionTimeToComplete = 30;
- break;
- case ActionTypes["Diplomacy"]:
- case ActionTypes["Hyperbolic Regeneration Chamber"]:
- this.actionTimeToComplete = 60;
- break;
- default:
- throw new Error("Invalid Action Type in Bladeburner.startAction(): " + actionId.type);
- break;
- }
-}
-
-Bladeburner.prototype.processAction = function(seconds) {
- if (this.action.type === ActionTypes["Idle"]) {return;}
- if (this.actionTimeToComplete <= 0) {
- throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
- }
- if (!(this.action instanceof ActionIdentifier)) {
- throw new Error("Bladeburner.action is not an ActionIdentifier Object");
- }
-
- // If the previous action went past its completion time, add to the next action
- // This is not added inmediatly in case the automation changes the action
- this.actionTimeCurrent += seconds + this.actionTimeOverflow;
- this.actionTimeOverflow = 0;
- if (this.actionTimeCurrent >= this.actionTimeToComplete) {
- this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
- return this.completeAction();
- }
-}
-
-Bladeburner.prototype.completeAction = function() {
- switch (this.action.type) {
- case ActionTypes["Contract"]:
- case ActionTypes["Operation"]:
- try {
- var isOperation = (this.action.type === ActionTypes["Operation"]);
- var action = this.getActionObject(this.action);
- if (action == null) {
- throw new Error("Failed to get Contract/Operation Object for: " + this.action.name);
- }
- var difficulty = action.getDifficulty();
- var difficultyMultiplier = Math.pow(difficulty, BladeburnerConstants.DiffMultExponentialFactor) + difficulty / BladeburnerConstants.DiffMultLinearFactor;
- var rewardMultiplier = Math.pow(action.rewardFac, action.level-1);
-
- // Stamina loss is based on difficulty
- this.stamina -= (BladeburnerConstants.BaseStaminaLoss * difficultyMultiplier);
- if (this.stamina < 0) {this.stamina = 0;}
-
- // Process Contract/Operation success/failure
- if (action.attempt(this)) {
- gainActionStats(this, Player, action, true);
- ++action.successes;
- --action.count;
-
- // Earn money for contracts
- var moneyGain = 0;
- if (!isOperation) {
- moneyGain = BladeburnerConstants.ContractBaseMoneyGain * rewardMultiplier * this.skillMultipliers.money;
- Player.gainMoney(moneyGain);
- Player.recordMoneySource(moneyGain, "bladeburner");
- }
-
- if (isOperation) {
- action.setMaxLevel(BladeburnerConstants.OperationSuccessesPerLevel);
- } else {
- action.setMaxLevel(BladeburnerConstants.ContractSuccessesPerLevel);
- }
- if (action.rankGain) {
- var gain = addOffset(action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank, 10);
- this.changeRank(gain);
- if (isOperation && this.logging.ops) {
- this.log(action.name + " successfully completed! Gained " + formatNumber(gain, 3) + " rank");
- } else if (!isOperation && this.logging.contracts) {
- this.log(action.name + " contract successfully completed! Gained " + formatNumber(gain, 3) + " rank and " + numeralWrapper.formatMoney(moneyGain));
- }
- }
- isOperation ? this.completeOperation(true) : this.completeContract(true);
- } else {
- gainActionStats(this, Player, action, false);
- ++action.failures;
- var loss = 0, damage = 0;
- if (action.rankLoss) {
- loss = addOffset(action.rankLoss * rewardMultiplier, 10);
- this.changeRank(-1 * loss);
- }
- if (action.hpLoss) {
- damage = action.hpLoss * difficultyMultiplier;
- damage = Math.ceil(addOffset(damage, 10));
- this.hpLost += damage;
- const cost = calculateHospitalizationCost(Player, damage);
- if (Player.takeDamage(damage)) {
- ++this.numHosp;
- this.moneyLost += cost;
- }
- }
- var logLossText = "";
- if (loss > 0) {logLossText += "Lost " + formatNumber(loss, 3) + " rank. ";}
- if (damage > 0) {logLossText += "Took " + formatNumber(damage, 0) + " damage.";}
- if (isOperation && this.logging.ops) {
- this.log(action.name + " failed! " + logLossText);
- } else if (!isOperation && this.logging.contracts) {
- this.log(action.name + " contract failed! " + logLossText);
- }
- isOperation ? this.completeOperation(false) : this.completeContract(false);
- }
- if (action.autoLevel) {action.level = action.maxLevel;} // Autolevel
- this.startAction(this.action); // Repeat action
- } catch(e) {
- exceptionAlert(e);
- }
- break;
- case ActionTypes["BlackOp"]:
- case ActionTypes["BlackOperation"]:
- try {
- var action = this.getActionObject(this.action);
- if (action == null || !(action instanceof BlackOperation)) {
- throw new Error("Failed to get BlackOperation Object for: " + this.action.name);
- }
- var difficulty = action.getDifficulty();
- var difficultyMultiplier = Math.pow(difficulty, BladeburnerConstants.DiffMultExponentialFactor) + difficulty / BladeburnerConstants.DiffMultLinearFactor;
-
- // Stamina loss is based on difficulty
- this.stamina -= (BladeburnerConstants.BaseStaminaLoss * difficultyMultiplier);
- if (this.stamina < 0) {this.stamina = 0;}
-
- // Team loss variables
- var teamCount = action.teamCount, teamLossMax;
-
- if (action.attempt(this)) {
- gainActionStats(this, Player, action, true);
- action.count = 0;
- this.blackops[action.name] = true;
- var rankGain = 0;
- if (action.rankGain) {
- rankGain = addOffset(action.rankGain * BitNodeMultipliers.BladeburnerRank, 10);
- this.changeRank(rankGain);
- }
- teamLossMax = Math.ceil(teamCount/2);
-
- // Operation Daedalus
- if (action.name === "Operation Daedalus") {
- this.resetAction();
- return hackWorldDaemon(Player.bitNodeN);
- }
-
- if (this.logging.blackops) {
- this.log(action.name + " successful! Gained " + formatNumber(rankGain, 1) + " rank");
- }
- } else {
- gainActionStats(this, Player, action, false);
- var rankLoss = 0, damage = 0;
- if (action.rankLoss) {
- rankLoss = addOffset(action.rankLoss, 10);
- this.changeRank(-1 * rankLoss);
- }
- if (action.hpLoss) {
- damage = action.hpLoss * difficultyMultiplier;
- damage = Math.ceil(addOffset(damage, 10));
- const cost = calculateHospitalizationCost(Player, damage);
- if (Player.takeDamage(damage)) {
- ++this.numHosp;
- this.moneyLost += cost;
- }
- }
- teamLossMax = Math.floor(teamCount);
-
- if (this.logging.blackops) {
- this.log(action.name + " failed! Lost " + formatNumber(rankLoss, 1) + " rank and took " + formatNumber(damage, 0) + " damage");
- }
- }
-
- this.resetAction(); // Stop regardless of success or fail
-
- // Calculate team lossses
- if (teamCount >= 1) {
- var losses = getRandomInt(1, teamLossMax);
- this.teamSize -= losses;
- this.teamLost += losses;
- if (this.logging.blackops) {
- this.log("You lost " + formatNumber(losses, 0) + " team members during " + action.name);
- }
- }
- } catch(e) {
- exceptionAlert(e);
- }
- break;
- case ActionTypes["Training"]:
- this.stamina -= (0.5 * BladeburnerConstants.BaseStaminaLoss);
- var strExpGain = 30 * Player.strength_exp_mult,
- defExpGain = 30 * Player.defense_exp_mult,
- dexExpGain = 30 * Player.dexterity_exp_mult,
- agiExpGain = 30 * Player.agility_exp_mult,
- staminaGain = 0.04 * this.skillMultipliers.stamina;
- Player.gainStrengthExp(strExpGain);
- Player.gainDefenseExp(defExpGain);
- Player.gainDexterityExp(dexExpGain);
- Player.gainAgilityExp(agiExpGain);
- this.staminaBonus += (staminaGain);
- if (this.logging.general) {
- this.log("Training completed. Gained: " +
- formatNumber(strExpGain, 1) + " str exp, " +
- formatNumber(defExpGain, 1) + " def exp, " +
- formatNumber(dexExpGain, 1) + " dex exp, " +
- formatNumber(agiExpGain, 1) + " agi exp, " +
- formatNumber(staminaGain, 3) + " max stamina");
- }
- this.startAction(this.action); // Repeat action
- break;
- case ActionTypes["FieldAnalysis"]:
- case ActionTypes["Field Analysis"]:
- // Does not use stamina. Effectiveness depends on hacking, int, and cha
- var eff = 0.04 * Math.pow(Player.hacking_skill, 0.3) +
- 0.04 * Math.pow(Player.intelligence, 0.9) +
- 0.02 * Math.pow(Player.charisma, 0.3);
- eff *= Player.bladeburner_analysis_mult;
- if (isNaN(eff) || eff < 0) {
- throw new Error("Field Analysis Effectiveness calculated to be NaN or negative");
- }
- var hackingExpGain = 20 * Player.hacking_exp_mult,
- charismaExpGain = 20 * Player.charisma_exp_mult;
- Player.gainHackingExp(hackingExpGain);
- Player.gainIntelligenceExp(BladeburnerConstants.BaseIntGain);
- Player.gainCharismaExp(charismaExpGain);
- this.changeRank(0.1 * BitNodeMultipliers.BladeburnerRank);
- this.getCurrentCity().improvePopulationEstimateByPercentage(eff * this.skillMultipliers.successChanceEstimate);
- if (this.logging.general) {
- this.log("Field analysis completed. Gained 0.1 rank, " + formatNumber(hackingExpGain, 1) + " hacking exp, and " + formatNumber(charismaExpGain, 1) + " charisma exp");
- }
- this.startAction(this.action); // Repeat action
- break;
- case ActionTypes["Recruitment"]:
- var successChance = getRecruitmentSuccessChance(this, Player);
- if (Math.random() < successChance) {
- var expGain = 2 * BladeburnerConstants.BaseStatGain * this.actionTimeToComplete;
- Player.gainCharismaExp(expGain);
- ++this.teamSize;
- if (this.logging.general) {
- this.log("Successfully recruited a team member! Gained " + formatNumber(expGain, 1) + " charisma exp");
- }
- } else {
- var expGain = BladeburnerConstants.BaseStatGain * this.actionTimeToComplete;
- Player.gainCharismaExp(expGain);
- if (this.logging.general) {
- this.log("Failed to recruit a team member. Gained " + formatNumber(expGain, 1) + " charisma exp");
- }
- }
- this.startAction(this.action); // Repeat action
- break;
- case ActionTypes["Diplomacy"]:
- var eff = getDiplomacyEffectiveness(this, Player);
- this.getCurrentCity().chaos *= eff;
- if (this.getCurrentCity().chaos < 0) { this.getCurrentCity().chaos = 0; }
- if (this.logging.general) {
- this.log(`Diplomacy completed. Chaos levels in the current city fell by ${numeralWrapper.formatPercentage(1 - eff)}`);
- }
- this.startAction(this.action); // Repeat Action
- break;
- case ActionTypes["Hyperbolic Regeneration Chamber"]: {
- Player.regenerateHp(BladeburnerConstants.HrcHpGain);
-
- const staminaGain = this.maxStamina * (BladeburnerConstants.HrcStaminaGain / 100);
- this.stamina = Math.min(this.maxStamina, this.stamina + staminaGain);
- this.startAction(this.action);
- if (this.logging.general) {
- this.log(`Rested in Hyperbolic Regeneration Chamber. Restored ${BladeburnerConstants.HrcHpGain} HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`);
- }
- break;
- }
- default:
- console.error(`Bladeburner.completeAction() called for invalid action: ${this.action.type}`);
- break;
- }
-}
-
-Bladeburner.prototype.completeContract = function(success) {
- if (this.action.type !== ActionTypes.Contract) {
- throw new Error("completeContract() called even though current action is not a Contract");
- }
- var city = this.getCurrentCity();
- if (success) {
- switch (this.action.name) {
- case "Tracking":
- // Increase estimate accuracy by a relatively small amount
- city.improvePopulationEstimateByCount(getRandomInt(100, 1e3));
- break;
- case "Bounty Hunter":
- city.changePopulationByCount(-1, {estChange:-1});
- city.changeChaosByCount(0.02);
- break;
- case "Retirement":
- city.changePopulationByCount(-1, {estChange:-1});
- city.changeChaosByCount(0.04);
- break;
- default:
- throw new Error("Invalid Action name in completeContract: " + this.action.name);
- }
- }
-}
-
-Bladeburner.prototype.completeOperation = function(success) {
- if (this.action.type !== ActionTypes.Operation) {
- throw new Error("completeOperation() called even though current action is not an Operation");
- }
- var action = this.getActionObject(this.action);
- if (action == null) {
- throw new Error("Failed to get Contract/Operation Object for: " + this.action.name);
- }
-
- // Calculate team losses
- var teamCount = action.teamCount, max;
- if (teamCount >= 1) {
- if (success) {
- max = Math.ceil(teamCount/2);
- } else {
- max = Math.floor(teamCount)
- }
- var losses = getRandomInt(0, max);
- this.teamSize -= losses;
- this.teamLost += losses;
- if (this.logging.ops && losses > 0) {
- this.log("Lost " + formatNumber(losses, 0) + " team members during this " + action.name);
- }
- }
-
- var city = this.getCurrentCity();
- switch (action.name) {
- case "Investigation":
- if (success) {
- city.improvePopulationEstimateByPercentage(0.4 * this.skillMultipliers.successChanceEstimate);
- if (Math.random() < (0.02 * this.skillMultipliers.successChanceEstimate)) {
- city.improveCommunityEstimate(1);
- }
- } else {
- triggerPotentialMigration(this, this.city, 0.1);
- }
- break;
- case "Undercover Operation":
- if (success) {
- city.improvePopulationEstimateByPercentage(0.8 * this.skillMultipliers.successChanceEstimate);
- if (Math.random() < (0.02 * this.skillMultipliers.successChanceEstimate)) {
- city.improveCommunityEstimate(1);
- }
- } else {
- triggerPotentialMigration(this, this.city, 0.15);
- }
- break;
- case "Sting Operation":
- if (success) {
- city.changePopulationByPercentage(-0.1, {changeEstEqually:true, nonZero:true});
- }
- city.changeChaosByCount(0.1);
- break;
- case "Raid":
- if (success) {
- city.changePopulationByPercentage(-1, {changeEstEqually:true, nonZero:true});
- --city.comms;
- --city.commsEst;
- } else {
- var change = getRandomInt(-10, -5) / 10;
- city.changePopulationByPercentage(change, {nonZero:true});
- }
- city.changeChaosByPercentage(getRandomInt(1, 5));
- break;
- case "Stealth Retirement Operation":
- if (success) {
- city.changePopulationByPercentage(-0.5, {changeEstEqually:true,nonZero:true});
- }
- city.changeChaosByPercentage(getRandomInt(-3, -1));
- break;
- case "Assassination":
- if (success) {
- city.changePopulationByCount(-1, {estChange:-1});
- }
- city.changeChaosByPercentage(getRandomInt(-5, 5));
- break;
- default:
- throw new Error("Invalid Action name in completeOperation: " + this.action.name);
- }
-}
-
-
////////////////////////////////////////////////////////////////////////////////
-/////////////////////////////Unconvertable for now//////////////////////////////
+//////////////////////////// Unconvertable for now /////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Bladeburner Console Window
@@ -995,7 +458,7 @@ Bladeburner.prototype.executeConsoleCommands = function(commands) {
}
////////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////Netscript Fns//////////////////////////////////
+//////////////////////////////// Netscript Fns /////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Bladeburner.prototype.getTypeAndNameFromActionId = function(actionId) {
@@ -1044,7 +507,7 @@ Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript
// 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 = this.getActionObject(actionId);
+ let action = getActionObject(this, actionId);
if (action.reqdRank > this.rank) {
workerScript.log("bladeburner.startAction", `Insufficient rank to start Black Op '${actionId.name}'.`);
return false;
@@ -1080,11 +543,11 @@ Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript
}
try {
- this.startAction(actionId);
+ startAction(this, Player, actionId);
workerScript.log("bladeburner.startAction", `Starting bladeburner action with type '${type}' and name ${name}"`);
return true;
} catch(e) {
- this.resetAction();
+ resetAction(this);
workerScript.log("bladeburner.startAction", errorLogText);
return false;
}
@@ -1098,7 +561,7 @@ Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScri
return -1;
}
- const actionObj = this.getActionObject(actionId);
+ const actionObj = getActionObject(this, actionId);
if (actionObj == null) {
workerScript.log("bladeburner.getActionTime", errorLogText);
return -1;
@@ -1133,7 +596,7 @@ Bladeburner.prototype.getActionEstimatedSuccessChanceNetscriptFn = function(type
return -1;
}
- const actionObj = this.getActionObject(actionId);
+ const actionObj = getActionObject(this, actionId);
if (actionObj == null) {
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText);
return -1;
@@ -1165,7 +628,7 @@ Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name,
return -1;
}
- const actionObj = this.getActionObject(actionId);
+ const actionObj = getActionObject(this, actionId);
if (actionObj == null) {
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
return -1;
@@ -1261,7 +724,7 @@ Bladeburner.prototype.getTeamSizeNetscriptFn = function(type, name, workerScript
return -1;
}
- const actionObj = this.getActionObject(actionId);
+ const actionObj = getActionObject(this, actionId);
if (actionObj == null) {
workerScript.log("bladeburner.getTeamSize", errorLogText);
return -1;
@@ -1291,7 +754,7 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
return -1;
}
- const actionObj = this.getActionObject(actionId);
+ const actionObj = getActionObject(this, actionId);
if (actionObj == null) {
workerScript.log("bladeburner.setTeamSize", errorLogText);
return -1;
diff --git a/src/Bladeburner/Bladeburner.ts b/src/Bladeburner/Bladeburner.ts
index a121ed51a..067f76949 100644
--- a/src/Bladeburner/Bladeburner.ts
+++ b/src/Bladeburner/Bladeburner.ts
@@ -7,6 +7,7 @@ import { IActionIdentifier } from "./IActionIdentifier";
import { ActionIdentifier } from "./ActionIdentifier";
import { ActionTypes } from "./data/ActionTypes";
import { BlackOperations } from "./BlackOperations";
+import { BlackOperation } from "./BlackOperation";
import { GeneralActions } from "./GeneralActions";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { Skills } from "./Skills";
@@ -18,6 +19,13 @@ import { ConsoleHelpText } from "./data/Help";
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { BladeburnerConstants } from "./data/Constants";
+import { numeralWrapper } from "../ui/numeralFormat";
+import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
+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";
export function getActionIdFromTypeAndName(bladeburner: IBladeburner, type: string = "", name: string = ""): IActionIdentifier | null {
if (type === "" || name === "") {return null;}
@@ -104,7 +112,7 @@ export function getActionIdFromTypeAndName(bladeburner: IBladeburner, type: stri
return null;
}
-export function executeStartConsoleCommand(bladeburner: IBladeburner, args: string[]): void {
+export function executeStartConsoleCommand(bladeburner: IBladeburner, player: IPlayer, args: string[]): void {
if (args.length !== 3) {
bladeburner.postToConsole("Invalid usage of 'start' console command: start [type] [name]");
bladeburner.postToConsole("Use 'help start' for more info");
@@ -117,7 +125,7 @@ export function executeStartConsoleCommand(bladeburner: IBladeburner, args: stri
if (GeneralActions[name] != null) {
bladeburner.action.type = ActionTypes[name];
bladeburner.action.name = name;
- bladeburner.startAction(bladeburner.action);
+ startAction(bladeburner,player, bladeburner.action);
} else {
bladeburner.postToConsole("Invalid action name specified: " + args[2]);
}
@@ -127,7 +135,7 @@ export function executeStartConsoleCommand(bladeburner: IBladeburner, args: stri
if (bladeburner.contracts[name] != null) {
bladeburner.action.type = ActionTypes.Contract;
bladeburner.action.name = name;
- bladeburner.startAction(bladeburner.action);
+ startAction(bladeburner,player, bladeburner.action);
} else {
bladeburner.postToConsole("Invalid contract name specified: " + args[2]);
}
@@ -139,7 +147,7 @@ export function executeStartConsoleCommand(bladeburner: IBladeburner, args: stri
if (bladeburner.operations[name] != null) {
bladeburner.action.type = ActionTypes.Operation;
bladeburner.action.name = name;
- bladeburner.startAction(bladeburner.action);
+ startAction(bladeburner,player, bladeburner.action);
} else {
bladeburner.postToConsole("Invalid Operation name specified: " + args[2]);
}
@@ -151,7 +159,7 @@ export function executeStartConsoleCommand(bladeburner: IBladeburner, args: stri
if (BlackOperations[name] != null) {
bladeburner.action.type = ActionTypes.BlackOperation;
bladeburner.action.name = name;
- bladeburner.startAction(bladeburner.action);
+ startAction(bladeburner,player, bladeburner.action);
} else {
bladeburner.postToConsole("Invalid BlackOp name specified: " + args[2]);
}
@@ -512,7 +520,7 @@ export function parseCommandArguments(command: string): string[] {
return args;
}
-export function executeConsoleCommand(bladeburner: IBladeburner, command: string) {
+export function executeConsoleCommand(bladeburner: IBladeburner, player: IPlayer, command: string) {
command = command.trim();
command = command.replace(/\s\s+/g, ' '); // Replace all whitespace w/ a single space
@@ -537,7 +545,7 @@ export function executeConsoleCommand(bladeburner: IBladeburner, command: string
executeSkillConsoleCommand(bladeburner, args);
break;
case "start":
- executeStartConsoleCommand(bladeburner, args);
+ executeStartConsoleCommand(bladeburner, player, args);
break;
case "stop":
bladeburner.resetAction();
@@ -549,7 +557,7 @@ export function executeConsoleCommand(bladeburner: IBladeburner, command: string
}
// Handles a potential series of commands (comm1; comm2; comm3;)
-export function executeConsoleCommands(bladeburner: IBladeburner, commands: string): void {
+export function executeConsoleCommands(bladeburner: IBladeburner, player: IPlayer, commands: string): void {
try {
// Console History
if (bladeburner.consoleHistory[bladeburner.consoleHistory.length-1] != commands) {
@@ -561,7 +569,7 @@ export function executeConsoleCommands(bladeburner: IBladeburner, commands: stri
const arrayOfCommands = commands.split(";");
for (let i = 0; i < arrayOfCommands.length; ++i) {
- executeConsoleCommand(bladeburner, arrayOfCommands[i]);
+ executeConsoleCommand(bladeburner, player, arrayOfCommands[i]);
}
} catch(e) {
exceptionAlert(e);
@@ -742,3 +750,564 @@ export function getRecruitmentTime(bladeburner: IBladeburner, player: IPlayer):
const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor));
}
+
+export function resetSkillMultipliers(bladeburner: IBladeburner): void {
+ bladeburner.skillMultipliers = {
+ successChanceAll: 1,
+ successChanceStealth: 1,
+ successChanceKill: 1,
+ successChanceContract: 1,
+ successChanceOperation: 1,
+ successChanceEstimate: 1,
+ actionTime: 1,
+ effHack: 1,
+ effStr: 1,
+ effDef: 1,
+ effDex: 1,
+ effAgi: 1,
+ effCha: 1,
+ effInt: 1,
+ stamina: 1,
+ money: 1,
+ expGain: 1,
+ };
+}
+
+export function updateSkillMultipliers(bladeburner: IBladeburner): void {
+ resetSkillMultipliers(bladeburner);
+ for (const skillName in bladeburner.skills) {
+ if (bladeburner.skills.hasOwnProperty(skillName)) {
+ const skill = Skills[skillName];
+ if (skill == null) {
+ throw new Error("Could not find Skill Object for: " + skillName);
+ }
+ const level = bladeburner.skills[skillName];
+ if (level == null || level <= 0) {continue;} //Not upgraded
+
+ const multiplierNames = Object.keys(bladeburner.skillMultipliers);
+ for (let i = 0; i < multiplierNames.length; ++i) {
+ const multiplierName = multiplierNames[i];
+ if (skill.getMultiplier(multiplierName) != null && !isNaN(skill.getMultiplier(multiplierName))) {
+ const value = skill.getMultiplier(multiplierName) * level;
+ let multiplierValue = 1 + (value / 100);
+ if (multiplierName === "actionTime") {
+ multiplierValue = 1 - (value / 100);
+ }
+ bladeburner.skillMultipliers[multiplierName] *= multiplierValue;
+ }
+ }
+ }
+ }
+}
+
+
+// Sets the player to the "IDLE" action
+export function resetAction(bladeburner: IBladeburner): void {
+ bladeburner.action = new ActionIdentifier({type:ActionTypes.Idle});
+}
+
+export function completeOperation(bladeburner: IBladeburner, success: boolean): void {
+ if (bladeburner.action.type !== ActionTypes.Operation) {
+ throw new Error("completeOperation() called even though current action is not an Operation");
+ }
+ const action = getActionObject(bladeburner, bladeburner.action);
+ if (action == null) {
+ throw new Error("Failed to get Contract/Operation Object for: " + bladeburner.action.name);
+ }
+
+ // Calculate team losses
+ const teamCount = action.teamCount;
+ if (teamCount >= 1) {
+ let max;
+ if (success) {
+ max = Math.ceil(teamCount/2);
+ } else {
+ max = Math.floor(teamCount)
+ }
+ const losses = getRandomInt(0, max);
+ bladeburner.teamSize -= losses;
+ bladeburner.teamLost += losses;
+ if (bladeburner.logging.ops && losses > 0) {
+ bladeburner.log("Lost " + formatNumber(losses, 0) + " team members during this " + action.name);
+ }
+ }
+
+ const city = bladeburner.getCurrentCity();
+ switch (action.name) {
+ case "Investigation":
+ if (success) {
+ city.improvePopulationEstimateByPercentage(0.4 * bladeburner.skillMultipliers.successChanceEstimate);
+ if (Math.random() < (0.02 * bladeburner.skillMultipliers.successChanceEstimate)) {
+ city.improveCommunityEstimate(1);
+ }
+ } else {
+ triggerPotentialMigration(bladeburner, bladeburner.city, 0.1);
+ }
+ break;
+ case "Undercover Operation":
+ if (success) {
+ city.improvePopulationEstimateByPercentage(0.8 * bladeburner.skillMultipliers.successChanceEstimate);
+ if (Math.random() < (0.02 * bladeburner.skillMultipliers.successChanceEstimate)) {
+ city.improveCommunityEstimate(1);
+ }
+ } else {
+ triggerPotentialMigration(bladeburner, bladeburner.city, 0.15);
+ }
+ break;
+ case "Sting Operation":
+ if (success) {
+ city.changePopulationByPercentage(-0.1, {changeEstEqually:true, nonZero:true});
+ }
+ city.changeChaosByCount(0.1);
+ break;
+ case "Raid":
+ if (success) {
+ city.changePopulationByPercentage(-1, {changeEstEqually:true, nonZero:true});
+ --city.comms;
+ --city.commsEst;
+ } else {
+ const change = getRandomInt(-10, -5) / 10;
+ city.changePopulationByPercentage(change, {nonZero:true, changeEstEqually:false});
+ }
+ city.changeChaosByPercentage(getRandomInt(1, 5));
+ break;
+ case "Stealth Retirement Operation":
+ if (success) {
+ city.changePopulationByPercentage(-0.5, {changeEstEqually:true,nonZero:true});
+ }
+ city.changeChaosByPercentage(getRandomInt(-3, -1));
+ break;
+ case "Assassination":
+ if (success) {
+ city.changePopulationByCount(-1, {estChange:-1, estOffset: 0});
+ }
+ city.changeChaosByPercentage(getRandomInt(-5, 5));
+ break;
+ default:
+ throw new Error("Invalid Action name in completeOperation: " + bladeburner.action.name);
+ }
+}
+
+export function getActionObject(bladeburner: IBladeburner, actionId: IActionIdentifier): IAction | null {
+ /**
+ * Given an ActionIdentifier object, returns the corresponding
+ * GeneralAction, Contract, Operation, or BlackOperation object
+ */
+ switch (actionId.type) {
+ case ActionTypes["Contract"]:
+ return bladeburner.contracts[actionId.name];
+ case ActionTypes["Operation"]:
+ return bladeburner.operations[actionId.name];
+ case ActionTypes["BlackOp"]:
+ case ActionTypes["BlackOperation"]:
+ return BlackOperations[actionId.name];
+ case ActionTypes["Training"]:
+ return GeneralActions["Training"];
+ case ActionTypes["Field Analysis"]:
+ return GeneralActions["Field Analysis"];
+ case ActionTypes["Recruitment"]:
+ return GeneralActions["Recruitment"];
+ case ActionTypes["Diplomacy"]:
+ return GeneralActions["Diplomacy"];
+ case ActionTypes["Hyperbolic Regeneration Chamber"]:
+ return GeneralActions["Hyperbolic Regeneration Chamber"];
+ default:
+ return null;
+ }
+}
+
+export function completeContract(bladeburner: IBladeburner, success: boolean): void {
+ if (bladeburner.action.type !== ActionTypes.Contract) {
+ throw new Error("completeContract() called even though current action is not a Contract");
+ }
+ var city = bladeburner.getCurrentCity();
+ if (success) {
+ switch (bladeburner.action.name) {
+ case "Tracking":
+ // Increase estimate accuracy by a relatively small amount
+ city.improvePopulationEstimateByCount(getRandomInt(100, 1e3));
+ break;
+ case "Bounty Hunter":
+ city.changePopulationByCount(-1, {estChange:-1, estOffset: 0});
+ city.changeChaosByCount(0.02);
+ break;
+ case "Retirement":
+ city.changePopulationByCount(-1, {estChange:-1, estOffset: 0});
+ city.changeChaosByCount(0.04);
+ break;
+ default:
+ throw new Error("Invalid Action name in completeContract: " + bladeburner.action.name);
+ }
+ }
+}
+
+export function completeAction(bladeburner: IBladeburner, player: IPlayer): void {
+ switch (bladeburner.action.type) {
+ case ActionTypes["Contract"]:
+ case ActionTypes["Operation"]: {
+ try {
+ const isOperation = (bladeburner.action.type === ActionTypes["Operation"]);
+ const action = getActionObject(bladeburner, bladeburner.action);
+ if (action == null) {
+ throw new Error("Failed to get Contract/Operation Object for: " + bladeburner.action.name);
+ }
+ const difficulty = action.getDifficulty();
+ const difficultyMultiplier = Math.pow(difficulty, BladeburnerConstants.DiffMultExponentialFactor) + difficulty / BladeburnerConstants.DiffMultLinearFactor;
+ const rewardMultiplier = Math.pow(action.rewardFac, action.level-1);
+
+ // Stamina loss is based on difficulty
+ bladeburner.stamina -= (BladeburnerConstants.BaseStaminaLoss * difficultyMultiplier);
+ if (bladeburner.stamina < 0) {bladeburner.stamina = 0;}
+
+ // Process Contract/Operation success/failure
+ if (action.attempt(bladeburner)) {
+ gainActionStats(bladeburner, player, action, true);
+ ++action.successes;
+ --action.count;
+
+ // Earn money for contracts
+ let moneyGain = 0;
+ if (!isOperation) {
+ moneyGain = BladeburnerConstants.ContractBaseMoneyGain * rewardMultiplier * bladeburner.skillMultipliers.money;
+ player.gainMoney(moneyGain);
+ player.recordMoneySource(moneyGain, "bladeburner");
+ }
+
+ if (isOperation) {
+ action.setMaxLevel(BladeburnerConstants.OperationSuccessesPerLevel);
+ } else {
+ action.setMaxLevel(BladeburnerConstants.ContractSuccessesPerLevel);
+ }
+ if (action.rankGain) {
+ const gain = addOffset(action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank, 10);
+ changeRank(bladeburner, player, gain);
+ if (isOperation && bladeburner.logging.ops) {
+ bladeburner.log(action.name + " successfully completed! Gained " + formatNumber(gain, 3) + " rank");
+ } else if (!isOperation && bladeburner.logging.contracts) {
+ bladeburner.log(action.name + " contract successfully completed! Gained " + formatNumber(gain, 3) + " rank and " + numeralWrapper.formatMoney(moneyGain));
+ }
+ }
+ isOperation ? completeOperation(bladeburner, true) : completeContract(bladeburner, true);
+ } else {
+ gainActionStats(bladeburner, player, action, false);
+ ++action.failures;
+ let loss = 0, damage = 0;
+ if (action.rankLoss) {
+ loss = addOffset(action.rankLoss * rewardMultiplier, 10);
+ changeRank(bladeburner, player, -1 * loss);
+ }
+ if (action.hpLoss) {
+ damage = action.hpLoss * difficultyMultiplier;
+ damage = Math.ceil(addOffset(damage, 10));
+ bladeburner.hpLost += damage;
+ const cost = calculateHospitalizationCost(player, damage);
+ if (player.takeDamage(damage)) {
+ ++bladeburner.numHosp;
+ bladeburner.moneyLost += cost;
+ }
+ }
+ let logLossText = "";
+ if (loss > 0) {logLossText += "Lost " + formatNumber(loss, 3) + " rank. ";}
+ if (damage > 0) {logLossText += "Took " + formatNumber(damage, 0) + " damage.";}
+ if (isOperation && bladeburner.logging.ops) {
+ bladeburner.log(action.name + " failed! " + logLossText);
+ } else if (!isOperation && bladeburner.logging.contracts) {
+ bladeburner.log(action.name + " contract failed! " + logLossText);
+ }
+ isOperation ? completeOperation(bladeburner, false) : completeContract(bladeburner, false);
+ }
+ if (action.autoLevel) {action.level = action.maxLevel;} // Autolevel
+ startAction(bladeburner,player, bladeburner.action); // Repeat action
+ } catch(e) {
+ exceptionAlert(e);
+ }
+ break;
+ }
+ case ActionTypes["BlackOp"]:
+ case ActionTypes["BlackOperation"]: {
+ try {
+ const action = getActionObject(bladeburner, bladeburner.action);
+ if (action == null || !(action instanceof BlackOperation)) {
+ throw new Error("Failed to get BlackOperation Object for: " + bladeburner.action.name);
+ }
+ const difficulty = action.getDifficulty();
+ const difficultyMultiplier = Math.pow(difficulty, BladeburnerConstants.DiffMultExponentialFactor) + difficulty / BladeburnerConstants.DiffMultLinearFactor;
+
+ // Stamina loss is based on difficulty
+ bladeburner.stamina -= (BladeburnerConstants.BaseStaminaLoss * difficultyMultiplier);
+ if (bladeburner.stamina < 0) {bladeburner.stamina = 0;}
+
+ // Team loss variables
+ const teamCount = action.teamCount;
+ let teamLossMax;
+
+ if (action.attempt(bladeburner)) {
+ gainActionStats(bladeburner, player, action, true);
+ action.count = 0;
+ bladeburner.blackops[action.name] = true;
+ let rankGain = 0;
+ if (action.rankGain) {
+ rankGain = addOffset(action.rankGain * BitNodeMultipliers.BladeburnerRank, 10);
+ changeRank(bladeburner, player, rankGain);
+ }
+ teamLossMax = Math.ceil(teamCount/2);
+
+ // Operation Daedalus
+ if (action.name === "Operation Daedalus") {
+ resetAction(bladeburner);
+ return hackWorldDaemon(player.bitNodeN);
+ }
+
+ if (bladeburner.logging.blackops) {
+ bladeburner.log(action.name + " successful! Gained " + formatNumber(rankGain, 1) + " rank");
+ }
+ } else {
+ gainActionStats(bladeburner, player, action, false);
+ let rankLoss = 0;
+ let damage = 0;
+ if (action.rankLoss) {
+ rankLoss = addOffset(action.rankLoss, 10);
+ changeRank(bladeburner, player, -1 * rankLoss);
+ }
+ if (action.hpLoss) {
+ damage = action.hpLoss * difficultyMultiplier;
+ damage = Math.ceil(addOffset(damage, 10));
+ const cost = calculateHospitalizationCost(player, damage);
+ if (player.takeDamage(damage)) {
+ ++bladeburner.numHosp;
+ bladeburner.moneyLost += cost;
+ }
+ }
+ teamLossMax = Math.floor(teamCount);
+
+ if (bladeburner.logging.blackops) {
+ bladeburner.log(action.name + " failed! Lost " + formatNumber(rankLoss, 1) + " rank and took " + formatNumber(damage, 0) + " damage");
+ }
+ }
+
+ resetAction(bladeburner); // Stop regardless of success or fail
+
+ // Calculate team lossses
+ if (teamCount >= 1) {
+ const losses = getRandomInt(1, teamLossMax);
+ bladeburner.teamSize -= losses;
+ bladeburner.teamLost += losses;
+ if (bladeburner.logging.blackops) {
+ bladeburner.log("You lost " + formatNumber(losses, 0) + " team members during " + action.name);
+ }
+ }
+ } catch(e) {
+ exceptionAlert(e);
+ }
+ break;
+ }
+ case ActionTypes["Training"]: {
+ bladeburner.stamina -= (0.5 * BladeburnerConstants.BaseStaminaLoss);
+ const strExpGain = 30 * player.strength_exp_mult,
+ defExpGain = 30 * player.defense_exp_mult,
+ dexExpGain = 30 * player.dexterity_exp_mult,
+ agiExpGain = 30 * player.agility_exp_mult,
+ staminaGain = 0.04 * bladeburner.skillMultipliers.stamina;
+ player.gainStrengthExp(strExpGain);
+ player.gainDefenseExp(defExpGain);
+ player.gainDexterityExp(dexExpGain);
+ player.gainAgilityExp(agiExpGain);
+ bladeburner.staminaBonus += (staminaGain);
+ if (bladeburner.logging.general) {
+ bladeburner.log("Training completed. Gained: " +
+ formatNumber(strExpGain, 1) + " str exp, " +
+ formatNumber(defExpGain, 1) + " def exp, " +
+ formatNumber(dexExpGain, 1) + " dex exp, " +
+ formatNumber(agiExpGain, 1) + " agi exp, " +
+ formatNumber(staminaGain, 3) + " max stamina");
+ }
+ startAction(bladeburner,player, bladeburner.action); // Repeat action
+ break;
+ }
+ case ActionTypes["FieldAnalysis"]:
+ case ActionTypes["Field Analysis"]: {
+ // Does not use stamina. Effectiveness depends on hacking, int, and cha
+ let eff = 0.04 * Math.pow(player.hacking_skill, 0.3) +
+ 0.04 * Math.pow(player.intelligence, 0.9) +
+ 0.02 * Math.pow(player.charisma, 0.3);
+ eff *= player.bladeburner_analysis_mult;
+ if (isNaN(eff) || eff < 0) {
+ throw new Error("Field Analysis Effectiveness calculated to be NaN or negative");
+ }
+ const hackingExpGain = 20 * player.hacking_exp_mult,
+ charismaExpGain = 20 * player.charisma_exp_mult;
+ player.gainHackingExp(hackingExpGain);
+ player.gainIntelligenceExp(BladeburnerConstants.BaseIntGain);
+ player.gainCharismaExp(charismaExpGain);
+ changeRank(bladeburner, player, 0.1 * BitNodeMultipliers.BladeburnerRank);
+ bladeburner.getCurrentCity().improvePopulationEstimateByPercentage(eff * bladeburner.skillMultipliers.successChanceEstimate);
+ if (bladeburner.logging.general) {
+ bladeburner.log("Field analysis completed. Gained 0.1 rank, " + formatNumber(hackingExpGain, 1) + " hacking exp, and " + formatNumber(charismaExpGain, 1) + " charisma exp");
+ }
+ startAction(bladeburner,player, bladeburner.action); // Repeat action
+ break;
+ }
+ case ActionTypes["Recruitment"]: {
+ const successChance = getRecruitmentSuccessChance(bladeburner, player);
+ if (Math.random() < successChance) {
+ const expGain = 2 * BladeburnerConstants.BaseStatGain * bladeburner.actionTimeToComplete;
+ player.gainCharismaExp(expGain);
+ ++bladeburner.teamSize;
+ if (bladeburner.logging.general) {
+ bladeburner.log("Successfully recruited a team member! Gained " + formatNumber(expGain, 1) + " charisma exp");
+ }
+ } else {
+ const expGain = BladeburnerConstants.BaseStatGain * bladeburner.actionTimeToComplete;
+ player.gainCharismaExp(expGain);
+ if (bladeburner.logging.general) {
+ bladeburner.log("Failed to recruit a team member. Gained " + formatNumber(expGain, 1) + " charisma exp");
+ }
+ }
+ startAction(bladeburner,player, bladeburner.action); // Repeat action
+ break;
+ }
+ case ActionTypes["Diplomacy"]: {
+ let eff = getDiplomacyEffectiveness(bladeburner, player);
+ bladeburner.getCurrentCity().chaos *= eff;
+ if (bladeburner.getCurrentCity().chaos < 0) { bladeburner.getCurrentCity().chaos = 0; }
+ if (bladeburner.logging.general) {
+ bladeburner.log(`Diplomacy completed. Chaos levels in the current city fell by ${numeralWrapper.formatPercentage(1 - eff)}`);
+ }
+ startAction(bladeburner,player, bladeburner.action); // Repeat Action
+ break;
+ }
+ case ActionTypes["Hyperbolic Regeneration Chamber"]: {
+ player.regenerateHp(BladeburnerConstants.HrcHpGain);
+
+ const staminaGain = bladeburner.maxStamina * (BladeburnerConstants.HrcStaminaGain / 100);
+ bladeburner.stamina = Math.min(bladeburner.maxStamina, bladeburner.stamina + staminaGain);
+ startAction(bladeburner,player, bladeburner.action);
+ if (bladeburner.logging.general) {
+ bladeburner.log(`Rested in Hyperbolic Regeneration Chamber. Restored ${BladeburnerConstants.HrcHpGain} HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`);
+ }
+ break;
+ }
+ default:
+ console.error(`Bladeburner.completeAction() called for invalid action: ${bladeburner.action.type}`);
+ break;
+ }
+}
+
+export function changeRank(bladeburner: IBladeburner, player: IPlayer, change: number): void {
+ if (isNaN(change)) {throw new Error("NaN passed into Bladeburner.changeRank()");}
+ bladeburner.rank += change;
+ if (bladeburner.rank < 0) {bladeburner.rank = 0;}
+ bladeburner.maxRank = Math.max(bladeburner.rank, bladeburner.maxRank);
+
+ var bladeburnersFactionName = "Bladeburners";
+ if (factionExists(bladeburnersFactionName)) {
+ var bladeburnerFac = Factions[bladeburnersFactionName];
+ if (!(bladeburnerFac instanceof Faction)) {
+ throw new Error("Could not properly get Bladeburner Faction object in Bladeburner UI Overview Faction button");
+ }
+ if (bladeburnerFac.isMember) {
+ var favorBonus = 1 + (bladeburnerFac.favor / 100);
+ bladeburnerFac.playerReputation += (BladeburnerConstants.RankToFactionRepFactor * change * player.faction_rep_mult * favorBonus);
+ }
+ }
+
+ // Gain skill points
+ var rankNeededForSp = (bladeburner.totalSkillPoints+1) * BladeburnerConstants.RanksPerSkillPoint;
+ if (bladeburner.maxRank >= rankNeededForSp) {
+ // Calculate how many skill points to gain
+ var gainedSkillPoints = Math.floor((bladeburner.maxRank - rankNeededForSp) / BladeburnerConstants.RanksPerSkillPoint + 1);
+ bladeburner.skillPoints += gainedSkillPoints;
+ bladeburner.totalSkillPoints += gainedSkillPoints;
+ }
+}
+
+export function processAction(bladeburner: IBladeburner, player: IPlayer, seconds: number): void {
+ if (bladeburner.action.type === ActionTypes["Idle"]) return;
+ if (bladeburner.actionTimeToComplete <= 0) {
+ throw new Error(`Invalid actionTimeToComplete value: ${bladeburner.actionTimeToComplete}, type; ${bladeburner.action.type}`);
+ }
+ if (!(bladeburner.action instanceof ActionIdentifier)) {
+ throw new Error("Bladeburner.action is not an ActionIdentifier Object");
+ }
+
+ // If the previous action went past its completion time, add to the next action
+ // This is not added inmediatly in case the automation changes the action
+ bladeburner.actionTimeCurrent += seconds + bladeburner.actionTimeOverflow;
+ bladeburner.actionTimeOverflow = 0;
+ if (bladeburner.actionTimeCurrent >= bladeburner.actionTimeToComplete) {
+ bladeburner.actionTimeOverflow = bladeburner.actionTimeCurrent - bladeburner.actionTimeToComplete;
+ return completeAction(bladeburner, player);
+ }
+}
+
+export function startAction(bladeburner: IBladeburner, player: IPlayer, actionId: IActionIdentifier): void {
+ if (actionId == null) return;
+ bladeburner.action = actionId;
+ bladeburner.actionTimeCurrent = 0;
+ switch (actionId.type) {
+ case ActionTypes["Idle"]:
+ bladeburner.actionTimeToComplete = 0;
+ break;
+ case ActionTypes["Contract"]:
+ try {
+ const action = getActionObject(bladeburner, actionId);
+ if (action == null) {
+ throw new Error("Failed to get Contract Object for: " + actionId.name);
+ }
+ if (action.count < 1) {return resetAction(bladeburner);}
+ bladeburner.actionTimeToComplete = action.getActionTime(bladeburner);
+ } catch(e) {
+ exceptionAlert(e);
+ }
+ break;
+ case ActionTypes["Operation"]: {
+ try {
+ const action = getActionObject(bladeburner, actionId);
+ if (action == null) {
+ throw new Error ("Failed to get Operation Object for: " + actionId.name);
+ }
+ if (action.count < 1) {return resetAction(bladeburner);}
+ if (actionId.name === "Raid" && bladeburner.getCurrentCity().commsEst === 0) {return resetAction(bladeburner);}
+ bladeburner.actionTimeToComplete = action.getActionTime(bladeburner);
+ } catch(e) {
+ exceptionAlert(e);
+ }
+ break;
+ }
+ case ActionTypes["BlackOp"]:
+ case ActionTypes["BlackOperation"]: {
+ try {
+ // Safety measure - don't repeat BlackOps that are already done
+ if (bladeburner.blackops[actionId.name] != null) {
+ resetAction(bladeburner);
+ bladeburner.log("Error: Tried to start a Black Operation that had already been completed");
+ break;
+ }
+
+ const action = getActionObject(bladeburner, actionId);
+ if (action == null) {
+ throw new Error("Failed to get BlackOperation object for: " + actionId.name);
+ }
+ bladeburner.actionTimeToComplete = action.getActionTime(bladeburner);
+ } catch(e) {
+ exceptionAlert(e);
+ }
+ break;
+ }
+ case ActionTypes["Recruitment"]:
+ bladeburner.actionTimeToComplete = getRecruitmentTime(bladeburner, player);
+ break;
+ case ActionTypes["Training"]:
+ case ActionTypes["FieldAnalysis"]:
+ case ActionTypes["Field Analysis"]:
+ bladeburner.actionTimeToComplete = 30;
+ break;
+ case ActionTypes["Diplomacy"]:
+ case ActionTypes["Hyperbolic Regeneration Chamber"]:
+ bladeburner.actionTimeToComplete = 60;
+ break;
+ default:
+ throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type);
+ break;
+ }
+}
\ No newline at end of file
diff --git a/src/Bladeburner/City.ts b/src/Bladeburner/City.ts
index 75f8aff24..361593c5f 100644
--- a/src/Bladeburner/City.ts
+++ b/src/Bladeburner/City.ts
@@ -4,14 +4,14 @@ import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { addOffset } from "../../utils/helpers/addOffset";
-export class ChangePopulationByCountParams {
- estChange = 0;
- estOffset = 0;
+interface IChangePopulationByCountParams {
+ estChange: number;
+ estOffset: number;
}
-export class ChangePopulationByPercentageParams {
- nonZero = false;
- changeEstEqually = false;
+interface IChangePopulationByPercentageParams {
+ nonZero: boolean;
+ changeEstEqually: boolean;
}
export class City {
@@ -113,7 +113,7 @@ export class City {
* estChange(int): How much the estimate should change by
* estOffset(int): Add offset to estimate (offset by percentage)
*/
- changePopulationByCount(n: number, params: ChangePopulationByCountParams=new ChangePopulationByCountParams()): void {
+ changePopulationByCount(n: number, params: IChangePopulationByCountParams = {estChange: 0, estOffset: 0}): void {
if (isNaN(n)) {throw new Error("NaN passed into City.changePopulationByCount()");}
this.pop += n;
if (params.estChange && !isNaN(params.estChange)) {this.popEst += params.estChange;}
@@ -129,7 +129,7 @@ export class City {
* changeEstEqually(bool) - Change the population estimate by an equal amount
* nonZero (bool) - Set to true to ensure that population always changes by at least 1
*/
- changePopulationByPercentage(p: number, params: ChangePopulationByPercentageParams=new ChangePopulationByPercentageParams()): number {
+ changePopulationByPercentage(p: number, params: IChangePopulationByPercentageParams={nonZero: false, changeEstEqually: false}): number {
if (isNaN(p)) {throw new Error("NaN passed into City.changePopulationByPercentage()");}
if (p === 0) {return 0;}
let change = Math.round(this.pop * (p/100));
diff --git a/src/Bladeburner/IBladeburner.ts b/src/Bladeburner/IBladeburner.ts
index 1e2f444a2..b8d65909c 100644
--- a/src/Bladeburner/IBladeburner.ts
+++ b/src/Bladeburner/IBladeburner.ts
@@ -11,6 +11,7 @@ export interface IBladeburner {
totalSkillPoints: number;
teamSize: number;
teamLost: number;
+ hpLost: number;
storedCycles: number;
randomEventCounter: number;
actionTimeToComplete: number;
diff --git a/src/Bladeburner/Skill.ts b/src/Bladeburner/Skill.ts
index deb84751e..fb590efd3 100644
--- a/src/Bladeburner/Skill.ts
+++ b/src/Bladeburner/Skill.ts
@@ -103,5 +103,28 @@ export class Skill {
calculateCost(currentLevel: number): number {
return Math.floor((this.baseCost + (currentLevel * this.costInc)) * BitNodeMultipliers.BladeburnerSkillCost);
}
+
+ getMultiplier(name: string): number {
+ if(name === "successChanceAll") return this.successChanceAll;
+ if(name === "successChanceStealth") return this.successChanceStealth;
+ if(name === "successChanceKill") return this.successChanceKill;
+ if(name === "successChanceContract") return this.successChanceContract;
+ if(name === "successChanceOperation") return this.successChanceOperation;
+ if(name === "successChanceEstimate") return this.successChanceEstimate;
+
+ if(name === "actionTime") return this.actionTime;
+
+ if(name === "effHack") return this.effHack;
+ if(name === "effStr") return this.effStr;
+ if(name === "effDef") return this.effDef;
+ if(name === "effDex") return this.effDex;
+ if(name === "effAgi") return this.effAgi;
+ if(name === "effCha") return this.effCha;
+
+ if(name === "stamina") return this.stamina;
+ if(name === "money") return this.money;
+ if(name === "expGain") return this.expGain;
+ return 1;
+ }
}
diff --git a/src/Bladeburner/ui/AllPages.tsx b/src/Bladeburner/ui/AllPages.tsx
index bfdd3466d..2ead8cf2f 100644
--- a/src/Bladeburner/ui/AllPages.tsx
+++ b/src/Bladeburner/ui/AllPages.tsx
@@ -6,9 +6,11 @@ import { BlackOpPage } from "./BlackOpPage";
import { SkillPage } from "./SkillPage";
import { stealthIcon, killIcon } from "../data/Icons";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function AllPages(props: IProps): React.ReactElement {
@@ -36,10 +38,10 @@ export function AllPages(props: IProps): React.ReactElement {
- {page === 'General' && }
- {page === 'Contracts' && }
- {page === 'Operations' && }
- {page === 'BlackOps' && }
+ {page === 'General' && }
+ {page === 'Contracts' && }
+ {page === 'Operations' && }
+ {page === 'BlackOps' && }
{page === 'Skills' && }
{stealthIcon}= This action requires stealth, {killIcon} = This action involves retirement
diff --git a/src/Bladeburner/ui/BlackOpElem.tsx b/src/Bladeburner/ui/BlackOpElem.tsx
index 5ac713359..c5b9c8f5a 100644
--- a/src/Bladeburner/ui/BlackOpElem.tsx
+++ b/src/Bladeburner/ui/BlackOpElem.tsx
@@ -9,9 +9,12 @@ import { stealthIcon, killIcon } from "../data/Icons";
import { createPopup } from "../../ui/React/createPopup";
import { TeamSizePopup } from "./TeamSizePopup";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
+import { startAction } from "../Bladeburner";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
action: any;
}
@@ -32,7 +35,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
function onStart() {
props.bladeburner.action.type = ActionTypes.BlackOperation;
props.bladeburner.action.name = props.action.name;
- props.bladeburner.startAction(props.bladeburner.action);
+ startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
diff --git a/src/Bladeburner/ui/BlackOpList.tsx b/src/Bladeburner/ui/BlackOpList.tsx
index 75cfafaf1..7f35db9a9 100644
--- a/src/Bladeburner/ui/BlackOpList.tsx
+++ b/src/Bladeburner/ui/BlackOpList.tsx
@@ -10,9 +10,11 @@ import { BlackOperations } from "../BlackOperations";
import { BlackOperation } from "../BlackOperation";
import { BlackOpElem } from "./BlackOpElem";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function BlackOpList(props: IProps): React.ReactElement {
@@ -34,7 +36,7 @@ export function BlackOpList(props: IProps): React.ReactElement {
return (<>
{blackops.map((blackop: BlackOperation) =>
-
+
,
)}
>);
diff --git a/src/Bladeburner/ui/BlackOpPage.tsx b/src/Bladeburner/ui/BlackOpPage.tsx
index 834b0b327..73ead8d09 100644
--- a/src/Bladeburner/ui/BlackOpPage.tsx
+++ b/src/Bladeburner/ui/BlackOpPage.tsx
@@ -1,9 +1,11 @@
import * as React from "react";
import { BlackOpList } from "./BlackOpList";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function BlackOpPage(props: IProps): React.ReactElement {
@@ -21,6 +23,6 @@ export function BlackOpPage(props: IProps): React.ReactElement {
Like normal operations, you may use a team for Black Ops. Failing
a black op will incur heavy HP and rank losses.
-
+
>);
}
\ No newline at end of file
diff --git a/src/Bladeburner/ui/Console.tsx b/src/Bladeburner/ui/Console.tsx
index 96bda3872..8cbee7181 100644
--- a/src/Bladeburner/ui/Console.tsx
+++ b/src/Bladeburner/ui/Console.tsx
@@ -1,6 +1,8 @@
import React, { useState, useRef, useEffect } from "react";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
+
interface ILineProps {
content: any;
}
@@ -13,6 +15,7 @@ function Line(props: ILineProps): React.ReactElement {
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function Console(props: IProps): React.ReactElement {
diff --git a/src/Bladeburner/ui/ContractElem.tsx b/src/Bladeburner/ui/ContractElem.tsx
index 568c62cfb..789317e11 100644
--- a/src/Bladeburner/ui/ContractElem.tsx
+++ b/src/Bladeburner/ui/ContractElem.tsx
@@ -8,9 +8,12 @@ import {
import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
+import { startAction } from "../Bladeburner";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
action: any;
}
@@ -26,19 +29,19 @@ export function ContractElem(props: IProps): React.ReactElement {
function onStart() {
props.bladeburner.action.type = ActionTypes.Contract;
props.bladeburner.action.name = props.action.name;
- props.bladeburner.startAction(props.bladeburner.action);
+ startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
function increaseLevel() {
++props.action.level;
- if (isActive) props.bladeburner.startAction(props.bladeburner.action);
+ if (isActive) startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
function decreaseLevel() {
--props.action.level;
- if (isActive) props.bladeburner.startAction(props.bladeburner.action);
+ if (isActive) startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
diff --git a/src/Bladeburner/ui/ContractList.tsx b/src/Bladeburner/ui/ContractList.tsx
index 8d3c7bace..3e5087eef 100644
--- a/src/Bladeburner/ui/ContractList.tsx
+++ b/src/Bladeburner/ui/ContractList.tsx
@@ -6,9 +6,11 @@ import {
import { ContractElem } from "./ContractElem";
import { Contract } from "../Contract";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function ContractList(props: IProps): React.ReactElement {
@@ -16,7 +18,7 @@ export function ContractList(props: IProps): React.ReactElement {
const contracts = props.bladeburner.contracts;
return (<>
{names.map((name: string) =>
-
+
,
)}
>);
diff --git a/src/Bladeburner/ui/ContractPage.tsx b/src/Bladeburner/ui/ContractPage.tsx
index b151f84c2..15848d8cf 100644
--- a/src/Bladeburner/ui/ContractPage.tsx
+++ b/src/Bladeburner/ui/ContractPage.tsx
@@ -1,9 +1,11 @@
import * as React from "react";
import { ContractList } from "./ContractList";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function ContractPage(props: IProps): React.ReactElement {
@@ -16,6 +18,6 @@ export function ContractPage(props: IProps): React.ReactElement {
You can unlock higher-level contracts by successfully completing them.
Higher-level contracts are more difficult, but grant more rank, experience, and money.
-
+
>);
}
\ No newline at end of file
diff --git a/src/Bladeburner/ui/GeneralActionElem.tsx b/src/Bladeburner/ui/GeneralActionElem.tsx
index 0cadbd7c2..bd312035f 100644
--- a/src/Bladeburner/ui/GeneralActionElem.tsx
+++ b/src/Bladeburner/ui/GeneralActionElem.tsx
@@ -8,9 +8,13 @@ import {
import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
+
+import { startAction } from "../Bladeburner";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
action: any;
}
@@ -22,7 +26,7 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
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);
+ startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
diff --git a/src/Bladeburner/ui/GeneralActionList.tsx b/src/Bladeburner/ui/GeneralActionList.tsx
index 9a2d4df08..be803bdae 100644
--- a/src/Bladeburner/ui/GeneralActionList.tsx
+++ b/src/Bladeburner/ui/GeneralActionList.tsx
@@ -7,9 +7,11 @@ import { GeneralActionElem } from "./GeneralActionElem";
import { Action } from "../Action";
import { GeneralActions } from "../GeneralActions";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function GeneralActionList(props: IProps): React.ReactElement {
@@ -21,7 +23,7 @@ export function GeneralActionList(props: IProps): React.ReactElement {
}
return (<>
{actions.map((action: Action) =>
-
+
,
)}
>);
diff --git a/src/Bladeburner/ui/GeneralActionPage.tsx b/src/Bladeburner/ui/GeneralActionPage.tsx
index bf87173f0..b2647a483 100644
--- a/src/Bladeburner/ui/GeneralActionPage.tsx
+++ b/src/Bladeburner/ui/GeneralActionPage.tsx
@@ -1,9 +1,11 @@
import * as React from "react";
import { GeneralActionList } from "./GeneralActionList";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function GeneralActionPage(props: IProps): React.ReactElement {
@@ -12,6 +14,6 @@ export function GeneralActionPage(props: IProps): React.ReactElement {
These are generic actions that will assist you in your Bladeburner
duties. They will not affect your Bladeburner rank in any way.
-
+
>);
}
\ No newline at end of file
diff --git a/src/Bladeburner/ui/OperationElem.tsx b/src/Bladeburner/ui/OperationElem.tsx
index 20e1f2892..f3d07eb62 100644
--- a/src/Bladeburner/ui/OperationElem.tsx
+++ b/src/Bladeburner/ui/OperationElem.tsx
@@ -10,9 +10,12 @@ import { BladeburnerConstants } from "../data/Constants";
import { createPopup } from "../../ui/React/createPopup";
import { TeamSizePopup } from "./TeamSizePopup";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
+import { startAction } from "../Bladeburner";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
action: any;
}
@@ -28,7 +31,7 @@ export function OperationElem(props: IProps): React.ReactElement {
function onStart() {
props.bladeburner.action.type = ActionTypes.Operation;
props.bladeburner.action.name = props.action.name;
- props.bladeburner.startAction(props.bladeburner.action);
+ startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
@@ -43,13 +46,13 @@ export function OperationElem(props: IProps): React.ReactElement {
function increaseLevel() {
++props.action.level;
- if (isActive) props.bladeburner.startAction(props.bladeburner.action);
+ if (isActive) startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
function decreaseLevel() {
--props.action.level;
- if (isActive) props.bladeburner.startAction(props.bladeburner.action);
+ if (isActive) startAction(props.bladeburner, props.player, props.bladeburner.action);
setRerender(old => !old);
}
diff --git a/src/Bladeburner/ui/OperationList.tsx b/src/Bladeburner/ui/OperationList.tsx
index 5d2387951..fa1e7e090 100644
--- a/src/Bladeburner/ui/OperationList.tsx
+++ b/src/Bladeburner/ui/OperationList.tsx
@@ -6,9 +6,11 @@ import {
import { OperationElem } from "./OperationElem";
import { Operation } from "../Operation";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function OperationList(props: IProps): React.ReactElement {
@@ -16,7 +18,7 @@ export function OperationList(props: IProps): React.ReactElement {
const operations = props.bladeburner.operations;
return (<>
{names.map((name: string) =>
-
+
,
)}
>);
diff --git a/src/Bladeburner/ui/OperationPage.tsx b/src/Bladeburner/ui/OperationPage.tsx
index 13233440d..f2560f6c0 100644
--- a/src/Bladeburner/ui/OperationPage.tsx
+++ b/src/Bladeburner/ui/OperationPage.tsx
@@ -1,9 +1,11 @@
import * as React from "react";
import { OperationList } from "./OperationList";
import { IBladeburner } from "../IBladeburner";
+import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
+ player: IPlayer;
}
export function OperationPage(props: IProps): React.ReactElement {
@@ -27,6 +29,6 @@ export function OperationPage(props: IProps): React.ReactElement {
You can unlock higher-level operations by successfully completing them.
Higher-level operations are more difficult, but grant more rank and experience.
-
+
>);
}
\ No newline at end of file
diff --git a/src/Bladeburner/ui/Root.tsx b/src/Bladeburner/ui/Root.tsx
index 0a1ea2881..7bb47d55e 100644
--- a/src/Bladeburner/ui/Root.tsx
+++ b/src/Bladeburner/ui/Root.tsx
@@ -19,10 +19,10 @@ export function Root(props: IProps): React.ReactElement {
-
+
);
}
\ No newline at end of file
diff --git a/src/RedPill.d.ts b/src/RedPill.d.ts
new file mode 100644
index 000000000..073ed8a6b
--- /dev/null
+++ b/src/RedPill.d.ts
@@ -0,0 +1 @@
+export declare function hackWorldDaemon(currentNodeNumber: number, flume: boolean = false, quick: boolean = false): void;
\ No newline at end of file