mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-22 14:12:27 +01:00
More converting blade to react.
This commit is contained in:
parent
58ada6d128
commit
cc8de58cff
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
@ -11,6 +11,7 @@ export interface IBladeburner {
|
||||
totalSkillPoints: number;
|
||||
teamSize: number;
|
||||
teamLost: number;
|
||||
hpLost: number;
|
||||
storedCycles: number;
|
||||
randomEventCounter: number;
|
||||
actionTimeToComplete: number;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
<Header name={'BlackOps'} />
|
||||
<Header name={'Skills'} />
|
||||
<div style={{display:"block", margin:"4px", padding:"4px"}}>
|
||||
{page === 'General' && <GeneralActionPage bladeburner={props.bladeburner} />}
|
||||
{page === 'Contracts' && <ContractPage bladeburner={props.bladeburner} />}
|
||||
{page === 'Operations' && <OperationPage bladeburner={props.bladeburner} />}
|
||||
{page === 'BlackOps' && <BlackOpPage bladeburner={props.bladeburner} />}
|
||||
{page === 'General' && <GeneralActionPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{page === 'Contracts' && <ContractPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{page === 'Operations' && <OperationPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{page === 'BlackOps' && <BlackOpPage bladeburner={props.bladeburner} player={props.player} />}
|
||||
{page === 'Skills' && <SkillPage bladeburner={props.bladeburner} />}
|
||||
</div>
|
||||
<span className="text">{stealthIcon}= This action requires stealth, {killIcon} = This action involves retirement</span>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) => <li key={blackop.name} className="bladeburner-action">
|
||||
<BlackOpElem bladeburner={props.bladeburner} action={blackop} />
|
||||
<BlackOpElem bladeburner={props.bladeburner} action={blackop} player={props.player} />
|
||||
</li>,
|
||||
)}
|
||||
</>);
|
||||
|
@ -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.
|
||||
</p>
|
||||
<BlackOpList bladeburner={props.bladeburner} />
|
||||
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
|
||||
</>);
|
||||
}
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) => <li key={name} className="bladeburner-action">
|
||||
<ContractElem bladeburner={props.bladeburner} action={contracts[name]} />
|
||||
<ContractElem bladeburner={props.bladeburner} action={contracts[name]} player={props.player} />
|
||||
</li>,
|
||||
)}
|
||||
</>);
|
||||
|
@ -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.
|
||||
</p>
|
||||
<ContractList bladeburner={props.bladeburner} />
|
||||
<ContractList bladeburner={props.bladeburner} player={props.player} />
|
||||
</>);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) => <li key={action.name} className="bladeburner-action">
|
||||
<GeneralActionElem bladeburner={props.bladeburner} action={action} />
|
||||
<GeneralActionElem bladeburner={props.bladeburner} action={action} player={props.player} />
|
||||
</li>,
|
||||
)}
|
||||
</>);
|
||||
|
@ -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.
|
||||
</p>
|
||||
<GeneralActionList bladeburner={props.bladeburner} />
|
||||
<GeneralActionList bladeburner={props.bladeburner} player={props.player} />
|
||||
</>);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) => <li key={name} className="bladeburner-action">
|
||||
<OperationElem bladeburner={props.bladeburner} action={operations[name]} />
|
||||
<OperationElem bladeburner={props.bladeburner} action={operations[name]} player={props.player} />
|
||||
</li>,
|
||||
)}
|
||||
</>);
|
||||
|
@ -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.
|
||||
</p>
|
||||
<OperationList bladeburner={props.bladeburner} />
|
||||
<OperationList bladeburner={props.bladeburner} player={props.player} />
|
||||
</>);
|
||||
}
|
@ -19,10 +19,10 @@ export function Root(props: IProps): React.ReactElement {
|
||||
<div style={{height: '100%', width:"30%", display:"inline-block", border:"1px solid white"}}>
|
||||
<Stats bladeburner={props.bladeburner} player={props.player} engine={props.engine} />
|
||||
</div>
|
||||
<Console bladeburner={props.bladeburner} />
|
||||
<Console bladeburner={props.bladeburner} player={props.player} />
|
||||
</div>
|
||||
<div style={{width:"70%", display:"block", border:"1px solid white", marginTop:"6px", padding: "6px", position:"relative"}}>
|
||||
<AllPages bladeburner={props.bladeburner} />
|
||||
<AllPages bladeburner={props.bladeburner} player={props.player} />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
1
src/RedPill.d.ts
vendored
Normal file
1
src/RedPill.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare function hackWorldDaemon(currentNodeNumber: number, flume: boolean = false, quick: boolean = false): void;
|
Loading…
Reference in New Issue
Block a user