mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-25 02:32:55 +02:00
Added BitNode multipliers for purchased servers. Fixed bugs in new Script Editor implementation. Added documentation for script editors
This commit is contained in:
@@ -16,6 +16,7 @@ import { Person,
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
|
||||
import { Crime } from "../../Crime/Crime";
|
||||
import { Crimes } from "../../Crime/Crimes";
|
||||
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
|
||||
@@ -42,6 +43,12 @@ export class Sleeve extends Person {
|
||||
return Generic_fromJSON(Sleeve, value.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the type of crime the sleeve is currently attempting
|
||||
* Must match the name of a Crime object
|
||||
*/
|
||||
crimeType: string = "";
|
||||
|
||||
/**
|
||||
* Enum value for current task
|
||||
*/
|
||||
@@ -136,8 +143,10 @@ export class Sleeve extends Person {
|
||||
/**
|
||||
* Commit crimes
|
||||
*/
|
||||
commitCrime(p: IPlayer, crime: Crime): boolean {
|
||||
commitCrime(p: IPlayer, crimeKey: string): boolean {
|
||||
const crime: Crime | null = Crimes[crimeKey];
|
||||
if (!(crime instanceof Crime)) { return false; }
|
||||
|
||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||
this.finishTask(p);
|
||||
} else {
|
||||
@@ -154,19 +163,7 @@ export class Sleeve extends Person {
|
||||
|
||||
this.currentTaskLocation = String(this.gainRatesForTask.money);
|
||||
|
||||
// We'll determine success now and adjust the earnings accordingly
|
||||
if (Math.random() < crime.successRate(p)) {
|
||||
this.gainRatesForTask.hack *= 2;
|
||||
this.gainRatesForTask.str *= 2;
|
||||
this.gainRatesForTask.def *= 2;
|
||||
this.gainRatesForTask.dex *= 2;
|
||||
this.gainRatesForTask.agi *= 2;
|
||||
this.gainRatesForTask.cha *= 2;
|
||||
} else {
|
||||
this.gainRatesForTask.money = 0;
|
||||
}
|
||||
|
||||
|
||||
this.crimeType = crimeKey;
|
||||
this.currentTaskMaxTime = crime.time;
|
||||
this.currentTask = SleeveTaskType.Crime;
|
||||
return true;
|
||||
@@ -181,8 +178,26 @@ export class Sleeve extends Person {
|
||||
if (this.currentTask === SleeveTaskType.Crime) {
|
||||
// For crimes, all experience and money is gained at the end
|
||||
if (this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||
retValue = this.gainExperience(p, this.gainRatesForTask);
|
||||
this.gainMoney(p, this.gainRatesForTask);
|
||||
const crime: Crime | null = Crimes[this.crimeType];
|
||||
if (!(crime instanceof Crime)) {
|
||||
console.error(`Invalid data stored in sleeve.crimeType: ${this.crimeType}`);
|
||||
this.resetTaskStatus();
|
||||
return retValue;
|
||||
}
|
||||
if (Math.random() < crime.successRate(p)) {
|
||||
// Success
|
||||
const successGainRates: ITaskTracker = createTaskTracker();
|
||||
|
||||
const keysForIteration: (keyof ITaskTracker)[] = (<(keyof ITaskTracker)[]>Object.keys(successGainRates));
|
||||
for (let i = 0; i < keysForIteration.length; ++i) {
|
||||
const key = keysForIteration[i];
|
||||
successGainRates[key] = this.gainRatesForTask[key] * 2;
|
||||
}
|
||||
retValue = this.gainExperience(p, successGainRates);
|
||||
this.gainMoney(p, this.gainRatesForTask);
|
||||
} else {
|
||||
retValue = this.gainExperience(p, this.gainRatesForTask);
|
||||
}
|
||||
|
||||
// Do not reset task to IDLE
|
||||
this.currentTaskTime = 0;
|
||||
@@ -261,7 +276,7 @@ export class Sleeve extends Person {
|
||||
this.defense_exp += pDefExp;
|
||||
p.gainDefenseExp(pDefExp);
|
||||
this.earningsForPlayer.def += pDefExp;
|
||||
this.earningsForTask.dex += pDefExp;
|
||||
this.earningsForTask.def += pDefExp;
|
||||
}
|
||||
|
||||
if (pDexExp > 0) {
|
||||
@@ -464,6 +479,9 @@ export class Sleeve extends Person {
|
||||
this.currentTaskTime = 0;
|
||||
this.currentTaskMaxTime = 0;
|
||||
this.factionWorkType = FactionWorkType.None;
|
||||
this.crimeType = "";
|
||||
this.currentTaskLocation = "";
|
||||
this.gymStatType = "";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -630,12 +648,16 @@ export class Sleeve extends Person {
|
||||
this.resetTaskStatus();
|
||||
}
|
||||
|
||||
const factionInfo = Factions[factionName].getInfo();
|
||||
|
||||
// Set type of work (hacking/field/security), and the experience gains
|
||||
const sanitizedWorkType: string = workType.toLowerCase();
|
||||
if (sanitizedWorkType.includes("hack")) {
|
||||
if (!factionInfo.offerHackingWork) { return false; }
|
||||
this.factionWorkType = FactionWorkType.Hacking;
|
||||
this.gainRatesForTask.hack = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
} else if (sanitizedWorkType.includes("field")) {
|
||||
if (!factionInfo.offerFieldWork) { return false; }
|
||||
this.factionWorkType = FactionWorkType.Field;
|
||||
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
this.gainRatesForTask.str = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
@@ -644,6 +666,7 @@ export class Sleeve extends Person {
|
||||
this.gainRatesForTask.agi = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
this.gainRatesForTask.cha = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
} else if (sanitizedWorkType.includes("security")) {
|
||||
if (!factionInfo.offerSecurityWork) { return false; }
|
||||
this.factionWorkType = FactionWorkType.Security;
|
||||
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
this.gainRatesForTask.str = .15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
|
||||
@@ -10,8 +10,12 @@ import { IPlayer } from "../IPlayer";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { Locations } from "../../Locations";
|
||||
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
|
||||
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
import { Crime } from "../../Crime/Crime";
|
||||
import { Crimes } from "../../Crime/Crimes";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
@@ -23,6 +27,7 @@ import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
||||
import { exceptionAlert } from "../../../utils/helpers/exceptionAlert";
|
||||
|
||||
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners";
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { createPopup } from "../../../utils/uiHelpers/createPopup";
|
||||
@@ -229,7 +234,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
popupArguments.push(createElement("p", {
|
||||
innerText: "Have this sleeve travel to a different city. This affects " +
|
||||
"the gyms and universities at which this sleeve can study. " +
|
||||
`Traveling to a different city costs ${numeralWrapper.formatMoney(CONSTANTS.TravelCost)}.` +
|
||||
`Traveling to a different city costs ${numeralWrapper.formatMoney(CONSTANTS.TravelCost)}. ` +
|
||||
"It will also CANCEL the sleeve's current task (setting it to idle)",
|
||||
}));
|
||||
for (const label in Cities) {
|
||||
@@ -250,6 +255,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
sleeve.resetTaskStatus();
|
||||
removeElementById(popupId);
|
||||
updateSleeveUi(sleeve, elems);
|
||||
updateSleeveTaskSelector(sleeve, elems, allSleeves);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
@@ -401,12 +407,6 @@ function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
|
||||
}
|
||||
}
|
||||
|
||||
const factionWorkTypeSelectorOptions: string[] = [
|
||||
"Hacking Contracts",
|
||||
"Security Work",
|
||||
"Field Work"
|
||||
];
|
||||
|
||||
const universitySelectorOptions: string[] = [
|
||||
"Study Computer Science",
|
||||
"Data Structures",
|
||||
@@ -450,6 +450,7 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
// Reset Selectors
|
||||
removeChildrenFromElement(elems.taskDetailsSelector);
|
||||
removeChildrenFromElement(elems.taskDetailsSelector2);
|
||||
elems.taskDetailsSelector2 = clearEventListeners(elems.taskDetailsSelector2!) as HTMLSelectElement;
|
||||
|
||||
const value: string = getSelectValue(elems.taskSelector);
|
||||
switch(value) {
|
||||
@@ -486,29 +487,57 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
++factionCount;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < factionWorkTypeSelectorOptions.length; ++i) {
|
||||
elems.taskDetailsSelector2!.add(createOptionElement(factionWorkTypeSelectorOptions[i]));
|
||||
}
|
||||
|
||||
// Set initial value for faction work type
|
||||
switch (sleeve.factionWorkType) {
|
||||
case FactionWorkType.Hacking:
|
||||
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||
break;
|
||||
case FactionWorkType.Security:
|
||||
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||
break;
|
||||
case FactionWorkType.Field:
|
||||
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// The available faction work types depends on the faction
|
||||
elems.taskDetailsSelector!.addEventListener("change", () => {
|
||||
const facName = getSelectValue(elems.taskDetailsSelector!);
|
||||
const faction: Faction | null = Factions[facName];
|
||||
if (faction == null) {
|
||||
console.warn(`Invalid faction name when trying to update Sleeve Task Selector: ${facName}`);
|
||||
return;
|
||||
}
|
||||
const facInfo = faction.getInfo();
|
||||
removeChildrenFromElement(elems.taskDetailsSelector2!);
|
||||
let numOptionsAdded = 0;
|
||||
if (facInfo.offerHackingWork) {
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("Hacking Contracts"));
|
||||
if (sleeve.factionWorkType === FactionWorkType.Hacking) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = numOptionsAdded;
|
||||
}
|
||||
++numOptionsAdded;
|
||||
}
|
||||
if (facInfo.offerFieldWork) {
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("Field Work"));
|
||||
if (sleeve.factionWorkType === FactionWorkType.Field) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = numOptionsAdded;
|
||||
}
|
||||
++numOptionsAdded;
|
||||
}
|
||||
if (facInfo.offerSecurityWork) {
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("Security Work"));
|
||||
if (sleeve.factionWorkType === FactionWorkType.Security) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = numOptionsAdded;
|
||||
}
|
||||
++numOptionsAdded;
|
||||
}
|
||||
});
|
||||
elems.taskDetailsSelector!.dispatchEvent(new Event("change"));
|
||||
break;
|
||||
case "Commit Crime":
|
||||
let i = 0;
|
||||
for (const crimeLabel in Crimes) {
|
||||
const name: string = Crimes[crimeLabel].name;
|
||||
elems.taskDetailsSelector!.add(createOptionElement(name, crimeLabel));
|
||||
|
||||
// Set initial value for crime type
|
||||
if (sleeve.crimeType === "") { continue; }
|
||||
const crime: Crime | null = Crimes[sleeve.crimeType];
|
||||
if (crime == null) { continue; }
|
||||
if (name === crime!.name) {
|
||||
elems.taskDetailsSelector!.selectedIndex = i;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||
@@ -614,7 +643,7 @@ function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): boolean {
|
||||
res = sleeve.workForFaction(playerRef!, detailValue, detailValue2);
|
||||
break;
|
||||
case "Commit Crime":
|
||||
res = sleeve.commitCrime(playerRef!, Crimes[detailValue]);
|
||||
res = sleeve.commitCrime(playerRef!, detailValue);
|
||||
break;
|
||||
case "Take University Course":
|
||||
res = sleeve.takeUniversityCourse(playerRef!, detailValue2, detailValue);
|
||||
@@ -637,7 +666,15 @@ function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): boolean {
|
||||
if (res) {
|
||||
updateSleeveTaskDescription(sleeve, elems);
|
||||
} else {
|
||||
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
|
||||
switch (taskValue) {
|
||||
case "Work for Faction":
|
||||
elems.taskDescription!.innerText = "Failed to assign sleeve to task. This is most likely because the selected faction does not offer the selected work type.";
|
||||
break;
|
||||
default:
|
||||
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (routing.isOn(Page.Sleeves)) {
|
||||
@@ -672,16 +709,13 @@ function updateSleeveTaskDescription(sleeve: Sleeve, elems: ISleeveUIElems): voi
|
||||
elems.taskDescription!.innerText = "This sleeve is currently idle";
|
||||
break;
|
||||
case "Work for Company":
|
||||
elems.taskDescription!.innerText = `This sleeve is currently working your ` +
|
||||
`job at ${sleeve.currentTaskLocation}.`;
|
||||
elems.taskDescription!.innerText = `This sleeve is currently working your job at ${sleeve.currentTaskLocation}.`;
|
||||
break;
|
||||
case "Work for Faction":
|
||||
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ` +
|
||||
`${sleeve.currentTaskLocation}.`;
|
||||
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ${sleeve.currentTaskLocation}.`;
|
||||
break;
|
||||
case "Commit Crime":
|
||||
elems.taskDescription!.innerText = `This sleeve is currently attempting to ` +
|
||||
`${Crimes[detailValue].type}.`;
|
||||
elems.taskDescription!.innerText = `This sleeve is currently attempting to ${Crimes[detailValue].type} (Success Rate: ${numeralWrapper.formatPercentage(Crimes[detailValue].successRate(playerRef))}).`;
|
||||
break;
|
||||
case "Take University Course":
|
||||
elems.taskDescription!.innerText = `This sleeve is currently studying/taking a course at ${sleeve.currentTaskLocation}.`;
|
||||
|
||||
Reference in New Issue
Block a user