mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-25 07:32:27 +01:00
Merge pull request #3680 from danielyxie/sleeve-blade
SLEEVE: Can now perform bladeburner actions
This commit is contained in:
commit
8d2041389e
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "bitburner",
|
"name": "bitburner",
|
||||||
"version": "1.6.4",
|
"version": "1.7.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "bitburner",
|
"name": "bitburner",
|
||||||
"version": "1.6.4",
|
"version": "1.7.0",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "SEE LICENSE IN license.txt",
|
"license": "SEE LICENSE IN license.txt",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -5,6 +5,7 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"
|
|||||||
import { BladeburnerConstants } from "./data/Constants";
|
import { BladeburnerConstants } from "./data/Constants";
|
||||||
import { IBladeburner } from "./IBladeburner";
|
import { IBladeburner } from "./IBladeburner";
|
||||||
import { IAction, ISuccessChanceParams } from "./IAction";
|
import { IAction, ISuccessChanceParams } from "./IAction";
|
||||||
|
import { IPerson } from "../PersonObjects/IPerson";
|
||||||
|
|
||||||
class StatsMultiplier {
|
class StatsMultiplier {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
@ -152,8 +153,8 @@ export class Action implements IAction {
|
|||||||
* Tests for success. Should be called when an action has completed
|
* Tests for success. Should be called when an action has completed
|
||||||
* @param inst {Bladeburner} - Bladeburner instance
|
* @param inst {Bladeburner} - Bladeburner instance
|
||||||
*/
|
*/
|
||||||
attempt(inst: IBladeburner): boolean {
|
attempt(inst: IBladeburner, person: IPerson): boolean {
|
||||||
return Math.random() < this.getSuccessChance(inst);
|
return Math.random() < this.getSuccessChance(inst, person);
|
||||||
}
|
}
|
||||||
|
|
||||||
// To be implemented by subtypes
|
// To be implemented by subtypes
|
||||||
@ -161,13 +162,13 @@ export class Action implements IAction {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getActionTime(inst: IBladeburner): number {
|
getActionTime(inst: IBladeburner, person: IPerson): number {
|
||||||
const difficulty = this.getDifficulty();
|
const difficulty = this.getDifficulty();
|
||||||
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
|
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
|
||||||
const skillFac = inst.skillMultipliers.actionTime; // Always < 1
|
const skillFac = inst.skillMultipliers.actionTime; // Always < 1
|
||||||
|
|
||||||
const effAgility = Player.agility * inst.skillMultipliers.effAgi;
|
const effAgility = person.agility * inst.skillMultipliers.effAgi;
|
||||||
const effDexterity = Player.dexterity * inst.skillMultipliers.effDex;
|
const effDexterity = person.dexterity * inst.skillMultipliers.effDex;
|
||||||
const statFac =
|
const statFac =
|
||||||
0.5 *
|
0.5 *
|
||||||
(Math.pow(effAgility, BladeburnerConstants.EffAgiExponentialFactor) +
|
(Math.pow(effAgility, BladeburnerConstants.EffAgiExponentialFactor) +
|
||||||
@ -211,12 +212,12 @@ export class Action implements IAction {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getEstSuccessChance(inst: IBladeburner): [number, number] {
|
getEstSuccessChance(inst: IBladeburner, person: IPerson): [number, number] {
|
||||||
function clamp(x: number): number {
|
function clamp(x: number): number {
|
||||||
return Math.max(0, Math.min(x, 1));
|
return Math.max(0, Math.min(x, 1));
|
||||||
}
|
}
|
||||||
const est = this.getSuccessChance(inst, { est: true });
|
const est = this.getSuccessChance(inst, person, { est: true });
|
||||||
const real = this.getSuccessChance(inst);
|
const real = this.getSuccessChance(inst, person);
|
||||||
const diff = Math.abs(real - est);
|
const diff = Math.abs(real - est);
|
||||||
let low = real - diff;
|
let low = real - diff;
|
||||||
let high = real + diff;
|
let high = real + diff;
|
||||||
@ -232,7 +233,7 @@ export class Action implements IAction {
|
|||||||
* @params - options:
|
* @params - options:
|
||||||
* est (bool): Get success chance estimate instead of real success chance
|
* est (bool): Get success chance estimate instead of real success chance
|
||||||
*/
|
*/
|
||||||
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams = { est: false }): number {
|
getSuccessChance(inst: IBladeburner, person: IPerson, params: ISuccessChanceParams = { est: false }): number {
|
||||||
if (inst == null) {
|
if (inst == null) {
|
||||||
throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");
|
throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");
|
||||||
}
|
}
|
||||||
@ -240,7 +241,7 @@ export class Action implements IAction {
|
|||||||
let competence = 0;
|
let competence = 0;
|
||||||
for (const stat of Object.keys(this.weights)) {
|
for (const stat of Object.keys(this.weights)) {
|
||||||
if (this.weights.hasOwnProperty(stat)) {
|
if (this.weights.hasOwnProperty(stat)) {
|
||||||
const playerStatLvl = Player.queryStatFromString(stat);
|
const playerStatLvl = person.queryStatFromString(stat);
|
||||||
const key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
|
const key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
|
||||||
let effMultiplier = inst.skillMultipliers[key];
|
let effMultiplier = inst.skillMultipliers[key];
|
||||||
if (effMultiplier == null) {
|
if (effMultiplier == null) {
|
||||||
|
@ -15,6 +15,8 @@ import { Skill } from "./Skill";
|
|||||||
import { City } from "./City";
|
import { City } from "./City";
|
||||||
import { IAction } from "./IAction";
|
import { IAction } from "./IAction";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { createTaskTracker, ITaskTracker } from "../PersonObjects/ITaskTracker";
|
||||||
|
import { IPerson } from "../PersonObjects/IPerson";
|
||||||
import { IRouter, Page } from "../ui/Router";
|
import { IRouter, Page } from "../ui/Router";
|
||||||
import { ConsoleHelpText } from "./data/Help";
|
import { ConsoleHelpText } from "./data/Help";
|
||||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
@ -52,6 +54,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
totalSkillPoints = 0;
|
totalSkillPoints = 0;
|
||||||
|
|
||||||
teamSize = 0;
|
teamSize = 0;
|
||||||
|
sleeveSize = 0;
|
||||||
teamLost = 0;
|
teamLost = 0;
|
||||||
hpLost = 0;
|
hpLost = 0;
|
||||||
|
|
||||||
@ -158,7 +161,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
return { isAvailable: true, action };
|
return { isAvailable: true, action };
|
||||||
}
|
}
|
||||||
|
|
||||||
startAction(player: IPlayer, actionId: IActionIdentifier): void {
|
startAction(person: IPerson, actionId: IActionIdentifier): void {
|
||||||
if (actionId == null) return;
|
if (actionId == null) return;
|
||||||
this.action = actionId;
|
this.action = actionId;
|
||||||
this.actionTimeCurrent = 0;
|
this.actionTimeCurrent = 0;
|
||||||
@ -175,7 +178,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
if (action.count < 1) {
|
if (action.count < 1) {
|
||||||
return this.resetAction();
|
return this.resetAction();
|
||||||
}
|
}
|
||||||
this.actionTimeToComplete = action.getActionTime(this);
|
this.actionTimeToComplete = action.getActionTime(this, person);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
@ -192,7 +195,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
if (actionId.name === "Raid" && this.getCurrentCity().comms === 0) {
|
if (actionId.name === "Raid" && this.getCurrentCity().comms === 0) {
|
||||||
return this.resetAction();
|
return this.resetAction();
|
||||||
}
|
}
|
||||||
this.actionTimeToComplete = action.getActionTime(this);
|
this.actionTimeToComplete = action.getActionTime(this, person);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
@ -210,14 +213,14 @@ export class Bladeburner implements IBladeburner {
|
|||||||
if (testBlackOp.action === undefined) {
|
if (testBlackOp.action === undefined) {
|
||||||
throw new Error("action should not be null");
|
throw new Error("action should not be null");
|
||||||
}
|
}
|
||||||
this.actionTimeToComplete = testBlackOp.action.getActionTime(this);
|
this.actionTimeToComplete = testBlackOp.action.getActionTime(this, person);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ActionTypes["Recruitment"]:
|
case ActionTypes["Recruitment"]:
|
||||||
this.actionTimeToComplete = this.getRecruitmentTime(player);
|
this.actionTimeToComplete = this.getRecruitmentTime(person);
|
||||||
break;
|
break;
|
||||||
case ActionTypes["Training"]:
|
case ActionTypes["Training"]:
|
||||||
case ActionTypes["FieldAnalysis"]:
|
case ActionTypes["FieldAnalysis"]:
|
||||||
@ -996,11 +999,11 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process stat gains from Contracts, Operations, and Black Operations
|
* Return stat to be gained from Contracts, Operations, and Black Operations
|
||||||
* @param action(Action obj) - Derived action class
|
* @param action(Action obj) - Derived action class
|
||||||
* @param success(bool) - Whether action was successful
|
* @param success(bool) - Whether action was successful
|
||||||
*/
|
*/
|
||||||
gainActionStats(player: IPlayer, action: IAction, success: boolean): void {
|
getActionStats(action: IAction, success: boolean): ITaskTracker {
|
||||||
const difficulty = action.getDifficulty();
|
const difficulty = action.getDifficulty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1017,34 +1020,48 @@ export class Bladeburner implements IBladeburner {
|
|||||||
const unweightedGain = time * BladeburnerConstants.BaseStatGain * successMult * difficultyMult;
|
const unweightedGain = time * BladeburnerConstants.BaseStatGain * successMult * difficultyMult;
|
||||||
const unweightedIntGain = time * BladeburnerConstants.BaseIntGain * successMult * difficultyMult;
|
const unweightedIntGain = time * BladeburnerConstants.BaseIntGain * successMult * difficultyMult;
|
||||||
const skillMult = this.skillMultipliers.expGain;
|
const skillMult = this.skillMultipliers.expGain;
|
||||||
player.gainHackingExp(unweightedGain * action.weights.hack * player.hacking_exp_mult * skillMult);
|
|
||||||
player.gainStrengthExp(unweightedGain * action.weights.str * player.strength_exp_mult * skillMult);
|
return {
|
||||||
player.gainDefenseExp(unweightedGain * action.weights.def * player.defense_exp_mult * skillMult);
|
hack: unweightedGain * action.weights.hack * skillMult,
|
||||||
player.gainDexterityExp(unweightedGain * action.weights.dex * player.dexterity_exp_mult * skillMult);
|
str: unweightedGain * action.weights.str * skillMult,
|
||||||
player.gainAgilityExp(unweightedGain * action.weights.agi * player.agility_exp_mult * skillMult);
|
def: unweightedGain * action.weights.def * skillMult,
|
||||||
player.gainCharismaExp(unweightedGain * action.weights.cha * player.charisma_exp_mult * skillMult);
|
dex: unweightedGain * action.weights.dex * skillMult,
|
||||||
player.gainIntelligenceExp(unweightedIntGain * action.weights.int * skillMult);
|
agi: unweightedGain * action.weights.agi * skillMult,
|
||||||
|
cha: unweightedGain * action.weights.cha * skillMult,
|
||||||
|
int: unweightedIntGain * action.weights.int * skillMult,
|
||||||
|
money: 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getDiplomacyEffectiveness(player: IPlayer): number {
|
getDiplomacyEffectiveness(person: IPerson): number {
|
||||||
// Returns a decimal by which the city's chaos level should be multiplied (e.g. 0.98)
|
// Returns a decimal by which the city's chaos level should be multiplied (e.g. 0.98)
|
||||||
const CharismaLinearFactor = 1e3;
|
const CharismaLinearFactor = 1e3;
|
||||||
const CharismaExponentialFactor = 0.045;
|
const CharismaExponentialFactor = 0.045;
|
||||||
|
|
||||||
const charismaEff = Math.pow(player.charisma, CharismaExponentialFactor) + player.charisma / CharismaLinearFactor;
|
const charismaEff = Math.pow(person.charisma, CharismaExponentialFactor) + person.charisma / CharismaLinearFactor;
|
||||||
return (100 - charismaEff) / 100;
|
return (100 - charismaEff) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRecruitmentSuccessChance(player: IPlayer): number {
|
getRecruitmentSuccessChance(person: IPerson): number {
|
||||||
return Math.pow(player.charisma, 0.45) / (this.teamSize + 1);
|
return Math.pow(person.charisma, 0.45) / (this.teamSize - this.sleeveSize + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRecruitmentTime(player: IPlayer): number {
|
getRecruitmentTime(person: IPerson): number {
|
||||||
const effCharisma = player.charisma * this.skillMultipliers.effCha;
|
const effCharisma = person.charisma * this.skillMultipliers.effCha;
|
||||||
const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
|
const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
|
||||||
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor));
|
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sleeveSupport(joining: boolean): void {
|
||||||
|
if (joining) {
|
||||||
|
this.sleeveSize += 1;
|
||||||
|
this.teamSize += 1;
|
||||||
|
} else {
|
||||||
|
this.sleeveSize -= 1;
|
||||||
|
this.teamSize -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resetSkillMultipliers(): void {
|
resetSkillMultipliers(): void {
|
||||||
this.skillMultipliers = {
|
this.skillMultipliers = {
|
||||||
successChanceAll: 1,
|
successChanceAll: 1,
|
||||||
@ -1096,7 +1113,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completeOperation(success: boolean): void {
|
completeOperation(success: boolean, player: IPlayer): void {
|
||||||
if (this.action.type !== ActionTypes.Operation) {
|
if (this.action.type !== ActionTypes.Operation) {
|
||||||
throw new Error("completeOperation() called even though current action is not an Operation");
|
throw new Error("completeOperation() called even though current action is not an Operation");
|
||||||
}
|
}
|
||||||
@ -1116,6 +1133,15 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
const losses = getRandomInt(0, max);
|
const losses = getRandomInt(0, max);
|
||||||
this.teamSize -= losses;
|
this.teamSize -= losses;
|
||||||
|
if (this.teamSize < this.sleeveSize) {
|
||||||
|
const sup = player.sleeves.filter((x) => x.bbAction == "Support main sleeve");
|
||||||
|
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
||||||
|
const r = Math.floor(Math.random() * sup.length);
|
||||||
|
sup[r].takeDamage(sup[r].max_hp);
|
||||||
|
sup.splice(r, 1);
|
||||||
|
}
|
||||||
|
this.teamSize += this.sleeveSize;
|
||||||
|
}
|
||||||
this.teamLost += losses;
|
this.teamLost += losses;
|
||||||
if (this.logging.ops && losses > 0) {
|
if (this.logging.ops && losses > 0) {
|
||||||
this.log("Lost " + formatNumber(losses, 0) + " team members during this " + action.name);
|
this.log("Lost " + formatNumber(losses, 0) + " team members during this " + action.name);
|
||||||
@ -1213,13 +1239,13 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completeContract(success: boolean): void {
|
completeContract(success: boolean, actionIdent: IActionIdentifier): void {
|
||||||
if (this.action.type !== ActionTypes.Contract) {
|
if (actionIdent.type !== ActionTypes.Contract) {
|
||||||
throw new Error("completeContract() called even though current action is not a Contract");
|
throw new Error("completeContract() called even though current action is not a Contract");
|
||||||
}
|
}
|
||||||
const city = this.getCurrentCity();
|
const city = this.getCurrentCity();
|
||||||
if (success) {
|
if (success) {
|
||||||
switch (this.action.name) {
|
switch (actionIdent.name) {
|
||||||
case "Tracking":
|
case "Tracking":
|
||||||
// Increase estimate accuracy by a relatively small amount
|
// Increase estimate accuracy by a relatively small amount
|
||||||
city.improvePopulationEstimateByCount(getRandomInt(100, 1e3));
|
city.improvePopulationEstimateByCount(getRandomInt(100, 1e3));
|
||||||
@ -1233,20 +1259,21 @@ export class Bladeburner implements IBladeburner {
|
|||||||
city.changeChaosByCount(0.04);
|
city.changeChaosByCount(0.04);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Invalid Action name in completeContract: " + this.action.name);
|
throw new Error("Invalid Action name in completeContract: " + actionIdent.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completeAction(router: IRouter, player: IPlayer): void {
|
completeAction(player: IPlayer, person: IPerson, actionIdent: IActionIdentifier, isPlayer = true): ITaskTracker {
|
||||||
switch (this.action.type) {
|
let retValue = createTaskTracker();
|
||||||
|
switch (actionIdent.type) {
|
||||||
case ActionTypes["Contract"]:
|
case ActionTypes["Contract"]:
|
||||||
case ActionTypes["Operation"]: {
|
case ActionTypes["Operation"]: {
|
||||||
try {
|
try {
|
||||||
const isOperation = this.action.type === ActionTypes["Operation"];
|
const isOperation = actionIdent.type === ActionTypes["Operation"];
|
||||||
const action = this.getActionObject(this.action);
|
const action = this.getActionObject(actionIdent);
|
||||||
if (action == null) {
|
if (action == null) {
|
||||||
throw new Error("Failed to get Contract/Operation Object for: " + this.action.name);
|
throw new Error("Failed to get Contract/Operation Object for: " + actionIdent.name);
|
||||||
}
|
}
|
||||||
const difficulty = action.getDifficulty();
|
const difficulty = action.getDifficulty();
|
||||||
const difficultyMultiplier =
|
const difficultyMultiplier =
|
||||||
@ -1254,15 +1281,17 @@ export class Bladeburner implements IBladeburner {
|
|||||||
difficulty / BladeburnerConstants.DiffMultLinearFactor;
|
difficulty / BladeburnerConstants.DiffMultLinearFactor;
|
||||||
const rewardMultiplier = Math.pow(action.rewardFac, action.level - 1);
|
const rewardMultiplier = Math.pow(action.rewardFac, action.level - 1);
|
||||||
|
|
||||||
|
if (isPlayer) {
|
||||||
// Stamina loss is based on difficulty
|
// Stamina loss is based on difficulty
|
||||||
this.stamina -= BladeburnerConstants.BaseStaminaLoss * difficultyMultiplier;
|
this.stamina -= BladeburnerConstants.BaseStaminaLoss * difficultyMultiplier;
|
||||||
if (this.stamina < 0) {
|
if (this.stamina < 0) {
|
||||||
this.stamina = 0;
|
this.stamina = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process Contract/Operation success/failure
|
// Process Contract/Operation success/failure
|
||||||
if (action.attempt(this)) {
|
if (action.attempt(this, person)) {
|
||||||
this.gainActionStats(player, action, true);
|
retValue = this.getActionStats(action, true);
|
||||||
++action.successes;
|
++action.successes;
|
||||||
--action.count;
|
--action.count;
|
||||||
|
|
||||||
@ -1270,7 +1299,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
let moneyGain = 0;
|
let moneyGain = 0;
|
||||||
if (!isOperation) {
|
if (!isOperation) {
|
||||||
moneyGain = BladeburnerConstants.ContractBaseMoneyGain * rewardMultiplier * this.skillMultipliers.money;
|
moneyGain = BladeburnerConstants.ContractBaseMoneyGain * rewardMultiplier * this.skillMultipliers.money;
|
||||||
player.gainMoney(moneyGain, "bladeburner");
|
retValue.money = moneyGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOperation) {
|
if (isOperation) {
|
||||||
@ -1280,11 +1309,18 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
if (action.rankGain) {
|
if (action.rankGain) {
|
||||||
const gain = addOffset(action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank, 10);
|
const gain = addOffset(action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank, 10);
|
||||||
this.changeRank(player, gain);
|
this.changeRank(person, gain);
|
||||||
if (isOperation && this.logging.ops) {
|
if (isOperation && this.logging.ops) {
|
||||||
this.log(action.name + " successfully completed! Gained " + formatNumber(gain, 3) + " rank");
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
|
action.name +
|
||||||
|
" successfully completed! Gained " +
|
||||||
|
formatNumber(gain, 3) +
|
||||||
|
" rank",
|
||||||
|
);
|
||||||
} else if (!isOperation && this.logging.contracts) {
|
} else if (!isOperation && this.logging.contracts) {
|
||||||
this.log(
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
action.name +
|
action.name +
|
||||||
" contract successfully completed! Gained " +
|
" contract successfully completed! Gained " +
|
||||||
formatNumber(gain, 3) +
|
formatNumber(gain, 3) +
|
||||||
@ -1293,22 +1329,22 @@ export class Bladeburner implements IBladeburner {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isOperation ? this.completeOperation(true) : this.completeContract(true);
|
isOperation ? this.completeOperation(true, player) : this.completeContract(true, actionIdent);
|
||||||
} else {
|
} else {
|
||||||
this.gainActionStats(player, action, false);
|
retValue = this.getActionStats(action, false);
|
||||||
++action.failures;
|
++action.failures;
|
||||||
let loss = 0,
|
let loss = 0,
|
||||||
damage = 0;
|
damage = 0;
|
||||||
if (action.rankLoss) {
|
if (action.rankLoss) {
|
||||||
loss = addOffset(action.rankLoss * rewardMultiplier, 10);
|
loss = addOffset(action.rankLoss * rewardMultiplier, 10);
|
||||||
this.changeRank(player, -1 * loss);
|
this.changeRank(person, -1 * loss);
|
||||||
}
|
}
|
||||||
if (action.hpLoss) {
|
if (action.hpLoss) {
|
||||||
damage = action.hpLoss * difficultyMultiplier;
|
damage = action.hpLoss * difficultyMultiplier;
|
||||||
damage = Math.ceil(addOffset(damage, 10));
|
damage = Math.ceil(addOffset(damage, 10));
|
||||||
this.hpLost += damage;
|
this.hpLost += damage;
|
||||||
const cost = calculateHospitalizationCost(player, damage);
|
const cost = calculateHospitalizationCost(player, damage);
|
||||||
if (player.takeDamage(damage)) {
|
if (person.takeDamage(damage)) {
|
||||||
++this.numHosp;
|
++this.numHosp;
|
||||||
this.moneyLost += cost;
|
this.moneyLost += cost;
|
||||||
}
|
}
|
||||||
@ -1321,16 +1357,15 @@ export class Bladeburner implements IBladeburner {
|
|||||||
logLossText += "Took " + formatNumber(damage, 0) + " damage.";
|
logLossText += "Took " + formatNumber(damage, 0) + " damage.";
|
||||||
}
|
}
|
||||||
if (isOperation && this.logging.ops) {
|
if (isOperation && this.logging.ops) {
|
||||||
this.log(action.name + " failed! " + logLossText);
|
this.log(`${person.whoAmI()}: ` + action.name + " failed! " + logLossText);
|
||||||
} else if (!isOperation && this.logging.contracts) {
|
} else if (!isOperation && this.logging.contracts) {
|
||||||
this.log(action.name + " contract failed! " + logLossText);
|
this.log(`${person.whoAmI()}: ` + action.name + " contract failed! " + logLossText);
|
||||||
}
|
}
|
||||||
isOperation ? this.completeOperation(false) : this.completeContract(false);
|
isOperation ? this.completeOperation(false, player) : this.completeContract(false, actionIdent);
|
||||||
}
|
}
|
||||||
if (action.autoLevel) {
|
if (action.autoLevel) {
|
||||||
action.level = action.maxLevel;
|
action.level = action.maxLevel;
|
||||||
} // Autolevel
|
} // Autolevel
|
||||||
this.startAction(player, this.action); // Repeat action
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
@ -1339,9 +1374,9 @@ export class Bladeburner implements IBladeburner {
|
|||||||
case ActionTypes["BlackOp"]:
|
case ActionTypes["BlackOp"]:
|
||||||
case ActionTypes["BlackOperation"]: {
|
case ActionTypes["BlackOperation"]: {
|
||||||
try {
|
try {
|
||||||
const action = this.getActionObject(this.action);
|
const action = this.getActionObject(actionIdent);
|
||||||
if (action == null || !(action instanceof BlackOperation)) {
|
if (action == null || !(action instanceof BlackOperation)) {
|
||||||
throw new Error("Failed to get BlackOperation Object for: " + this.action.name);
|
throw new Error("Failed to get BlackOperation Object for: " + actionIdent.name);
|
||||||
}
|
}
|
||||||
const difficulty = action.getDifficulty();
|
const difficulty = action.getDifficulty();
|
||||||
const difficultyMultiplier =
|
const difficultyMultiplier =
|
||||||
@ -1358,39 +1393,35 @@ export class Bladeburner implements IBladeburner {
|
|||||||
const teamCount = action.teamCount;
|
const teamCount = action.teamCount;
|
||||||
let teamLossMax;
|
let teamLossMax;
|
||||||
|
|
||||||
if (action.attempt(this)) {
|
if (action.attempt(this, person)) {
|
||||||
this.gainActionStats(player, action, true);
|
retValue = this.getActionStats(action, true);
|
||||||
action.count = 0;
|
action.count = 0;
|
||||||
this.blackops[action.name] = true;
|
this.blackops[action.name] = true;
|
||||||
let rankGain = 0;
|
let rankGain = 0;
|
||||||
if (action.rankGain) {
|
if (action.rankGain) {
|
||||||
rankGain = addOffset(action.rankGain * BitNodeMultipliers.BladeburnerRank, 10);
|
rankGain = addOffset(action.rankGain * BitNodeMultipliers.BladeburnerRank, 10);
|
||||||
this.changeRank(player, rankGain);
|
this.changeRank(person, rankGain);
|
||||||
}
|
}
|
||||||
teamLossMax = Math.ceil(teamCount / 2);
|
teamLossMax = Math.ceil(teamCount / 2);
|
||||||
|
|
||||||
// Operation Daedalus
|
|
||||||
if (action.name === BlackOperationNames.OperationDaedalus) {
|
|
||||||
this.resetAction();
|
|
||||||
return router.toBitVerse(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.logging.blackops) {
|
if (this.logging.blackops) {
|
||||||
this.log(action.name + " successful! Gained " + formatNumber(rankGain, 1) + " rank");
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` + action.name + " successful! Gained " + formatNumber(rankGain, 1) + " rank",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.gainActionStats(player, action, false);
|
retValue = this.getActionStats(action, false);
|
||||||
let rankLoss = 0;
|
let rankLoss = 0;
|
||||||
let damage = 0;
|
let damage = 0;
|
||||||
if (action.rankLoss) {
|
if (action.rankLoss) {
|
||||||
rankLoss = addOffset(action.rankLoss, 10);
|
rankLoss = addOffset(action.rankLoss, 10);
|
||||||
this.changeRank(player, -1 * rankLoss);
|
this.changeRank(person, -1 * rankLoss);
|
||||||
}
|
}
|
||||||
if (action.hpLoss) {
|
if (action.hpLoss) {
|
||||||
damage = action.hpLoss * difficultyMultiplier;
|
damage = action.hpLoss * difficultyMultiplier;
|
||||||
damage = Math.ceil(addOffset(damage, 10));
|
damage = Math.ceil(addOffset(damage, 10));
|
||||||
const cost = calculateHospitalizationCost(player, damage);
|
const cost = calculateHospitalizationCost(player, damage);
|
||||||
if (player.takeDamage(damage)) {
|
if (person.takeDamage(damage)) {
|
||||||
++this.numHosp;
|
++this.numHosp;
|
||||||
this.moneyLost += cost;
|
this.moneyLost += cost;
|
||||||
}
|
}
|
||||||
@ -1399,6 +1430,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
|
|
||||||
if (this.logging.blackops) {
|
if (this.logging.blackops) {
|
||||||
this.log(
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
action.name +
|
action.name +
|
||||||
" failed! Lost " +
|
" failed! Lost " +
|
||||||
formatNumber(rankLoss, 1) +
|
formatNumber(rankLoss, 1) +
|
||||||
@ -1415,9 +1447,18 @@ export class Bladeburner implements IBladeburner {
|
|||||||
if (teamCount >= 1) {
|
if (teamCount >= 1) {
|
||||||
const losses = getRandomInt(1, teamLossMax);
|
const losses = getRandomInt(1, teamLossMax);
|
||||||
this.teamSize -= losses;
|
this.teamSize -= losses;
|
||||||
|
if (this.teamSize < this.sleeveSize) {
|
||||||
|
const sup = player.sleeves.filter((x) => x.bbAction == "Support main sleeve");
|
||||||
|
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
|
||||||
|
const r = Math.floor(Math.random() * sup.length);
|
||||||
|
sup[r].takeDamage(sup[r].max_hp);
|
||||||
|
sup.splice(r, 1);
|
||||||
|
}
|
||||||
|
this.teamSize += this.sleeveSize;
|
||||||
|
}
|
||||||
this.teamLost += losses;
|
this.teamLost += losses;
|
||||||
if (this.logging.blackops) {
|
if (this.logging.blackops) {
|
||||||
this.log("You lost " + formatNumber(losses, 0) + " team members during " + action.name);
|
this.log(`${person.whoAmI()}: You lost ${formatNumber(losses, 0)} team members during ${action.name}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@ -1427,18 +1468,19 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
case ActionTypes["Training"]: {
|
case ActionTypes["Training"]: {
|
||||||
this.stamina -= 0.5 * BladeburnerConstants.BaseStaminaLoss;
|
this.stamina -= 0.5 * BladeburnerConstants.BaseStaminaLoss;
|
||||||
const strExpGain = 30 * player.strength_exp_mult,
|
const strExpGain = 30 * person.strength_exp_mult,
|
||||||
defExpGain = 30 * player.defense_exp_mult,
|
defExpGain = 30 * person.defense_exp_mult,
|
||||||
dexExpGain = 30 * player.dexterity_exp_mult,
|
dexExpGain = 30 * person.dexterity_exp_mult,
|
||||||
agiExpGain = 30 * player.agility_exp_mult,
|
agiExpGain = 30 * person.agility_exp_mult,
|
||||||
staminaGain = 0.04 * this.skillMultipliers.stamina;
|
staminaGain = 0.04 * this.skillMultipliers.stamina;
|
||||||
player.gainStrengthExp(strExpGain);
|
retValue.str = strExpGain;
|
||||||
player.gainDefenseExp(defExpGain);
|
retValue.def = defExpGain;
|
||||||
player.gainDexterityExp(dexExpGain);
|
retValue.dex = dexExpGain;
|
||||||
player.gainAgilityExp(agiExpGain);
|
retValue.agi = agiExpGain;
|
||||||
this.staminaBonus += staminaGain;
|
this.staminaBonus += staminaGain;
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log(
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
"Training completed. Gained: " +
|
"Training completed. Gained: " +
|
||||||
formatNumber(strExpGain, 1) +
|
formatNumber(strExpGain, 1) +
|
||||||
" str exp, " +
|
" str exp, " +
|
||||||
@ -1452,80 +1494,89 @@ export class Bladeburner implements IBladeburner {
|
|||||||
" max stamina",
|
" max stamina",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.startAction(player, this.action); // Repeat action
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ActionTypes["FieldAnalysis"]:
|
case ActionTypes["FieldAnalysis"]:
|
||||||
case ActionTypes["Field Analysis"]: {
|
case ActionTypes["Field Analysis"]: {
|
||||||
// Does not use stamina. Effectiveness depends on hacking, int, and cha
|
// Does not use stamina. Effectiveness depends on hacking, int, and cha
|
||||||
let eff =
|
let eff =
|
||||||
0.04 * Math.pow(player.hacking, 0.3) +
|
0.04 * Math.pow(person.hacking, 0.3) +
|
||||||
0.04 * Math.pow(player.intelligence, 0.9) +
|
0.04 * Math.pow(person.intelligence, 0.9) +
|
||||||
0.02 * Math.pow(player.charisma, 0.3);
|
0.02 * Math.pow(person.charisma, 0.3);
|
||||||
eff *= player.bladeburner_analysis_mult;
|
eff *= person.bladeburner_analysis_mult;
|
||||||
if (isNaN(eff) || eff < 0) {
|
if (isNaN(eff) || eff < 0) {
|
||||||
throw new Error("Field Analysis Effectiveness calculated to be NaN or negative");
|
throw new Error("Field Analysis Effectiveness calculated to be NaN or negative");
|
||||||
}
|
}
|
||||||
const hackingExpGain = 20 * player.hacking_exp_mult;
|
const hackingExpGain = 20 * person.hacking_exp_mult;
|
||||||
const charismaExpGain = 20 * player.charisma_exp_mult;
|
const charismaExpGain = 20 * person.charisma_exp_mult;
|
||||||
const rankGain = 0.1 * BitNodeMultipliers.BladeburnerRank;
|
const rankGain = 0.1 * BitNodeMultipliers.BladeburnerRank;
|
||||||
player.gainHackingExp(hackingExpGain);
|
retValue.hack = hackingExpGain;
|
||||||
player.gainIntelligenceExp(BladeburnerConstants.BaseIntGain);
|
retValue.cha = charismaExpGain;
|
||||||
player.gainCharismaExp(charismaExpGain);
|
retValue.int = BladeburnerConstants.BaseIntGain;
|
||||||
this.changeRank(player, rankGain);
|
this.changeRank(person, rankGain);
|
||||||
this.getCurrentCity().improvePopulationEstimateByPercentage(eff * this.skillMultipliers.successChanceEstimate);
|
this.getCurrentCity().improvePopulationEstimateByPercentage(eff * this.skillMultipliers.successChanceEstimate);
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log(
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
`Field analysis completed. Gained ${formatNumber(rankGain, 2)} rank, ` +
|
`Field analysis completed. Gained ${formatNumber(rankGain, 2)} rank, ` +
|
||||||
`${formatNumber(hackingExpGain, 1)} hacking exp, and ` +
|
`${formatNumber(hackingExpGain, 1)} hacking exp, and ` +
|
||||||
`${formatNumber(charismaExpGain, 1)} charisma exp`,
|
`${formatNumber(charismaExpGain, 1)} charisma exp`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.startAction(player, this.action); // Repeat action
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ActionTypes["Recruitment"]: {
|
case ActionTypes["Recruitment"]: {
|
||||||
const successChance = this.getRecruitmentSuccessChance(player);
|
const successChance = this.getRecruitmentSuccessChance(person);
|
||||||
|
const recruitTime = this.getRecruitmentTime(person) * 1000;
|
||||||
if (Math.random() < successChance) {
|
if (Math.random() < successChance) {
|
||||||
const expGain = 2 * BladeburnerConstants.BaseStatGain * this.actionTimeToComplete;
|
const expGain = 2 * BladeburnerConstants.BaseStatGain * recruitTime;
|
||||||
player.gainCharismaExp(expGain);
|
retValue.cha = expGain;
|
||||||
++this.teamSize;
|
++this.teamSize;
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log("Successfully recruited a team member! Gained " + formatNumber(expGain, 1) + " charisma exp");
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
|
"Successfully recruited a team member! Gained " +
|
||||||
|
formatNumber(expGain, 1) +
|
||||||
|
" charisma exp",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const expGain = BladeburnerConstants.BaseStatGain * this.actionTimeToComplete;
|
const expGain = BladeburnerConstants.BaseStatGain * recruitTime;
|
||||||
player.gainCharismaExp(expGain);
|
retValue.cha = expGain;
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log("Failed to recruit a team member. Gained " + formatNumber(expGain, 1) + " charisma exp");
|
this.log(
|
||||||
|
`${person.whoAmI()}: ` +
|
||||||
|
"Failed to recruit a team member. Gained " +
|
||||||
|
formatNumber(expGain, 1) +
|
||||||
|
" charisma exp",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.startAction(player, this.action); // Repeat action
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ActionTypes["Diplomacy"]: {
|
case ActionTypes["Diplomacy"]: {
|
||||||
const eff = this.getDiplomacyEffectiveness(player);
|
const eff = this.getDiplomacyEffectiveness(person);
|
||||||
this.getCurrentCity().chaos *= eff;
|
this.getCurrentCity().chaos *= eff;
|
||||||
if (this.getCurrentCity().chaos < 0) {
|
if (this.getCurrentCity().chaos < 0) {
|
||||||
this.getCurrentCity().chaos = 0;
|
this.getCurrentCity().chaos = 0;
|
||||||
}
|
}
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log(
|
this.log(
|
||||||
`Diplomacy completed. Chaos levels in the current city fell by ${numeralWrapper.formatPercentage(1 - eff)}`,
|
`${person.whoAmI()}: Diplomacy completed. Chaos levels in the current city fell by ${numeralWrapper.formatPercentage(
|
||||||
|
1 - eff,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.startAction(player, this.action); // Repeat Action
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ActionTypes["Hyperbolic Regeneration Chamber"]: {
|
case ActionTypes["Hyperbolic Regeneration Chamber"]: {
|
||||||
player.regenerateHp(BladeburnerConstants.HrcHpGain);
|
person.regenerateHp(BladeburnerConstants.HrcHpGain);
|
||||||
|
|
||||||
const staminaGain = this.maxStamina * (BladeburnerConstants.HrcStaminaGain / 100);
|
const staminaGain = this.maxStamina * (BladeburnerConstants.HrcStaminaGain / 100);
|
||||||
this.stamina = Math.min(this.maxStamina, this.stamina + staminaGain);
|
this.stamina = Math.min(this.maxStamina, this.stamina + staminaGain);
|
||||||
this.startAction(player, this.action);
|
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log(
|
this.log(
|
||||||
`Rested in Hyperbolic Regeneration Chamber. Restored ${
|
`${person.whoAmI()}: Rested in Hyperbolic Regeneration Chamber. Restored ${
|
||||||
BladeburnerConstants.HrcHpGain
|
BladeburnerConstants.HrcHpGain
|
||||||
} HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`,
|
} HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`,
|
||||||
);
|
);
|
||||||
@ -1544,24 +1595,37 @@ export class Bladeburner implements IBladeburner {
|
|||||||
this.operations[operation].count += (60 * 3 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
this.operations[operation].count += (60 * 3 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
||||||
}
|
}
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log(`Incited violence in the synthoid communities.`);
|
this.log(`${person.whoAmI()}: Incited violence in the synthoid communities.`);
|
||||||
}
|
}
|
||||||
for (const cityName of Object.keys(this.cities)) {
|
for (const cityName of Object.keys(this.cities)) {
|
||||||
const city = this.cities[cityName];
|
const city = this.cities[cityName];
|
||||||
city.chaos += 10;
|
city.chaos += 10;
|
||||||
city.chaos += city.chaos / (Math.log(city.chaos) / Math.log(10));
|
city.chaos += city.chaos / (Math.log(city.chaos) / Math.log(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.startAction(player, this.action);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
console.error(`Bladeburner.completeAction() called for invalid action: ${this.action.type}`);
|
console.error(`Bladeburner.completeAction() called for invalid action: ${actionIdent.type}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
infiltrateSynthoidCommunities(p: IPlayer): void {
|
||||||
|
const infilSleeves = p.sleeves.filter((s) => s.bbAction === "Infiltrate synthoids").length;
|
||||||
|
const amt = Math.pow(infilSleeves, -0.5) / 2;
|
||||||
|
for (const contract of Object.keys(this.contracts)) {
|
||||||
|
this.contracts[contract].count += amt;
|
||||||
|
}
|
||||||
|
for (const operation of Object.keys(this.operations)) {
|
||||||
|
this.operations[operation].count += amt;
|
||||||
|
}
|
||||||
|
if (this.logging.general) {
|
||||||
|
this.log(`Sleeve: Infiltrate the synthoid communities.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeRank(player: IPlayer, change: number): void {
|
changeRank(person: IPerson, change: number): void {
|
||||||
if (isNaN(change)) {
|
if (isNaN(change)) {
|
||||||
throw new Error("NaN passed into Bladeburner.changeRank()");
|
throw new Error("NaN passed into Bladeburner.changeRank()");
|
||||||
}
|
}
|
||||||
@ -1582,7 +1646,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
if (bladeburnerFac.isMember) {
|
if (bladeburnerFac.isMember) {
|
||||||
const favorBonus = 1 + bladeburnerFac.favor / 100;
|
const favorBonus = 1 + bladeburnerFac.favor / 100;
|
||||||
bladeburnerFac.playerReputation +=
|
bladeburnerFac.playerReputation +=
|
||||||
BladeburnerConstants.RankToFactionRepFactor * change * player.faction_rep_mult * favorBonus;
|
BladeburnerConstants.RankToFactionRepFactor * change * person.faction_rep_mult * favorBonus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1613,7 +1677,19 @@ export class Bladeburner implements IBladeburner {
|
|||||||
this.actionTimeOverflow = 0;
|
this.actionTimeOverflow = 0;
|
||||||
if (this.actionTimeCurrent >= this.actionTimeToComplete) {
|
if (this.actionTimeCurrent >= this.actionTimeToComplete) {
|
||||||
this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
|
this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
|
||||||
return this.completeAction(router, player);
|
const retValue = this.completeAction(player, player, this.action);
|
||||||
|
player.gainMoney(retValue.money, "bladeburner");
|
||||||
|
player.gainStats(retValue);
|
||||||
|
// Operation Daedalus
|
||||||
|
const action = this.getActionObject(this.action);
|
||||||
|
if (action == null) {
|
||||||
|
throw new Error("Failed to get BlackOperation Object for: " + this.action.name);
|
||||||
|
} else if (action.name === BlackOperationNames.OperationDaedalus && this.blackops[action.name]) {
|
||||||
|
this.resetAction();
|
||||||
|
router.toBitVerse(false, false);
|
||||||
|
} else if (this.action.type != ActionTypes["BlackOperation"] && this.action.type != ActionTypes["BlackOp"]) {
|
||||||
|
this.startAction(player, this.action); // Repeat action
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2092,67 +2168,53 @@ export class Bladeburner implements IBladeburner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getActionTimeNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): number {
|
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string {
|
||||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
|
||||||
const actionId = this.getActionIdFromTypeAndName(type, name);
|
const actionId = this.getActionIdFromTypeAndName(type, name);
|
||||||
if (actionId == null) {
|
if (actionId == null) {
|
||||||
workerScript.log("bladeburner.getActionTime", () => errorLogText);
|
return "bladeburner.getActionTime";
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionObj = this.getActionObject(actionId);
|
const actionObj = this.getActionObject(actionId);
|
||||||
if (actionObj == null) {
|
if (actionObj == null) {
|
||||||
workerScript.log("bladeburner.getActionTime", () => errorLogText);
|
return "bladeburner.getActionTime";
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (actionId.type) {
|
switch (actionId.type) {
|
||||||
case ActionTypes["Contract"]:
|
case ActionTypes["Contract"]:
|
||||||
case ActionTypes["Operation"]:
|
case ActionTypes["Operation"]:
|
||||||
case ActionTypes["BlackOp"]:
|
case ActionTypes["BlackOp"]:
|
||||||
case ActionTypes["BlackOperation"]:
|
case ActionTypes["BlackOperation"]:
|
||||||
return actionObj.getActionTime(this) * 1000;
|
return actionObj.getActionTime(this, person) * 1000;
|
||||||
case ActionTypes["Training"]:
|
case ActionTypes["Training"]:
|
||||||
case ActionTypes["Field Analysis"]:
|
case ActionTypes["Field Analysis"]:
|
||||||
case ActionTypes["FieldAnalysis"]:
|
case ActionTypes["FieldAnalysis"]:
|
||||||
return 30000;
|
return 30000;
|
||||||
case ActionTypes["Recruitment"]:
|
case ActionTypes["Recruitment"]:
|
||||||
return this.getRecruitmentTime(player) * 1000;
|
return this.getRecruitmentTime(person) * 1000;
|
||||||
case ActionTypes["Diplomacy"]:
|
case ActionTypes["Diplomacy"]:
|
||||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||||
case ActionTypes["Incite Violence"]:
|
case ActionTypes["Incite Violence"]:
|
||||||
return 60000;
|
return 60000;
|
||||||
default:
|
default:
|
||||||
workerScript.log("bladeburner.getActionTime", () => errorLogText);
|
return "bladeburner.getActionTime";
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getActionEstimatedSuccessChanceNetscriptFn(
|
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string {
|
||||||
player: IPlayer,
|
|
||||||
type: string,
|
|
||||||
name: string,
|
|
||||||
workerScript: WorkerScript,
|
|
||||||
): [number, number] {
|
|
||||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
|
||||||
const actionId = this.getActionIdFromTypeAndName(type, name);
|
const actionId = this.getActionIdFromTypeAndName(type, name);
|
||||||
if (actionId == null) {
|
if (actionId == null) {
|
||||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", () => errorLogText);
|
return "bladeburner.getActionEstimatedSuccessChance";
|
||||||
return [-1, -1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionObj = this.getActionObject(actionId);
|
const actionObj = this.getActionObject(actionId);
|
||||||
if (actionObj == null) {
|
if (actionObj == null) {
|
||||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", () => errorLogText);
|
return "bladeburner.getActionEstimatedSuccessChance";
|
||||||
return [-1, -1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (actionId.type) {
|
switch (actionId.type) {
|
||||||
case ActionTypes["Contract"]:
|
case ActionTypes["Contract"]:
|
||||||
case ActionTypes["Operation"]:
|
case ActionTypes["Operation"]:
|
||||||
case ActionTypes["BlackOp"]:
|
case ActionTypes["BlackOp"]:
|
||||||
case ActionTypes["BlackOperation"]:
|
case ActionTypes["BlackOperation"]:
|
||||||
return actionObj.getEstSuccessChance(this);
|
return actionObj.getEstSuccessChance(this, person);
|
||||||
case ActionTypes["Training"]:
|
case ActionTypes["Training"]:
|
||||||
case ActionTypes["Field Analysis"]:
|
case ActionTypes["Field Analysis"]:
|
||||||
case ActionTypes["FieldAnalysis"]:
|
case ActionTypes["FieldAnalysis"]:
|
||||||
@ -2161,12 +2223,11 @@ export class Bladeburner implements IBladeburner {
|
|||||||
case ActionTypes["Incite Violence"]:
|
case ActionTypes["Incite Violence"]:
|
||||||
return [1, 1];
|
return [1, 1];
|
||||||
case ActionTypes["Recruitment"]: {
|
case ActionTypes["Recruitment"]: {
|
||||||
const recChance = this.getRecruitmentSuccessChance(player);
|
const recChance = this.getRecruitmentSuccessChance(person);
|
||||||
return [recChance, recChance];
|
return [recChance, recChance];
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
workerScript.log("bladeburner.getActionEstimatedSuccessChance", () => errorLogText);
|
return "bladeburner.getActionEstimatedSuccessChance";
|
||||||
return [-1, -1];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { IPerson } from "../PersonObjects/IPerson";
|
||||||
import { IBladeburner } from "./IBladeburner";
|
import { IBladeburner } from "./IBladeburner";
|
||||||
|
|
||||||
interface IStatsMultiplier {
|
interface IStatsMultiplier {
|
||||||
@ -55,15 +56,15 @@ export interface IAction {
|
|||||||
teamCount: number;
|
teamCount: number;
|
||||||
|
|
||||||
getDifficulty(): number;
|
getDifficulty(): number;
|
||||||
attempt(inst: IBladeburner): boolean;
|
attempt(inst: IBladeburner, person: IPerson): boolean;
|
||||||
getActionTimePenalty(): number;
|
getActionTimePenalty(): number;
|
||||||
getActionTime(inst: IBladeburner): number;
|
getActionTime(inst: IBladeburner, person: IPerson): number;
|
||||||
getTeamSuccessBonus(inst: IBladeburner): number;
|
getTeamSuccessBonus(inst: IBladeburner): number;
|
||||||
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
|
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
|
||||||
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
|
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
|
||||||
getChaosDifficultyBonus(inst: IBladeburner): number;
|
getChaosDifficultyBonus(inst: IBladeburner): number;
|
||||||
getEstSuccessChance(inst: IBladeburner): [number, number];
|
getEstSuccessChance(inst: IBladeburner, person: IPerson): [number, number];
|
||||||
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams): number;
|
getSuccessChance(inst: IBladeburner, person: IPerson, params: ISuccessChanceParams): number;
|
||||||
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
|
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
|
||||||
setMaxLevel(baseSuccessesPerLevel: number): void;
|
setMaxLevel(baseSuccessesPerLevel: number): void;
|
||||||
toJSON(): any;
|
toJSON(): any;
|
||||||
|
@ -3,6 +3,8 @@ import { City } from "./City";
|
|||||||
import { Skill } from "./Skill";
|
import { Skill } from "./Skill";
|
||||||
import { IAction } from "./IAction";
|
import { IAction } from "./IAction";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { IPerson } from "../PersonObjects/IPerson";
|
||||||
|
import { ITaskTracker } from "../PersonObjects/ITaskTracker";
|
||||||
import { IRouter } from "../ui/Router";
|
import { IRouter } from "../ui/Router";
|
||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
|
|
||||||
@ -70,13 +72,8 @@ export interface IBladeburner {
|
|||||||
getGeneralActionNamesNetscriptFn(): string[];
|
getGeneralActionNamesNetscriptFn(): string[];
|
||||||
getSkillNamesNetscriptFn(): string[];
|
getSkillNamesNetscriptFn(): string[];
|
||||||
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean;
|
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean;
|
||||||
getActionTimeNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): number;
|
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string;
|
||||||
getActionEstimatedSuccessChanceNetscriptFn(
|
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string;
|
||||||
player: IPlayer,
|
|
||||||
type: string,
|
|
||||||
name: string,
|
|
||||||
workerScript: WorkerScript,
|
|
||||||
): [number, number];
|
|
||||||
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
|
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
|
||||||
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number;
|
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number;
|
||||||
getSkillUpgradeCostNetscriptFn(skillName: string, workerScript: WorkerScript): number;
|
getSkillUpgradeCostNetscriptFn(skillName: string, workerScript: WorkerScript): number;
|
||||||
@ -95,20 +92,22 @@ export interface IBladeburner {
|
|||||||
triggerMigration(sourceCityName: string): void;
|
triggerMigration(sourceCityName: string): void;
|
||||||
triggerPotentialMigration(sourceCityName: string, chance: number): void;
|
triggerPotentialMigration(sourceCityName: string, chance: number): void;
|
||||||
randomEvent(): void;
|
randomEvent(): void;
|
||||||
gainActionStats(player: IPlayer, action: IAction, success: boolean): void;
|
|
||||||
getDiplomacyEffectiveness(player: IPlayer): number;
|
getDiplomacyEffectiveness(player: IPlayer): number;
|
||||||
getRecruitmentSuccessChance(player: IPlayer): number;
|
getRecruitmentSuccessChance(player: IPerson): number;
|
||||||
getRecruitmentTime(player: IPlayer): number;
|
getRecruitmentTime(player: IPerson): number;
|
||||||
resetSkillMultipliers(): void;
|
resetSkillMultipliers(): void;
|
||||||
updateSkillMultipliers(): void;
|
updateSkillMultipliers(): void;
|
||||||
completeOperation(success: boolean): void;
|
completeOperation(success: boolean, player: IPlayer): void;
|
||||||
getActionObject(actionId: IActionIdentifier): IAction | null;
|
getActionObject(actionId: IActionIdentifier): IAction | null;
|
||||||
completeContract(success: boolean): void;
|
completeContract(success: boolean, actionIdent: IActionIdentifier): void;
|
||||||
completeAction(router: IRouter, player: IPlayer): void;
|
completeAction(player: IPlayer, person: IPerson, actionIdent: IActionIdentifier, isPlayer?: boolean): ITaskTracker;
|
||||||
|
infiltrateSynthoidCommunities(p: IPlayer): void;
|
||||||
changeRank(player: IPlayer, change: number): void;
|
changeRank(player: IPlayer, change: number): void;
|
||||||
processAction(router: IRouter, player: IPlayer, seconds: number): void;
|
processAction(router: IRouter, player: IPlayer, seconds: number): void;
|
||||||
calculateStaminaGainPerSecond(player: IPlayer): number;
|
calculateStaminaGainPerSecond(player: IPlayer): number;
|
||||||
calculateMaxStamina(player: IPlayer): void;
|
calculateMaxStamina(player: IPlayer): void;
|
||||||
create(): void;
|
create(): void;
|
||||||
process(router: IRouter, player: IPlayer): void;
|
process(router: IRouter, player: IPlayer): void;
|
||||||
|
getActionStats(action: IAction, success: boolean): ITaskTracker;
|
||||||
|
sleeveSupport(joining: boolean): void;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
|
|||||||
const isActive =
|
const isActive =
|
||||||
props.bladeburner.action.type === ActionTypes["BlackOperation"] &&
|
props.bladeburner.action.type === ActionTypes["BlackOperation"] &&
|
||||||
props.action.name === props.bladeburner.action.name;
|
props.action.name === props.bladeburner.action.name;
|
||||||
const actionTime = props.action.getActionTime(props.bladeburner);
|
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
|
||||||
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
|
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
|
||||||
const computedActionTimeCurrent = Math.min(
|
const computedActionTimeCurrent = Math.min(
|
||||||
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
||||||
|
@ -32,7 +32,7 @@ export function ContractElem(props: IProps): React.ReactElement {
|
|||||||
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
||||||
props.bladeburner.actionTimeToComplete,
|
props.bladeburner.actionTimeToComplete,
|
||||||
);
|
);
|
||||||
const actionTime = props.action.getActionTime(props.bladeburner);
|
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
|
||||||
|
|
||||||
const actionData = Contracts[props.action.name];
|
const actionData = Contracts[props.action.name];
|
||||||
if (actionData === undefined) {
|
if (actionData === undefined) {
|
||||||
|
@ -33,7 +33,7 @@ export function OperationElem(props: IProps): React.ReactElement {
|
|||||||
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
|
||||||
props.bladeburner.actionTimeToComplete,
|
props.bladeburner.actionTimeToComplete,
|
||||||
);
|
);
|
||||||
const actionTime = props.action.getActionTime(props.bladeburner);
|
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
|
||||||
|
|
||||||
const actionData = Operations[props.action.name];
|
const actionData = Operations[props.action.name];
|
||||||
if (actionData === undefined) {
|
if (actionData === undefined) {
|
||||||
|
@ -4,6 +4,7 @@ import { StealthIcon } from "./StealthIcon";
|
|||||||
import { KillIcon } from "./KillIcon";
|
import { KillIcon } from "./KillIcon";
|
||||||
import { IAction } from "../IAction";
|
import { IAction } from "../IAction";
|
||||||
import { IBladeburner } from "../IBladeburner";
|
import { IBladeburner } from "../IBladeburner";
|
||||||
|
import { Player } from "../../Player";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
bladeburner: IBladeburner;
|
bladeburner: IBladeburner;
|
||||||
@ -11,7 +12,7 @@ interface IProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function SuccessChance(props: IProps): React.ReactElement {
|
export function SuccessChance(props: IProps): React.ReactElement {
|
||||||
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
|
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner, Player);
|
||||||
|
|
||||||
let chance = <></>;
|
let chance = <></>;
|
||||||
if (estimatedSuccessChance[0] === estimatedSuccessChance[1]) {
|
if (estimatedSuccessChance[0] === estimatedSuccessChance[1]) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
|
import { IPerson } from "../PersonObjects/IPerson";
|
||||||
import { IRouter } from "../ui/Router";
|
import { IRouter } from "../ui/Router";
|
||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
import { CrimeType } from "../utils/WorkType";
|
import { CrimeType } from "../utils/WorkType";
|
||||||
@ -117,7 +117,7 @@ export class Crime {
|
|||||||
return this.time;
|
return this.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
successRate(p: IPlayerOrSleeve): number {
|
successRate(p: IPerson): number {
|
||||||
let chance: number =
|
let chance: number =
|
||||||
this.hacking_success_weight * p.hacking +
|
this.hacking_success_weight * p.hacking +
|
||||||
this.strength_success_weight * p.strength +
|
this.strength_success_weight * p.strength +
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { CONSTANTS } from "../Constants";
|
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
|
||||||
export function getHospitalizationCost(p: IPlayer): number {
|
export function getHospitalizationCost(p: IPlayer): number {
|
||||||
if (p.money < 0) {
|
if (p.money < 0) {
|
||||||
|
@ -284,6 +284,7 @@ const sleeve: IMap<any> = {
|
|||||||
getSleeveAugmentations: RamCostConstants.ScriptSleeveBaseRamCost,
|
getSleeveAugmentations: RamCostConstants.ScriptSleeveBaseRamCost,
|
||||||
getSleevePurchasableAugs: RamCostConstants.ScriptSleeveBaseRamCost,
|
getSleevePurchasableAugs: RamCostConstants.ScriptSleeveBaseRamCost,
|
||||||
purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost,
|
purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost,
|
||||||
|
setToBladeburnerAction: RamCostConstants.ScriptSleeveBaseRamCost,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stanek API
|
// Stanek API
|
||||||
|
@ -125,7 +125,14 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
|
|||||||
const bladeburner = player.bladeburner;
|
const bladeburner = player.bladeburner;
|
||||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||||
try {
|
try {
|
||||||
return bladeburner.getActionTimeNetscriptFn(player, type, name, workerScript);
|
const time = bladeburner.getActionTimeNetscriptFn(player, type, name);
|
||||||
|
if (typeof time === "string") {
|
||||||
|
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||||
|
ctx.log(() => errorLogText);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw ctx.makeRuntimeErrorMsg(e);
|
throw ctx.makeRuntimeErrorMsg(e);
|
||||||
}
|
}
|
||||||
@ -139,7 +146,14 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
|
|||||||
const bladeburner = player.bladeburner;
|
const bladeburner = player.bladeburner;
|
||||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||||
try {
|
try {
|
||||||
return bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name, workerScript);
|
const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name);
|
||||||
|
if (typeof chance === "string") {
|
||||||
|
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||||
|
ctx.log(() => errorLogText);
|
||||||
|
return [-1, -1];
|
||||||
|
} else {
|
||||||
|
return chance;
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw ctx.makeRuntimeErrorMsg(e);
|
throw ctx.makeRuntimeErrorMsg(e);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import { Router } from "../ui/GameRoot";
|
|||||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||||
import { Page } from "../ui/Router";
|
import { Page } from "../ui/Router";
|
||||||
import { Locations } from "../Locations/Locations";
|
import { Locations } from "../Locations/Locations";
|
||||||
import { GetServer, AddToAllServers, createUniqueRandomIp } from "../Server/AllServers";
|
import { GetServer } from "../Server/AllServers";
|
||||||
import { Programs } from "../Programs/Programs";
|
import { Programs } from "../Programs/Programs";
|
||||||
import { numeralWrapper } from "../ui/numeralFormat";
|
import { numeralWrapper } from "../ui/numeralFormat";
|
||||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
@ -39,7 +39,7 @@ import { Factions, factionExists } from "../Faction/Factions";
|
|||||||
import { Faction } from "../Faction/Faction";
|
import { Faction } from "../Faction/Faction";
|
||||||
import { netscriptDelay } from "../NetscriptEvaluator";
|
import { netscriptDelay } from "../NetscriptEvaluator";
|
||||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||||
import { getServerOnNetwork, safetlyCreateUniqueServer } from "../Server/ServerHelpers";
|
import { getServerOnNetwork } from "../Server/ServerHelpers";
|
||||||
import { Terminal } from "../Terminal";
|
import { Terminal } from "../Terminal";
|
||||||
import { calculateHackingTime } from "../Hacking";
|
import { calculateHackingTime } from "../Hacking";
|
||||||
import { Server } from "../Server/Server";
|
import { Server } from "../Server/Server";
|
||||||
|
@ -310,5 +310,36 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
|||||||
|
|
||||||
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
|
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
|
||||||
},
|
},
|
||||||
|
setToBladeburnerAction:
|
||||||
|
(ctx: NetscriptContext) =>
|
||||||
|
(_sleeveNumber: unknown, _action: unknown, _contract?: unknown): boolean => {
|
||||||
|
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||||
|
const action = ctx.helper.string("action", _action);
|
||||||
|
let contract: string;
|
||||||
|
if (typeof _contract === "undefined") {
|
||||||
|
contract = "------";
|
||||||
|
} else {
|
||||||
|
contract = ctx.helper.string("contract", _contract);
|
||||||
|
}
|
||||||
|
checkSleeveAPIAccess(ctx);
|
||||||
|
checkSleeveNumber(ctx, sleeveNumber);
|
||||||
|
|
||||||
|
// Cannot Take on Contracts if another sleeve is performing that action
|
||||||
|
if (action === "Take on contracts") {
|
||||||
|
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||||
|
if (i === sleeveNumber) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const other = player.sleeves[i];
|
||||||
|
if (other.currentTask === SleeveTaskType.Bladeburner && other.bbAction === action) {
|
||||||
|
throw ctx.helper.makeRuntimeErrorMsg(
|
||||||
|
`Sleeve ${sleeveNumber} cannot take of contracts because Sleeve ${i} is already performing that action.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return player.sleeves[sleeveNumber].bladeburner(player, action, contract);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
66
src/PersonObjects/IPerson.ts
Normal file
66
src/PersonObjects/IPerson.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Interface that represents either the player (PlayerObject) or
|
||||||
|
// a Sleeve. Used for functions that need to take in both.
|
||||||
|
|
||||||
|
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||||
|
import { ITaskTracker } from "./ITaskTracker";
|
||||||
|
|
||||||
|
export interface IPerson {
|
||||||
|
// Stats
|
||||||
|
hacking: number;
|
||||||
|
strength: number;
|
||||||
|
defense: number;
|
||||||
|
dexterity: number;
|
||||||
|
agility: number;
|
||||||
|
charisma: number;
|
||||||
|
intelligence: number;
|
||||||
|
hp: number;
|
||||||
|
max_hp: number;
|
||||||
|
|
||||||
|
// Experience
|
||||||
|
hacking_exp: number;
|
||||||
|
strength_exp: number;
|
||||||
|
defense_exp: number;
|
||||||
|
dexterity_exp: number;
|
||||||
|
agility_exp: number;
|
||||||
|
charisma_exp: number;
|
||||||
|
intelligence_exp: number;
|
||||||
|
|
||||||
|
// Multipliers
|
||||||
|
hacking_exp_mult: number;
|
||||||
|
strength_exp_mult: number;
|
||||||
|
defense_exp_mult: number;
|
||||||
|
dexterity_exp_mult: number;
|
||||||
|
agility_exp_mult: number;
|
||||||
|
charisma_exp_mult: number;
|
||||||
|
hacking_mult: number;
|
||||||
|
strength_mult: number;
|
||||||
|
defense_mult: number;
|
||||||
|
dexterity_mult: number;
|
||||||
|
agility_mult: number;
|
||||||
|
charisma_mult: number;
|
||||||
|
|
||||||
|
company_rep_mult: number;
|
||||||
|
faction_rep_mult: number;
|
||||||
|
|
||||||
|
crime_money_mult: number;
|
||||||
|
crime_success_mult: number;
|
||||||
|
|
||||||
|
bladeburner_analysis_mult: number;
|
||||||
|
|
||||||
|
augmentations: IPlayerOwnedAugmentation[];
|
||||||
|
|
||||||
|
getIntelligenceBonus(weight: number): number;
|
||||||
|
gainHackingExp(exp: number): void;
|
||||||
|
gainStrengthExp(exp: number): void;
|
||||||
|
gainDefenseExp(exp: number): void;
|
||||||
|
gainDexterityExp(exp: number): void;
|
||||||
|
gainAgilityExp(exp: number): void;
|
||||||
|
gainCharismaExp(exp: number): void;
|
||||||
|
gainIntelligenceExp(exp: number): void;
|
||||||
|
gainStats(retValue: ITaskTracker): void;
|
||||||
|
calculateSkill(exp: number, mult?: number): number;
|
||||||
|
takeDamage(amt: number): boolean;
|
||||||
|
regenerateHp: (amt: number) => void;
|
||||||
|
queryStatFromString: (str: string) => number;
|
||||||
|
whoAmI: () => string;
|
||||||
|
}
|
@ -30,11 +30,10 @@ import { WorkerScript } from "../Netscript/WorkerScript";
|
|||||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||||
import { ISkillProgress } from "./formulas/skill";
|
import { ISkillProgress } from "./formulas/skill";
|
||||||
import { PlayerAchievement } from "../Achievements/Achievements";
|
import { PlayerAchievement } from "../Achievements/Achievements";
|
||||||
|
import { IPerson } from "./IPerson";
|
||||||
import { WorkType, ClassType, CrimeType } from "../utils/WorkType";
|
import { WorkType, ClassType, CrimeType } from "../utils/WorkType";
|
||||||
|
|
||||||
export interface IPlayer {
|
export interface IPlayer extends IPerson {
|
||||||
// Class members
|
|
||||||
augmentations: IPlayerOwnedAugmentation[];
|
|
||||||
bitNodeN: number;
|
bitNodeN: number;
|
||||||
city: CityName;
|
city: CityName;
|
||||||
companyName: string;
|
companyName: string;
|
||||||
@ -186,13 +185,6 @@ export interface IPlayer {
|
|||||||
canAccessGang(): boolean;
|
canAccessGang(): boolean;
|
||||||
canAccessGrafting(): boolean;
|
canAccessGrafting(): boolean;
|
||||||
canAfford(cost: number): boolean;
|
canAfford(cost: number): boolean;
|
||||||
gainHackingExp(exp: number): void;
|
|
||||||
gainStrengthExp(exp: number): void;
|
|
||||||
gainDefenseExp(exp: number): void;
|
|
||||||
gainDexterityExp(exp: number): void;
|
|
||||||
gainAgilityExp(exp: number): void;
|
|
||||||
gainCharismaExp(exp: number): void;
|
|
||||||
gainIntelligenceExp(exp: number): void;
|
|
||||||
gainMoney(money: number, source: string): void;
|
gainMoney(money: number, source: string): void;
|
||||||
getCurrentServer(): BaseServer;
|
getCurrentServer(): BaseServer;
|
||||||
getGangFaction(): Faction;
|
getGangFaction(): Faction;
|
||||||
@ -215,7 +207,6 @@ export interface IPlayer {
|
|||||||
process(router: IRouter, numCycles?: number): void;
|
process(router: IRouter, numCycles?: number): void;
|
||||||
reapplyAllAugmentations(resetMultipliers?: boolean): void;
|
reapplyAllAugmentations(resetMultipliers?: boolean): void;
|
||||||
reapplyAllSourceFiles(): void;
|
reapplyAllSourceFiles(): void;
|
||||||
regenerateHp(amt: number): void;
|
|
||||||
setMoney(amt: number): void;
|
setMoney(amt: number): void;
|
||||||
singularityStopWork(): string;
|
singularityStopWork(): string;
|
||||||
startBladeburner(p: any): void;
|
startBladeburner(p: any): void;
|
||||||
@ -242,12 +233,9 @@ export interface IPlayer {
|
|||||||
startGang(facName: string, isHacking: boolean): void;
|
startGang(facName: string, isHacking: boolean): void;
|
||||||
startWork(companyName: string): void;
|
startWork(companyName: string): void;
|
||||||
startWorkPartTime(companyName: string): void;
|
startWorkPartTime(companyName: string): void;
|
||||||
takeDamage(amt: number): boolean;
|
|
||||||
travel(to: CityName): boolean;
|
travel(to: CityName): boolean;
|
||||||
giveExploit(exploit: Exploit): void;
|
giveExploit(exploit: Exploit): void;
|
||||||
giveAchievement(achievementId: string): void;
|
giveAchievement(achievementId: string): void;
|
||||||
queryStatFromString(str: string): number;
|
|
||||||
getIntelligenceBonus(weight: number): number;
|
|
||||||
getCasinoWinnings(): number;
|
getCasinoWinnings(): number;
|
||||||
quitJob(company: string, sing?: boolean): void;
|
quitJob(company: string, sing?: boolean): void;
|
||||||
hasJob(): boolean;
|
hasJob(): boolean;
|
||||||
@ -268,7 +256,6 @@ export interface IPlayer {
|
|||||||
resetMultipliers(): void;
|
resetMultipliers(): void;
|
||||||
prestigeAugmentation(): void;
|
prestigeAugmentation(): void;
|
||||||
prestigeSourceFile(): void;
|
prestigeSourceFile(): void;
|
||||||
calculateSkill(exp: number, mult?: number): number;
|
|
||||||
calculateSkillProgress(exp: number, mult?: number): ISkillProgress;
|
calculateSkillProgress(exp: number, mult?: number): ISkillProgress;
|
||||||
resetWorkStatus(generalType?: WorkType, group?: string, workType?: string): void;
|
resetWorkStatus(generalType?: WorkType, group?: string, workType?: string): void;
|
||||||
getWorkHackExpGain(): number;
|
getWorkHackExpGain(): number;
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
// Interface that represents either the player (PlayerObject) or
|
|
||||||
// a Sleeve. Used for functions that need to take in both.
|
|
||||||
|
|
||||||
export interface IPlayerOrSleeve {
|
|
||||||
// Stats
|
|
||||||
hacking: number;
|
|
||||||
strength: number;
|
|
||||||
defense: number;
|
|
||||||
dexterity: number;
|
|
||||||
agility: number;
|
|
||||||
charisma: number;
|
|
||||||
intelligence: number;
|
|
||||||
|
|
||||||
// Experience
|
|
||||||
hacking_exp: number;
|
|
||||||
strength_exp: number;
|
|
||||||
defense_exp: number;
|
|
||||||
dexterity_exp: number;
|
|
||||||
agility_exp: number;
|
|
||||||
charisma_exp: number;
|
|
||||||
|
|
||||||
// Multipliers
|
|
||||||
crime_success_mult: number;
|
|
||||||
|
|
||||||
getIntelligenceBonus(weight: number): number;
|
|
||||||
}
|
|
25
src/PersonObjects/ITaskTracker.ts
Normal file
25
src/PersonObjects/ITaskTracker.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Interface that defines a generic object used to track experience/money
|
||||||
|
// earnings for tasks
|
||||||
|
export interface ITaskTracker {
|
||||||
|
hack: number;
|
||||||
|
str: number;
|
||||||
|
def: number;
|
||||||
|
dex: number;
|
||||||
|
agi: number;
|
||||||
|
cha: number;
|
||||||
|
int: number;
|
||||||
|
money: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTaskTracker(): ITaskTracker {
|
||||||
|
return {
|
||||||
|
hack: 0,
|
||||||
|
str: 0,
|
||||||
|
def: 0,
|
||||||
|
dex: 0,
|
||||||
|
agi: 0,
|
||||||
|
cha: 0,
|
||||||
|
int: 0,
|
||||||
|
money: 0,
|
||||||
|
};
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Base class representing a person-like object
|
import * as generalMethods from "./Player/PlayerObjectGeneralMethods";
|
||||||
import { Augmentation } from "../Augmentation/Augmentation";
|
import { Augmentation } from "../Augmentation/Augmentation";
|
||||||
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
@ -6,32 +6,10 @@ import { CityName } from "../Locations/data/CityNames";
|
|||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
import { calculateSkill } from "./formulas/skill";
|
import { calculateSkill } from "./formulas/skill";
|
||||||
import { calculateIntelligenceBonus } from "./formulas/intelligence";
|
import { calculateIntelligenceBonus } from "./formulas/intelligence";
|
||||||
|
import { IPerson } from "./IPerson";
|
||||||
|
|
||||||
// Interface that defines a generic object used to track experience/money
|
// Base class representing a person-like object
|
||||||
// earnings for tasks
|
export abstract class Person implements IPerson {
|
||||||
export interface ITaskTracker {
|
|
||||||
hack: number;
|
|
||||||
str: number;
|
|
||||||
def: number;
|
|
||||||
dex: number;
|
|
||||||
agi: number;
|
|
||||||
cha: number;
|
|
||||||
money: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createTaskTracker(): ITaskTracker {
|
|
||||||
return {
|
|
||||||
hack: 0,
|
|
||||||
str: 0,
|
|
||||||
def: 0,
|
|
||||||
dex: 0,
|
|
||||||
agi: 0,
|
|
||||||
cha: 0,
|
|
||||||
money: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class Person {
|
|
||||||
/**
|
/**
|
||||||
* Stats
|
* Stats
|
||||||
*/
|
*/
|
||||||
@ -41,7 +19,7 @@ export abstract class Person {
|
|||||||
dexterity = 1;
|
dexterity = 1;
|
||||||
agility = 1;
|
agility = 1;
|
||||||
charisma = 1;
|
charisma = 1;
|
||||||
intelligence = 1;
|
intelligence = 0;
|
||||||
hp = 10;
|
hp = 10;
|
||||||
max_hp = 10;
|
max_hp = 10;
|
||||||
|
|
||||||
@ -97,24 +75,28 @@ export abstract class Person {
|
|||||||
bladeburner_analysis_mult = 1;
|
bladeburner_analysis_mult = 1;
|
||||||
bladeburner_success_chance_mult = 1;
|
bladeburner_success_chance_mult = 1;
|
||||||
|
|
||||||
infiltration_base_rep_increase = 0;
|
|
||||||
infiltration_rep_mult = 1;
|
|
||||||
infiltration_trade_mult = 1;
|
|
||||||
infiltration_sell_mult = 1;
|
|
||||||
infiltration_timer_mult = 1;
|
|
||||||
infiltration_damage_reduction_mult = 1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Augmentations
|
* Augmentations
|
||||||
*/
|
*/
|
||||||
augmentations: IPlayerOwnedAugmentation[] = [];
|
augmentations: IPlayerOwnedAugmentation[] = [];
|
||||||
queuedAugmentations: IPlayerOwnedAugmentation[] = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* City that the person is in
|
* City that the person is in
|
||||||
*/
|
*/
|
||||||
city: CityName = CityName.Sector12;
|
city: CityName = CityName.Sector12;
|
||||||
|
|
||||||
|
gainHackingExp = generalMethods.gainHackingExp;
|
||||||
|
gainStrengthExp = generalMethods.gainStrengthExp;
|
||||||
|
gainDefenseExp = generalMethods.gainDefenseExp;
|
||||||
|
gainDexterityExp = generalMethods.gainDexterityExp;
|
||||||
|
gainAgilityExp = generalMethods.gainAgilityExp;
|
||||||
|
gainCharismaExp = generalMethods.gainCharismaExp;
|
||||||
|
gainIntelligenceExp = generalMethods.gainIntelligenceExp;
|
||||||
|
gainStats = generalMethods.gainStats;
|
||||||
|
calculateSkill = generalMethods.calculateSkill;
|
||||||
|
regenerateHp = generalMethods.regenerateHp;
|
||||||
|
queryStatFromString = generalMethods.queryStatFromString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this object's multipliers for the given augmentation
|
* Updates this object's multipliers for the given augmentation
|
||||||
*/
|
*/
|
||||||
@ -213,13 +195,6 @@ export abstract class Person {
|
|||||||
this.bladeburner_stamina_gain_mult = 1;
|
this.bladeburner_stamina_gain_mult = 1;
|
||||||
this.bladeburner_analysis_mult = 1;
|
this.bladeburner_analysis_mult = 1;
|
||||||
this.bladeburner_success_chance_mult = 1;
|
this.bladeburner_success_chance_mult = 1;
|
||||||
|
|
||||||
this.infiltration_base_rep_increase = 0;
|
|
||||||
this.infiltration_rep_mult = 1;
|
|
||||||
this.infiltration_trade_mult = 1;
|
|
||||||
this.infiltration_sell_mult = 1;
|
|
||||||
this.infiltration_timer_mult = 1;
|
|
||||||
this.infiltration_damage_reduction_mult = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -265,4 +240,8 @@ export abstract class Person {
|
|||||||
getIntelligenceBonus(weight: number): number {
|
getIntelligenceBonus(weight: number): number {
|
||||||
return calculateIntelligenceBonus(this.intelligence, weight);
|
return calculateIntelligenceBonus(this.intelligence, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract takeDamage(amt: number): boolean;
|
||||||
|
|
||||||
|
abstract whoAmI(): string;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import { ISkillProgress } from "../formulas/skill";
|
|||||||
import { PlayerAchievement } from "../../Achievements/Achievements";
|
import { PlayerAchievement } from "../../Achievements/Achievements";
|
||||||
import { cyrb53 } from "../../utils/StringHelperFunctions";
|
import { cyrb53 } from "../../utils/StringHelperFunctions";
|
||||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||||
|
import { ITaskTracker } from "../ITaskTracker";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { WorkType, ClassType, CrimeType, PlayerFactionWorkType } from "../../utils/WorkType";
|
import { WorkType, ClassType, CrimeType, PlayerFactionWorkType } from "../../utils/WorkType";
|
||||||
|
|
||||||
@ -203,6 +204,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
gainAgilityExp: (exp: number) => void;
|
gainAgilityExp: (exp: number) => void;
|
||||||
gainCharismaExp: (exp: number) => void;
|
gainCharismaExp: (exp: number) => void;
|
||||||
gainIntelligenceExp: (exp: number) => void;
|
gainIntelligenceExp: (exp: number) => void;
|
||||||
|
gainStats: (retValue: ITaskTracker) => void;
|
||||||
gainMoney: (money: number, source: string) => void;
|
gainMoney: (money: number, source: string) => void;
|
||||||
getCurrentServer: () => BaseServer;
|
getCurrentServer: () => BaseServer;
|
||||||
getGangFaction: () => Faction;
|
getGangFaction: () => Faction;
|
||||||
@ -524,6 +526,7 @@ export class PlayerObject implements IPlayer {
|
|||||||
this.gainAgilityExp = generalMethods.gainAgilityExp;
|
this.gainAgilityExp = generalMethods.gainAgilityExp;
|
||||||
this.gainCharismaExp = generalMethods.gainCharismaExp;
|
this.gainCharismaExp = generalMethods.gainCharismaExp;
|
||||||
this.gainIntelligenceExp = generalMethods.gainIntelligenceExp;
|
this.gainIntelligenceExp = generalMethods.gainIntelligenceExp;
|
||||||
|
this.gainStats = generalMethods.gainStats;
|
||||||
this.queryStatFromString = generalMethods.queryStatFromString;
|
this.queryStatFromString = generalMethods.queryStatFromString;
|
||||||
this.resetWorkStatus = generalMethods.resetWorkStatus;
|
this.resetWorkStatus = generalMethods.resetWorkStatus;
|
||||||
this.processWorkEarnings = generalMethods.processWorkEarnings;
|
this.processWorkEarnings = generalMethods.processWorkEarnings;
|
||||||
@ -632,6 +635,10 @@ export class PlayerObject implements IPlayer {
|
|||||||
this.applyEntropy = augmentationMethods.applyEntropy;
|
this.applyEntropy = augmentationMethods.applyEntropy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
whoAmI(): string {
|
||||||
|
return "Player";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize the current object to a JSON save state.
|
* Serialize the current object to a JSON save state.
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +64,9 @@ import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar";
|
|||||||
import { calculateClassEarnings } from "../formulas/work";
|
import { calculateClassEarnings } from "../formulas/work";
|
||||||
import { achievements } from "../../Achievements/Achievements";
|
import { achievements } from "../../Achievements/Achievements";
|
||||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||||
|
import { ITaskTracker } from "../ITaskTracker";
|
||||||
|
import { IPerson } from "../IPerson";
|
||||||
|
import { Player } from "../../Player";
|
||||||
import { graftingIntBonus } from "../Grafting/GraftingHelpers";
|
import { graftingIntBonus } from "../Grafting/GraftingHelpers";
|
||||||
|
|
||||||
import { WorkType, PlayerFactionWorkType, ClassType, CrimeType } from "../../utils/WorkType";
|
import { WorkType, PlayerFactionWorkType, ClassType, CrimeType } from "../../utils/WorkType";
|
||||||
@ -228,7 +231,7 @@ export function receiveInvite(this: IPlayer, factionName: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Calculates skill level based on experience. The same formula will be used for every skill
|
//Calculates skill level based on experience. The same formula will be used for every skill
|
||||||
export function calculateSkill(this: IPlayer, exp: number, mult = 1): number {
|
export function calculateSkill(this: IPerson, exp: number, mult = 1): number {
|
||||||
return calculateSkillF(exp, mult);
|
return calculateSkillF(exp, mult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +382,7 @@ export function recordMoneySource(this: PlayerObject, amt: number, source: strin
|
|||||||
this.moneySourceB.record(amt, source);
|
this.moneySourceB.record(amt, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainHackingExp(this: IPlayer, exp: number): void {
|
export function gainHackingExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERR: NaN passed into Player.gainHackingExp()");
|
console.error("ERR: NaN passed into Player.gainHackingExp()");
|
||||||
return;
|
return;
|
||||||
@ -392,7 +395,7 @@ export function gainHackingExp(this: IPlayer, exp: number): void {
|
|||||||
this.hacking = calculateSkillF(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier);
|
this.hacking = calculateSkillF(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainStrengthExp(this: IPlayer, exp: number): void {
|
export function gainStrengthExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERR: NaN passed into Player.gainStrengthExp()");
|
console.error("ERR: NaN passed into Player.gainStrengthExp()");
|
||||||
return;
|
return;
|
||||||
@ -405,7 +408,7 @@ export function gainStrengthExp(this: IPlayer, exp: number): void {
|
|||||||
this.strength = calculateSkillF(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier);
|
this.strength = calculateSkillF(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainDefenseExp(this: IPlayer, exp: number): void {
|
export function gainDefenseExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERR: NaN passed into player.gainDefenseExp()");
|
console.error("ERR: NaN passed into player.gainDefenseExp()");
|
||||||
return;
|
return;
|
||||||
@ -421,7 +424,7 @@ export function gainDefenseExp(this: IPlayer, exp: number): void {
|
|||||||
this.hp = Math.round(this.max_hp * ratio);
|
this.hp = Math.round(this.max_hp * ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainDexterityExp(this: IPlayer, exp: number): void {
|
export function gainDexterityExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERR: NaN passed into Player.gainDexterityExp()");
|
console.error("ERR: NaN passed into Player.gainDexterityExp()");
|
||||||
return;
|
return;
|
||||||
@ -437,7 +440,7 @@ export function gainDexterityExp(this: IPlayer, exp: number): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainAgilityExp(this: IPlayer, exp: number): void {
|
export function gainAgilityExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERR: NaN passed into Player.gainAgilityExp()");
|
console.error("ERR: NaN passed into Player.gainAgilityExp()");
|
||||||
return;
|
return;
|
||||||
@ -450,7 +453,7 @@ export function gainAgilityExp(this: IPlayer, exp: number): void {
|
|||||||
this.agility = calculateSkillF(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier);
|
this.agility = calculateSkillF(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainCharismaExp(this: IPlayer, exp: number): void {
|
export function gainCharismaExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERR: NaN passed into Player.gainCharismaExp()");
|
console.error("ERR: NaN passed into Player.gainCharismaExp()");
|
||||||
return;
|
return;
|
||||||
@ -463,17 +466,27 @@ export function gainCharismaExp(this: IPlayer, exp: number): void {
|
|||||||
this.charisma = calculateSkillF(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier);
|
this.charisma = calculateSkillF(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainIntelligenceExp(this: IPlayer, exp: number): void {
|
export function gainIntelligenceExp(this: IPerson, exp: number): void {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.error("ERROR: NaN passed into Player.gainIntelligenceExp()");
|
console.error("ERROR: NaN passed into Player.gainIntelligenceExp()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.sourceFileLvl(5) > 0 || this.intelligence > 0) {
|
if (Player.sourceFileLvl(5) > 0 || this.intelligence > 0) {
|
||||||
this.intelligence_exp += exp;
|
this.intelligence_exp += exp;
|
||||||
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
|
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function gainStats(this: IPerson, retValue: ITaskTracker): void {
|
||||||
|
this.gainHackingExp(retValue.hack * this.hacking_exp_mult);
|
||||||
|
this.gainStrengthExp(retValue.str * this.strength_exp_mult);
|
||||||
|
this.gainDefenseExp(retValue.def * this.defense_exp_mult);
|
||||||
|
this.gainDexterityExp(retValue.dex * this.dexterity_exp_mult);
|
||||||
|
this.gainAgilityExp(retValue.agi * this.agility_exp_mult);
|
||||||
|
this.gainCharismaExp(retValue.cha * this.charisma_exp_mult);
|
||||||
|
this.gainIntelligenceExp(retValue.int);
|
||||||
|
}
|
||||||
|
|
||||||
//Given a string expression like "str" or "strength", returns the given stat
|
//Given a string expression like "str" or "strength", returns the given stat
|
||||||
export function queryStatFromString(this: IPlayer, str: string): number {
|
export function queryStatFromString(this: IPlayer, str: string): number {
|
||||||
const tempStr = str.toLowerCase();
|
const tempStr = str.toLowerCase();
|
||||||
@ -1726,7 +1739,7 @@ export function takeDamage(this: IPlayer, amt: number): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function regenerateHp(this: IPlayer, amt: number): void {
|
export function regenerateHp(this: IPerson, amt: number): void {
|
||||||
if (typeof amt !== "number") {
|
if (typeof amt !== "number") {
|
||||||
console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`);
|
console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`);
|
||||||
return;
|
return;
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
||||||
|
|
||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
import { Person, ITaskTracker, createTaskTracker } from "../Person";
|
import { Person } from "../Person";
|
||||||
|
import { ITaskTracker, createTaskTracker } from "../ITaskTracker";
|
||||||
|
|
||||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||||
|
|
||||||
@ -33,6 +34,9 @@ import { CityName } from "../../Locations/data/CityNames";
|
|||||||
import { LocationName } from "../../Locations/data/LocationNames";
|
import { LocationName } from "../../Locations/data/LocationNames";
|
||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||||
|
import { BladeburnerConstants } from "../../Bladeburner/data/Constants";
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
import { capitalizeFirstLetter, capitalizeEachWord } from "../../utils/StringHelperFunctions";
|
||||||
|
|
||||||
export class Sleeve extends Person {
|
export class Sleeve extends Person {
|
||||||
/**
|
/**
|
||||||
@ -58,6 +62,7 @@ export class Sleeve extends Person {
|
|||||||
* Faction/Company Work: Name of Faction/Company
|
* Faction/Company Work: Name of Faction/Company
|
||||||
* Crime: Money earned if successful
|
* Crime: Money earned if successful
|
||||||
* Class/Gym: Name of university/gym
|
* Class/Gym: Name of university/gym
|
||||||
|
* Bladeburner: success chance
|
||||||
*/
|
*/
|
||||||
currentTaskLocation = "";
|
currentTaskLocation = "";
|
||||||
|
|
||||||
@ -101,6 +106,16 @@ export class Sleeve extends Person {
|
|||||||
*/
|
*/
|
||||||
gymStatType = "";
|
gymStatType = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String that stores what stat the sleeve is training at the gym
|
||||||
|
*/
|
||||||
|
bbAction = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String that stores what stat the sleeve is training at the gym
|
||||||
|
*/
|
||||||
|
bbContract = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of events/notifications for this sleeve
|
* Keeps track of events/notifications for this sleeve
|
||||||
*/
|
*/
|
||||||
@ -151,7 +166,7 @@ export class Sleeve extends Person {
|
|||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gainRatesForTask.hack = crime.hacking_exp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.hack = crime.hacking_exp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
@ -160,6 +175,7 @@ export class Sleeve extends Person {
|
|||||||
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.int = crime.intelligence_exp;
|
||||||
this.gainRatesForTask.money = crime.money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
|
this.gainRatesForTask.money = crime.money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
|
||||||
|
|
||||||
this.currentTaskLocation = String(this.gainRatesForTask.money);
|
this.currentTaskLocation = String(this.gainRatesForTask.money);
|
||||||
@ -182,7 +198,7 @@ export class Sleeve extends Person {
|
|||||||
const crime: Crime | undefined = Object.values(Crimes).find((crime) => crime.name === this.crimeType);
|
const crime: Crime | undefined = Object.values(Crimes).find((crime) => crime.name === this.crimeType);
|
||||||
if (!crime) {
|
if (!crime) {
|
||||||
console.error(`Invalid data stored in sleeve.crimeType: ${this.crimeType}`);
|
console.error(`Invalid data stored in sleeve.crimeType: ${this.crimeType}`);
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
return retValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
if (Math.random() < crime.successRate(this)) {
|
if (Math.random() < crime.successRate(this)) {
|
||||||
@ -206,11 +222,60 @@ export class Sleeve extends Person {
|
|||||||
this.currentTaskTime = 0;
|
this.currentTaskTime = 0;
|
||||||
return retValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (this.currentTask === SleeveTaskType.Bladeburner) {
|
||||||
// For other crimes... I dont think anything else needs to be done
|
if (this.currentTaskMaxTime === 0) {
|
||||||
|
this.currentTaskTime = 0;
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
// For bladeburner, all experience and money is gained at the end
|
||||||
|
const bb = p.bladeburner;
|
||||||
|
if (bb === null) {
|
||||||
|
const errorLogText = `bladeburner is null`;
|
||||||
|
console.error(`Function: sleeves.finishTask; Message: '${errorLogText}'`);
|
||||||
|
this.resetTaskStatus(p);
|
||||||
|
return retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resetTaskStatus();
|
if (this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||||
|
if (this.bbAction === "Infiltrate synthoids") {
|
||||||
|
bb.infiltrateSynthoidCommunities(p);
|
||||||
|
this.currentTaskTime = 0;
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
let type: string;
|
||||||
|
let name: string;
|
||||||
|
if (this.bbAction === "Take on contracts") {
|
||||||
|
type = "Contracts";
|
||||||
|
name = this.bbContract;
|
||||||
|
} else {
|
||||||
|
type = "General";
|
||||||
|
name = this.bbAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionIdent = bb.getActionIdFromTypeAndName(type, name);
|
||||||
|
if (actionIdent === null) {
|
||||||
|
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||||
|
console.error(`Function: sleeves.finishTask; Message: '${errorLogText}'`);
|
||||||
|
this.resetTaskStatus(p);
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const action = bb.getActionObject(actionIdent);
|
||||||
|
if ((action?.count ?? 0) > 0) {
|
||||||
|
const bbRetValue = bb.completeAction(p, this, actionIdent, false);
|
||||||
|
if (bbRetValue) {
|
||||||
|
retValue = this.gainExperience(p, bbRetValue);
|
||||||
|
this.gainMoney(p, bbRetValue);
|
||||||
|
|
||||||
|
// Do not reset task to IDLE
|
||||||
|
this.currentTaskTime = 0;
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetTaskStatus(p);
|
||||||
|
|
||||||
return retValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
@ -260,50 +325,56 @@ export class Sleeve extends Person {
|
|||||||
const pDexExp = exp.dex * multFac;
|
const pDexExp = exp.dex * multFac;
|
||||||
const pAgiExp = exp.agi * multFac;
|
const pAgiExp = exp.agi * multFac;
|
||||||
const pChaExp = exp.cha * multFac;
|
const pChaExp = exp.cha * multFac;
|
||||||
|
const pIntExp = exp.int * multFac;
|
||||||
|
|
||||||
// Experience is gained by both this sleeve and player
|
// Experience is gained by both this sleeve and player
|
||||||
if (pHackExp > 0) {
|
if (pHackExp > 0) {
|
||||||
this.hacking_exp += pHackExp;
|
this.gainHackingExp(pHackExp);
|
||||||
p.gainHackingExp(pHackExp);
|
p.gainHackingExp(pHackExp);
|
||||||
this.earningsForPlayer.hack += pHackExp;
|
this.earningsForPlayer.hack += pHackExp;
|
||||||
this.earningsForTask.hack += pHackExp;
|
this.earningsForTask.hack += pHackExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pStrExp > 0) {
|
if (pStrExp > 0) {
|
||||||
this.strength_exp += pStrExp;
|
this.gainStrengthExp(pStrExp);
|
||||||
p.gainStrengthExp(pStrExp);
|
p.gainStrengthExp(pStrExp);
|
||||||
this.earningsForPlayer.str += pStrExp;
|
this.earningsForPlayer.str += pStrExp;
|
||||||
this.earningsForTask.str += pStrExp;
|
this.earningsForTask.str += pStrExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDefExp > 0) {
|
if (pDefExp > 0) {
|
||||||
this.defense_exp += pDefExp;
|
this.gainDefenseExp(pDefExp);
|
||||||
p.gainDefenseExp(pDefExp);
|
p.gainDefenseExp(pDefExp);
|
||||||
this.earningsForPlayer.def += pDefExp;
|
this.earningsForPlayer.def += pDefExp;
|
||||||
this.earningsForTask.def += pDefExp;
|
this.earningsForTask.def += pDefExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDexExp > 0) {
|
if (pDexExp > 0) {
|
||||||
this.dexterity_exp += pDexExp;
|
this.gainDexterityExp(pDexExp);
|
||||||
p.gainDexterityExp(pDexExp);
|
p.gainDexterityExp(pDexExp);
|
||||||
this.earningsForPlayer.dex += pDexExp;
|
this.earningsForPlayer.dex += pDexExp;
|
||||||
this.earningsForTask.dex += pDexExp;
|
this.earningsForTask.dex += pDexExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pAgiExp > 0) {
|
if (pAgiExp > 0) {
|
||||||
this.agility_exp += pAgiExp;
|
this.gainAgilityExp(pAgiExp);
|
||||||
p.gainAgilityExp(pAgiExp);
|
p.gainAgilityExp(pAgiExp);
|
||||||
this.earningsForPlayer.agi += pAgiExp;
|
this.earningsForPlayer.agi += pAgiExp;
|
||||||
this.earningsForTask.agi += pAgiExp;
|
this.earningsForTask.agi += pAgiExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pChaExp > 0) {
|
if (pChaExp > 0) {
|
||||||
this.charisma_exp += pChaExp;
|
this.gainCharismaExp(pChaExp);
|
||||||
p.gainCharismaExp(pChaExp);
|
p.gainCharismaExp(pChaExp);
|
||||||
this.earningsForPlayer.cha += pChaExp;
|
this.earningsForPlayer.cha += pChaExp;
|
||||||
this.earningsForTask.cha += pChaExp;
|
this.earningsForTask.cha += pChaExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pIntExp > 0) {
|
||||||
|
this.gainIntelligenceExp(pIntExp);
|
||||||
|
p.gainIntelligenceExp(pIntExp);
|
||||||
|
}
|
||||||
|
|
||||||
// Record earnings for other sleeves
|
// Record earnings for other sleeves
|
||||||
this.earningsForSleeves.hack += pHackExp * (this.sync / 100);
|
this.earningsForSleeves.hack += pHackExp * (this.sync / 100);
|
||||||
this.earningsForSleeves.str += pStrExp * (this.sync / 100);
|
this.earningsForSleeves.str += pStrExp * (this.sync / 100);
|
||||||
@ -320,7 +391,8 @@ export class Sleeve extends Person {
|
|||||||
dex: pDexExp * (this.sync / 100),
|
dex: pDexExp * (this.sync / 100),
|
||||||
agi: pAgiExp * (this.sync / 100),
|
agi: pAgiExp * (this.sync / 100),
|
||||||
cha: pChaExp * (this.sync / 100),
|
cha: pChaExp * (this.sync / 100),
|
||||||
money: 0,
|
int: pIntExp * (this.sync / 100),
|
||||||
|
money: exp.money,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +517,7 @@ export class Sleeve extends Person {
|
|||||||
this.charisma_exp = 0;
|
this.charisma_exp = 0;
|
||||||
|
|
||||||
// Reset task-related stuff
|
// Reset task-related stuff
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
this.earningsForSleeves = createTaskTracker();
|
this.earningsForSleeves = createTaskTracker();
|
||||||
this.earningsForPlayer = createTaskTracker();
|
this.earningsForPlayer = createTaskTracker();
|
||||||
this.shockRecovery(p);
|
this.shockRecovery(p);
|
||||||
@ -523,7 +595,7 @@ export class Sleeve extends Person {
|
|||||||
// for, we need to reset the sleeve's task
|
// for, we need to reset the sleeve's task
|
||||||
if (p.gang) {
|
if (p.gang) {
|
||||||
if (fac.name === p.gang.facName) {
|
if (fac.name === p.gang.facName) {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,18 +617,18 @@ export class Sleeve extends Person {
|
|||||||
}
|
}
|
||||||
case SleeveTaskType.Recovery:
|
case SleeveTaskType.Recovery:
|
||||||
this.shock = Math.min(100, this.shock + 0.0002 * cyclesUsed);
|
this.shock = Math.min(100, this.shock + 0.0002 * cyclesUsed);
|
||||||
if (this.shock >= 100) this.resetTaskStatus();
|
if (this.shock >= 100) this.resetTaskStatus(p);
|
||||||
break;
|
break;
|
||||||
case SleeveTaskType.Synchro:
|
case SleeveTaskType.Synchro:
|
||||||
this.sync = Math.min(100, this.sync + p.getIntelligenceBonus(0.5) * 0.0002 * cyclesUsed);
|
this.sync = Math.min(100, this.sync + p.getIntelligenceBonus(0.5) * 0.0002 * cyclesUsed);
|
||||||
if (this.sync >= 100) this.resetTaskStatus();
|
if (this.sync >= 100) this.resetTaskStatus(p);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
|
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||||
if (this.currentTask === SleeveTaskType.Crime) {
|
if (this.currentTask === SleeveTaskType.Crime || this.currentTask === SleeveTaskType.Bladeburner) {
|
||||||
retValue = this.finishTask(p);
|
retValue = this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
@ -573,7 +645,16 @@ export class Sleeve extends Person {
|
|||||||
/**
|
/**
|
||||||
* Resets all parameters used to keep information about the current task
|
* Resets all parameters used to keep information about the current task
|
||||||
*/
|
*/
|
||||||
resetTaskStatus(): void {
|
resetTaskStatus(p: IPlayer): void {
|
||||||
|
if (this.bbAction == "Support main sleeve") {
|
||||||
|
p.bladeburner?.sleeveSupport(false);
|
||||||
|
}
|
||||||
|
if (this.currentTask == SleeveTaskType.Class) {
|
||||||
|
const retVal = createTaskTracker();
|
||||||
|
retVal.int = CONSTANTS.IntelligenceClassBaseExpGain * Math.round(this.currentTaskTime / 1000);
|
||||||
|
const r = this.gainExperience(p, retVal);
|
||||||
|
p.sleeves.filter((s) => s != this).forEach((s) => s.gainExperience(p, r, 1, true));
|
||||||
|
}
|
||||||
this.earningsForTask = createTaskTracker();
|
this.earningsForTask = createTaskTracker();
|
||||||
this.gainRatesForTask = createTaskTracker();
|
this.gainRatesForTask = createTaskTracker();
|
||||||
this.currentTask = SleeveTaskType.Idle;
|
this.currentTask = SleeveTaskType.Idle;
|
||||||
@ -584,13 +665,15 @@ export class Sleeve extends Person {
|
|||||||
this.currentTaskLocation = "";
|
this.currentTaskLocation = "";
|
||||||
this.gymStatType = "";
|
this.gymStatType = "";
|
||||||
this.className = "";
|
this.className = "";
|
||||||
|
this.bbAction = "";
|
||||||
|
this.bbContract = "------";
|
||||||
}
|
}
|
||||||
|
|
||||||
shockRecovery(p: IPlayer): boolean {
|
shockRecovery(p: IPlayer): boolean {
|
||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentTask = SleeveTaskType.Recovery;
|
this.currentTask = SleeveTaskType.Recovery;
|
||||||
@ -601,7 +684,7 @@ export class Sleeve extends Person {
|
|||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentTask = SleeveTaskType.Synchro;
|
this.currentTask = SleeveTaskType.Synchro;
|
||||||
@ -615,7 +698,7 @@ export class Sleeve extends Person {
|
|||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set exp/money multipliers based on which university.
|
// Set exp/money multipliers based on which university.
|
||||||
@ -809,7 +892,7 @@ export class Sleeve extends Person {
|
|||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
const company: Company | null = Companies[companyName];
|
const company: Company | null = Companies[companyName];
|
||||||
@ -875,7 +958,7 @@ export class Sleeve extends Person {
|
|||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
const factionInfo = faction.getInfo();
|
const factionInfo = faction.getInfo();
|
||||||
@ -926,7 +1009,7 @@ export class Sleeve extends Person {
|
|||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask(p);
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set exp/money multipliers based on which university.
|
// Set exp/money multipliers based on which university.
|
||||||
@ -994,6 +1077,162 @@ export class Sleeve extends Person {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a bladeburner task
|
||||||
|
*/
|
||||||
|
bladeburner(p: IPlayer, action: string, contract: string): boolean {
|
||||||
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
|
this.finishTask(p);
|
||||||
|
} else {
|
||||||
|
this.resetTaskStatus(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gainRatesForTask.hack = 0;
|
||||||
|
this.gainRatesForTask.str = 0;
|
||||||
|
this.gainRatesForTask.def = 0;
|
||||||
|
this.gainRatesForTask.dex = 0;
|
||||||
|
this.gainRatesForTask.agi = 0;
|
||||||
|
this.gainRatesForTask.cha = 0;
|
||||||
|
this.gainRatesForTask.money = 0;
|
||||||
|
this.currentTaskLocation = "";
|
||||||
|
|
||||||
|
let time = 0;
|
||||||
|
|
||||||
|
this.bbContract = "------";
|
||||||
|
switch (action) {
|
||||||
|
case "Field analysis":
|
||||||
|
time = this.getBladeburnerActionTime(p, "General", action);
|
||||||
|
this.gainRatesForTask.hack = 20 * this.hacking_exp_mult;
|
||||||
|
this.gainRatesForTask.cha = 20 * this.charisma_exp_mult;
|
||||||
|
break;
|
||||||
|
case "Recruitment":
|
||||||
|
time = this.getBladeburnerActionTime(p, "General", action);
|
||||||
|
this.gainRatesForTask.cha =
|
||||||
|
2 * BladeburnerConstants.BaseStatGain * (p.bladeburner?.getRecruitmentTime(this) ?? 0) * 1000;
|
||||||
|
this.currentTaskLocation = `(Success Rate: ${numeralWrapper.formatPercentage(
|
||||||
|
this.recruitmentSuccessChance(p),
|
||||||
|
)})`;
|
||||||
|
break;
|
||||||
|
case "Diplomacy":
|
||||||
|
time = this.getBladeburnerActionTime(p, "General", action);
|
||||||
|
break;
|
||||||
|
case "Infiltrate synthoids":
|
||||||
|
time = 60000;
|
||||||
|
this.currentTaskLocation = "This will generate additional contracts and operations";
|
||||||
|
break;
|
||||||
|
case "Support main sleeve":
|
||||||
|
p.bladeburner?.sleeveSupport(true);
|
||||||
|
time = 0;
|
||||||
|
break;
|
||||||
|
case "Take on contracts":
|
||||||
|
time = this.getBladeburnerActionTime(p, "Contracts", contract);
|
||||||
|
this.contractGainRates(p, "Contracts", contract);
|
||||||
|
this.currentTaskLocation = this.contractSuccessChance(p, "Contracts", contract);
|
||||||
|
this.bbContract = capitalizeEachWord(contract.toLowerCase());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bbAction = capitalizeFirstLetter(action.toLowerCase());
|
||||||
|
this.currentTaskMaxTime = time;
|
||||||
|
this.currentTask = SleeveTaskType.Bladeburner;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
recruitmentSuccessChance(p: IPlayer): number {
|
||||||
|
return Math.max(0, Math.min(1, p.bladeburner?.getRecruitmentSuccessChance(this) ?? 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
contractSuccessChance(p: IPlayer, type: string, name: string): string {
|
||||||
|
const bb = p.bladeburner;
|
||||||
|
if (bb === null) {
|
||||||
|
const errorLogText = `bladeburner is null`;
|
||||||
|
console.error(`Function: sleeves.contractSuccessChance; Message: '${errorLogText}'`);
|
||||||
|
return "0%";
|
||||||
|
}
|
||||||
|
const chances = bb.getActionEstimatedSuccessChanceNetscriptFn(this, type, name);
|
||||||
|
if (typeof chances === "string") {
|
||||||
|
console.error(`Function: sleeves.contractSuccessChance; Message: '${chances}'`);
|
||||||
|
return "0%";
|
||||||
|
}
|
||||||
|
if (chances[0] >= 1) {
|
||||||
|
return "100%";
|
||||||
|
} else {
|
||||||
|
return `${numeralWrapper.formatPercentage(chances[0])} - ${numeralWrapper.formatPercentage(chances[1])}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contractGainRates(p: IPlayer, type: string, name: string): void {
|
||||||
|
const bb = p.bladeburner;
|
||||||
|
if (bb === null) {
|
||||||
|
const errorLogText = `bladeburner is null`;
|
||||||
|
console.error(`Function: sleeves.contractGainRates; Message: '${errorLogText}'`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const actionIdent = bb.getActionIdFromTypeAndName(type, name);
|
||||||
|
if (actionIdent === null) {
|
||||||
|
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||||
|
console.error(`Function: sleeves.contractGainRates; Message: '${errorLogText}'`);
|
||||||
|
this.resetTaskStatus(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const action = bb.getActionObject(actionIdent);
|
||||||
|
if (action === null) {
|
||||||
|
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||||
|
console.error(`Function: sleeves.contractGainRates; Message: '${errorLogText}'`);
|
||||||
|
this.resetTaskStatus(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const retValue = bb.getActionStats(action, true);
|
||||||
|
this.gainRatesForTask.hack = retValue.hack;
|
||||||
|
this.gainRatesForTask.str = retValue.str;
|
||||||
|
this.gainRatesForTask.def = retValue.def;
|
||||||
|
this.gainRatesForTask.dex = retValue.dex;
|
||||||
|
this.gainRatesForTask.agi = retValue.agi;
|
||||||
|
this.gainRatesForTask.cha = retValue.cha;
|
||||||
|
const rewardMultiplier = Math.pow(action.rewardFac, action.level - 1);
|
||||||
|
this.gainRatesForTask.money =
|
||||||
|
BladeburnerConstants.ContractBaseMoneyGain * rewardMultiplier * bb.skillMultipliers.money;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBladeburnerActionTime(p: IPlayer, type: string, name: string): number {
|
||||||
|
//Maybe find workerscript and use original
|
||||||
|
const bb = p.bladeburner;
|
||||||
|
if (bb === null) {
|
||||||
|
const errorLogText = `bladeburner is null`;
|
||||||
|
console.error(`Function: sleeves.getBladeburnerActionTime; Message: '${errorLogText}'`);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = bb.getActionTimeNetscriptFn(this, type, name);
|
||||||
|
if (typeof time === "string") {
|
||||||
|
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||||
|
console.error(`Function: sleeves.getBladeburnerActionTime; Message: '${errorLogText}'`);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
takeDamage(amt: number): boolean {
|
||||||
|
if (typeof amt !== "number") {
|
||||||
|
console.warn(`Player.takeDamage() called without a numeric argument: ${amt}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hp -= amt;
|
||||||
|
if (this.hp <= 0) {
|
||||||
|
this.shock += 0.5;
|
||||||
|
this.hp = this.max_hp;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
whoAmI(): string {
|
||||||
|
return "Sleeve";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize the current object to a JSON save state.
|
* Serialize the current object to a JSON save state.
|
||||||
*/
|
*/
|
||||||
|
@ -9,6 +9,7 @@ export enum SleeveTaskType {
|
|||||||
Crime,
|
Crime,
|
||||||
Class,
|
Class,
|
||||||
Gym,
|
Gym,
|
||||||
|
Bladeburner,
|
||||||
Recovery,
|
Recovery,
|
||||||
Synchro,
|
Synchro,
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
const [abc, setABC] = useState(["------", "------", "------"]);
|
const [abc, setABC] = useState(["------", "------", "------"]);
|
||||||
|
|
||||||
function setTask(): void {
|
function setTask(): void {
|
||||||
props.sleeve.resetTaskStatus(); // sets to idle
|
props.sleeve.resetTaskStatus(player); // sets to idle
|
||||||
switch (abc[0]) {
|
switch (abc[0]) {
|
||||||
case "------":
|
case "------":
|
||||||
break;
|
break;
|
||||||
@ -49,6 +49,9 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
case "Workout at Gym":
|
case "Workout at Gym":
|
||||||
props.sleeve.workoutAtGym(player, abc[2], abc[1]);
|
props.sleeve.workoutAtGym(player, abc[2], abc[1]);
|
||||||
break;
|
break;
|
||||||
|
case "Perform Bladeburner Actions":
|
||||||
|
props.sleeve.bladeburner(player, abc[1], abc[2]);
|
||||||
|
break;
|
||||||
case "Shock Recovery":
|
case "Shock Recovery":
|
||||||
props.sleeve.shockRecovery(player);
|
props.sleeve.shockRecovery(player);
|
||||||
break;
|
break;
|
||||||
@ -106,6 +109,20 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
case SleeveTaskType.Gym:
|
case SleeveTaskType.Gym:
|
||||||
desc = <>This sleeve is currently working out at {props.sleeve.currentTaskLocation}.</>;
|
desc = <>This sleeve is currently working out at {props.sleeve.currentTaskLocation}.</>;
|
||||||
break;
|
break;
|
||||||
|
case SleeveTaskType.Bladeburner: {
|
||||||
|
let message = "";
|
||||||
|
if (props.sleeve.bbContract !== "------") {
|
||||||
|
message = ` - ${props.sleeve.bbContract} (Success Rate: ${props.sleeve.currentTaskLocation})`;
|
||||||
|
} else if (props.sleeve.currentTaskLocation !== "") {
|
||||||
|
message = props.sleeve.currentTaskLocation;
|
||||||
|
}
|
||||||
|
desc = (
|
||||||
|
<>
|
||||||
|
This sleeve is currently attempting to {props.sleeve.bbAction}. {message}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SleeveTaskType.Recovery:
|
case SleeveTaskType.Recovery:
|
||||||
desc = (
|
desc = (
|
||||||
<>
|
<>
|
||||||
@ -168,7 +185,9 @@ export function SleeveElem(props: IProps): React.ReactElement {
|
|||||||
</Button>
|
</Button>
|
||||||
<Typography>{desc}</Typography>
|
<Typography>{desc}</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{props.sleeve.currentTask === SleeveTaskType.Crime && (
|
{(props.sleeve.currentTask === SleeveTaskType.Crime ||
|
||||||
|
props.sleeve.currentTask === SleeveTaskType.Bladeburner) &&
|
||||||
|
props.sleeve.currentTaskMaxTime > 0 && (
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
value={(props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime) * 100}
|
value={(props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime) * 100}
|
||||||
|
@ -22,6 +22,15 @@ const universitySelectorOptions: string[] = [
|
|||||||
|
|
||||||
const gymSelectorOptions: string[] = ["Train Strength", "Train Defense", "Train Dexterity", "Train Agility"];
|
const gymSelectorOptions: string[] = ["Train Strength", "Train Defense", "Train Dexterity", "Train Agility"];
|
||||||
|
|
||||||
|
const bladeburnerSelectorOptions: string[] = [
|
||||||
|
"Field analysis",
|
||||||
|
"Recruitment",
|
||||||
|
"Diplomacy",
|
||||||
|
"Infiltrate synthoids",
|
||||||
|
"Support main sleeve",
|
||||||
|
"Take on contracts",
|
||||||
|
];
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
sleeve: Sleeve;
|
sleeve: Sleeve;
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
@ -84,6 +93,26 @@ function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function possibleContracts(player: IPlayer, sleeve: Sleeve): string[] {
|
||||||
|
const bb = player.bladeburner;
|
||||||
|
if (bb === null) {
|
||||||
|
return ["------"];
|
||||||
|
}
|
||||||
|
let contracts = bb.getContractNamesNetscriptFn();
|
||||||
|
for (const otherSleeve of player.sleeves) {
|
||||||
|
if (sleeve === otherSleeve) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (otherSleeve.currentTask === SleeveTaskType.Bladeburner && otherSleeve.bbAction == "Take on contracts") {
|
||||||
|
contracts = contracts.filter((x) => x != otherSleeve.bbContract);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contracts.length === 0) {
|
||||||
|
return ["------"];
|
||||||
|
}
|
||||||
|
return contracts;
|
||||||
|
}
|
||||||
|
|
||||||
const tasks: {
|
const tasks: {
|
||||||
[key: string]: undefined | ((player: IPlayer, sleeve: Sleeve) => ITaskDetails);
|
[key: string]: undefined | ((player: IPlayer, sleeve: Sleeve) => ITaskDetails);
|
||||||
["------"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
["------"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
@ -92,6 +121,7 @@ const tasks: {
|
|||||||
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
|
["Perform Bladeburner Actions"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
|
||||||
} = {
|
} = {
|
||||||
@ -170,6 +200,18 @@ const tasks: {
|
|||||||
|
|
||||||
return { first: gymSelectorOptions, second: () => gyms };
|
return { first: gymSelectorOptions, second: () => gyms };
|
||||||
},
|
},
|
||||||
|
"Perform Bladeburner Actions": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
|
||||||
|
return {
|
||||||
|
first: bladeburnerSelectorOptions,
|
||||||
|
second: (s1: string) => {
|
||||||
|
if (s1 === "Take on contracts") {
|
||||||
|
return possibleContracts(player, sleeve);
|
||||||
|
} else {
|
||||||
|
return ["------"];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
"Shock Recovery": (): ITaskDetails => {
|
"Shock Recovery": (): ITaskDetails => {
|
||||||
return { first: ["------"], second: () => ["------"] };
|
return { first: ["------"], second: () => ["------"] };
|
||||||
},
|
},
|
||||||
@ -186,6 +228,7 @@ const canDo: {
|
|||||||
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
||||||
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
||||||
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
||||||
|
["Perform Bladeburner Actions"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
||||||
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
||||||
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => boolean;
|
||||||
} = {
|
} = {
|
||||||
@ -197,6 +240,7 @@ const canDo: {
|
|||||||
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
|
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
|
||||||
"Workout at Gym": (player: IPlayer, sleeve: Sleeve) =>
|
"Workout at Gym": (player: IPlayer, sleeve: Sleeve) =>
|
||||||
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
|
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
|
||||||
|
"Perform Bladeburner Actions": (player: IPlayer, _: Sleeve) => player.inBladeburner(),
|
||||||
"Shock Recovery": (player: IPlayer, sleeve: Sleeve) => sleeve.shock < 100,
|
"Shock Recovery": (player: IPlayer, sleeve: Sleeve) => sleeve.shock < 100,
|
||||||
Synchronize: (player: IPlayer, sleeve: Sleeve) => sleeve.sync < 100,
|
Synchronize: (player: IPlayer, sleeve: Sleeve) => sleeve.sync < 100,
|
||||||
};
|
};
|
||||||
@ -228,6 +272,8 @@ function getABC(sleeve: Sleeve): [string, string, string] {
|
|||||||
return ["Take University Course", sleeve.className, sleeve.currentTaskLocation];
|
return ["Take University Course", sleeve.className, sleeve.currentTaskLocation];
|
||||||
case SleeveTaskType.Gym:
|
case SleeveTaskType.Gym:
|
||||||
return ["Workout at Gym", sleeve.gymStatType, sleeve.currentTaskLocation];
|
return ["Workout at Gym", sleeve.gymStatType, sleeve.currentTaskLocation];
|
||||||
|
case SleeveTaskType.Bladeburner:
|
||||||
|
return ["Perform Bladeburner Actions", sleeve.bbAction, sleeve.bbContract];
|
||||||
case SleeveTaskType.Recovery:
|
case SleeveTaskType.Recovery:
|
||||||
return ["Shock Recovery", "------", "------"];
|
return ["Shock Recovery", "------", "------"];
|
||||||
case SleeveTaskType.Synchro:
|
case SleeveTaskType.Synchro:
|
||||||
|
@ -26,7 +26,7 @@ export function TravelModal(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
props.sleeve.city = city as CityName;
|
props.sleeve.city = city as CityName;
|
||||||
player.loseMoney(CONSTANTS.TravelCost, "sleeve");
|
player.loseMoney(CONSTANTS.TravelCost, "sleeve");
|
||||||
props.sleeve.resetTaskStatus();
|
props.sleeve.resetTaskStatus(player);
|
||||||
props.rerender();
|
props.rerender();
|
||||||
props.onClose();
|
props.onClose();
|
||||||
}
|
}
|
||||||
|
14
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
14
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -3789,6 +3789,20 @@ export interface Sleeve {
|
|||||||
* @returns True if the aug was purchased and installed on the sleeve, false otherwise.
|
* @returns True if the aug was purchased and installed on the sleeve, false otherwise.
|
||||||
*/
|
*/
|
||||||
purchaseSleeveAug(sleeveNumber: number, augName: string): boolean;
|
purchaseSleeveAug(sleeveNumber: number, augName: string): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a sleeve to perform bladeburner actions.
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: 4 GB
|
||||||
|
*
|
||||||
|
* Return a boolean indicating whether or not the sleeve started working out.
|
||||||
|
*
|
||||||
|
* @param sleeveNumber - Index of the sleeve to workout at the gym.
|
||||||
|
* @param action - Name of the action to be performed.
|
||||||
|
* @param contract - Name of the contract if applicable.
|
||||||
|
* @returns True if the sleeve started working out, false otherwise.
|
||||||
|
*/
|
||||||
|
setToBladeburnerAction(sleeveNumber: number, action: string, contract?: string): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,6 +117,17 @@ function cyrb53(str: string, seed = 0): string {
|
|||||||
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
|
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function capitalizeFirstLetter(s: string): string {
|
||||||
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function capitalizeEachWord(s: string): string {
|
||||||
|
return s
|
||||||
|
.split(" ")
|
||||||
|
.map((word) => capitalizeFirstLetter(word))
|
||||||
|
.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
convertTimeMsToTimeElapsedString,
|
convertTimeMsToTimeElapsedString,
|
||||||
longestCommonStart,
|
longestCommonStart,
|
||||||
@ -124,4 +135,6 @@ export {
|
|||||||
formatNumber,
|
formatNumber,
|
||||||
generateRandomString,
|
generateRandomString,
|
||||||
cyrb53,
|
cyrb53,
|
||||||
|
capitalizeFirstLetter,
|
||||||
|
capitalizeEachWord,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user