mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-23 22:52:29 +01:00
More bug fixes for Sleeve/Resleeve features. Rebalancing for Sleeve/Resleeve and stock market. Added an option to remove source files in the dev menu
This commit is contained in:
parent
5573e778bb
commit
a2237d4319
@ -31,13 +31,12 @@
|
||||
border: 1px solid #fff;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.bladeburner-nav-button {
|
||||
@extend %bladeburner-nav-button;
|
||||
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #3d4044;
|
||||
}
|
||||
|
3986
dist/engine.bundle.js
vendored
3986
dist/engine.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
9
dist/engine.css
vendored
9
dist/engine.css
vendored
@ -2054,12 +2054,11 @@ button {
|
||||
.bladeburner-nav-button, .bladeburner-nav-button-inactive {
|
||||
border: 1px solid #fff;
|
||||
margin: 2px;
|
||||
padding: 2px; }
|
||||
|
||||
.bladeburner-nav-button {
|
||||
padding: 2px;
|
||||
color: #fff; }
|
||||
.bladeburner-nav-button:hover {
|
||||
background-color: #3d4044; }
|
||||
|
||||
.bladeburner-nav-button:hover {
|
||||
background-color: #3d4044; }
|
||||
|
||||
.bladeburner-nav-button-inactive {
|
||||
text-decoration: none;
|
||||
|
400
dist/vendor.bundle.js
vendored
400
dist/vendor.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
@ -52,3 +52,16 @@ it decreases by assigning sleeves to the 'Shock Recovery' task.
|
||||
|
||||
Re-sleeving
|
||||
^^^^^^^^^^^
|
||||
Re-sleeving is the process of digitizing and transferring your consciousness into a
|
||||
new human body, or "sleeve". When you re-sleeve into a new body, your stat experience
|
||||
and Augmentations get replaced with those of the new body.
|
||||
|
||||
In order to re-sleeve, you must purchase new bodies. This can be done at VitaLife in
|
||||
New Tokyo. Once you purchase a body to re-sleeve into, the effects will take
|
||||
place immediately.
|
||||
|
||||
Note that resleeving **REMOVES** all of your currently-installed Augmentations,
|
||||
and replaces them with the ones provided by the purchased sleeve. However,
|
||||
Augmentations that are purchased but not installed will **not** be removed. If you have purchased
|
||||
an Augmentation and then re-sleeve into a body which already has that Augmentation,
|
||||
it will be removed since you cannot have duplicate Augmentations.
|
||||
|
@ -26,7 +26,7 @@ List of all Source-Files
|
||||
| | * Increases the player's charisma and company salary multipliers by 8%/12%/14% |
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
| BitNode-4: The Singularity | * Lets the player access and use Netscript Singularity Functions in other BitNodes. |
|
||||
| | Each level of this Source-File opens up more of the Singularity Functions to use |
|
||||
| | * Each level of this Source-File opens up more of the Singularity Functions to use |
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
| BitNode-5: Artificial Intelligence | * Unlocks :ref:`gameplay_intelligence` |
|
||||
| | * Unlocks getBitNodeMultipliers() Netscript function |
|
||||
@ -56,7 +56,7 @@ List of all Source-Files
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
| BitNode-12: The Recursion | * There is no maximum level for this Source-File |
|
||||
| | * Each level of this Source-File increases all of the player's multipliers by 1%. |
|
||||
| | This affect is multiplicative with itself. This means that level N of this |
|
||||
| | * This affect is multiplicative with itself. This means that level N of this |
|
||||
| | Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers |
|
||||
| | that decrease) |
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
|
@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
version = '0.43'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0'
|
||||
release = '0.43.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@ -94,6 +94,9 @@ todo_include_todos = True
|
||||
#
|
||||
#html_theme = 'agogo'
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme_options = {
|
||||
"navigation_depth": 5,
|
||||
}
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
@ -179,7 +182,10 @@ texinfo_documents = [
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
|
||||
|
||||
def setup(app):
|
||||
print("Initializing (setup())");
|
||||
app.add_stylesheet('maxwidthoverride.css')
|
||||
|
3
doc/source/ystatic/maxwidthoverride.css
Normal file
3
doc/source/ystatic/maxwidthoverride.css
Normal file
@ -0,0 +1,3 @@
|
||||
.wy-nav-content {
|
||||
max-width: none;
|
||||
}
|
@ -94,8 +94,8 @@ let NetscriptFunctions =
|
||||
"installAugmentations|" +
|
||||
|
||||
// TIX API
|
||||
"getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|" +
|
||||
"shortStock|sellShort|" +
|
||||
"getStockPrice|getStockPosition|getStockSymbols|getStockMaxShares|" +
|
||||
"buyStock|sellStock|shortStock|sellShort|" +
|
||||
"placeOrder|cancelOrder|getOrders|getStockVolatility|getStockForecast|" +
|
||||
"purchase4SMarketData|purchase4SMarketDataTixApi|" +
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Augmentation } from "./Augmentation";
|
||||
import { Augmentations } from "./Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "./PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "./data/AugmentationNames";
|
||||
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
@ -11,7 +12,8 @@ import { addWorkerScript } from "../NetscriptWorker";
|
||||
import { Player } from "../Player";
|
||||
import { prestigeAugmentation } from "../Prestige";
|
||||
import { saveObject } from "../SaveObject";
|
||||
import { Script , RunningScript} from "../Script";
|
||||
import { Script,
|
||||
RunningScript} from "../Script";
|
||||
import { Server } from "../Server";
|
||||
import { OwnedAugmentationsOrderSetting } from "../SettingEnums";
|
||||
import { Settings } from "../Settings";
|
||||
|
@ -19,7 +19,7 @@ export let CONSTANTS: IMap<any> = {
|
||||
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
|
||||
BaseCostFor1GBOfRamHacknetNode: 30000,
|
||||
|
||||
TravelCost: 200000,
|
||||
TravelCost: 200e3,
|
||||
|
||||
BaseCostForHacknetNode: 1000,
|
||||
BaseCostForHacknetNodeCore: 500000,
|
||||
@ -130,7 +130,7 @@ export let CONSTANTS: IMap<any> = {
|
||||
WSEAccountCost: 200e6,
|
||||
TIXAPICost: 5e9,
|
||||
MarketData4SCost: 1e9,
|
||||
MarketDataTixApi4SCost: 20e9,
|
||||
MarketDataTixApi4SCost: 25e9,
|
||||
StockMarketCommission: 100e3,
|
||||
|
||||
//Hospital/Health
|
||||
@ -512,10 +512,11 @@ export let CONSTANTS: IMap<any> = {
|
||||
`
|
||||
v0.43.0
|
||||
* Added BitNode-10: Digital Carbon
|
||||
|
||||
|
||||
* Stock Market Changes:
|
||||
** Each stock now has a maximum number of shares you can purchase (both Long and Short positions combined)
|
||||
** Added getStockMaxShares() Netscript function to the TIX API
|
||||
** The cost of 4S Market Data TIX API Access increased from $20b to $25b
|
||||
|
||||
* Job Changes:
|
||||
** You can now hold multiple jobs at once. This means you no longer lose reputation when leaving a company
|
||||
|
@ -9,10 +9,14 @@ import { StockMarket,
|
||||
SymbolToStockMap } from "./StockMarket/StockMarket";
|
||||
import { Stock } from "./StockMarket/Stock";
|
||||
import { Terminal } from "./Terminal";
|
||||
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
|
||||
import { getSelectText } from "../utils/uiHelpers/getSelectData";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
const devMenuContainerId = "dev-menu-container";
|
||||
@ -222,7 +226,7 @@ export function createDevMenu() {
|
||||
innerText: "Receive Invite to Faction",
|
||||
});
|
||||
|
||||
// Augmentations / Source Files
|
||||
// Augmentations
|
||||
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
|
||||
|
||||
const augmentationsDropdown = createElement("select", {
|
||||
@ -242,6 +246,32 @@ export function createDevMenu() {
|
||||
innerText: "Queue Augmentation",
|
||||
})
|
||||
|
||||
// Source Files
|
||||
const sourceFilesHeader = createElement("h2", { innerText: "Source-Files" });
|
||||
|
||||
const removeSourceFileDropdown = createElement("select", {
|
||||
class: "dropdown",
|
||||
margin: "5px",
|
||||
});
|
||||
for (let i = 0; i < 24; ++i) {
|
||||
removeSourceFileDropdown.add(createOptionElement(String(i)));
|
||||
}
|
||||
|
||||
const removeSourceFileButton = createElement("button", {
|
||||
class: "std-button",
|
||||
clickListener: () => {
|
||||
const numToRemove = parseInt(getSelectText(removeSourceFileDropdown));
|
||||
for (let i = 0; i < Player.sourceFiles.length; ++i) {
|
||||
if (Player.sourceFiles[i].n === numToRemove) {
|
||||
Player.sourceFiles.splice(i, 1);
|
||||
hackWorldDaemon(Player.bitNodeN, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
innerText: "Remove Source File and Trigger Bitflume",
|
||||
});
|
||||
|
||||
// Programs
|
||||
const programsHeader = createElement("h2", {innerText: "Programs"});
|
||||
|
||||
@ -508,6 +538,9 @@ export function createDevMenu() {
|
||||
devMenuContainer.appendChild(augmentationsHeader);
|
||||
devMenuContainer.appendChild(augmentationsDropdown);
|
||||
devMenuContainer.appendChild(augmentationsQueueButton);
|
||||
devMenuContainer.appendChild(sourceFilesHeader);
|
||||
devMenuContainer.appendChild(removeSourceFileDropdown);
|
||||
devMenuContainer.appendChild(removeSourceFileButton);
|
||||
devMenuContainer.appendChild(programsHeader);
|
||||
devMenuContainer.appendChild(programsAddDropdown);
|
||||
devMenuContainer.appendChild(programsAddButton);
|
||||
|
@ -347,6 +347,9 @@ function processNetscript1Imports(code, workerScript) {
|
||||
ImportDeclaration: (node) => {
|
||||
hasImports = true;
|
||||
let scriptName = node.source.value;
|
||||
if (scriptName.startsWith("./")) {
|
||||
scriptName = scriptName.slice(2);
|
||||
}
|
||||
let script = getScript(scriptName);
|
||||
if (script == null) {
|
||||
throw new Error("'Import' failed due to invalid script: " + scriptName);
|
||||
|
@ -6,7 +6,6 @@ import { Person } from "../Person";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
|
||||
|
||||
@ -24,10 +23,10 @@ export class Resleeve extends Person {
|
||||
|
||||
getCost(): number {
|
||||
// Each experience point adds this to the cost
|
||||
const CostPerExp: number = 4;
|
||||
const CostPerExp: number = 10e3;
|
||||
|
||||
// Final cost is multiplied by # Augs ^ this constant
|
||||
const NumAugsExponent: number = 1.05;
|
||||
// Final cost is multiplied by this constant ^ # Augs
|
||||
const NumAugsExponent: number = 1.12;
|
||||
|
||||
// Get total exp in this re-sleeve
|
||||
let totalExp: number = this.hacking_exp +
|
||||
@ -48,7 +47,7 @@ export class Resleeve extends Person {
|
||||
totalAugmentationCost += aug!.baseCost;
|
||||
}
|
||||
|
||||
return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(this.augmentations.length, NumAugsExponent));
|
||||
return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(NumAugsExponent, this.augmentations.length));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ export function purchaseResleeve(r: Resleeve, p: IPlayer): boolean {
|
||||
for (let i = p.queuedAugmentations.length - 1; i >= 0; --i) {
|
||||
const name: string = p.queuedAugmentations[i].name;
|
||||
|
||||
if (p.augmentations.filter((e: IPlayerOwnedAugmentation) => {e.name !== AugmentationNames.NeuroFluxGovernor && e.name === name}).length >= 1) {
|
||||
if (p.augmentations.filter((e: IPlayerOwnedAugmentation) => {return e.name !== AugmentationNames.NeuroFluxGovernor && e.name === name}).length >= 1) {
|
||||
p.queuedAugmentations.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ export function createResleevesPage(p: IPlayer) {
|
||||
"into a new human body, or 'sleeve'. Here at VitaLife, you can purchase new " +
|
||||
"specially-engineered bodies for the re-sleeve process. Many of these bodies " +
|
||||
"even come with genetic and cybernetic Augmentations!<br><br>" +
|
||||
"Re-sleeving will chance your experience for every stat. It will also REMOVE " +
|
||||
"Re-sleeving will change your experience for every stat. It will also REMOVE " +
|
||||
"all of your currently-installed Augmentations, and replace " +
|
||||
"them with the ones provided by the purchased sleeve. However, Augmentations that you have " +
|
||||
"purchased but not installed will NOT be removed. If you have purchased an " +
|
||||
|
@ -92,6 +92,11 @@ export class Sleeve extends Person {
|
||||
*/
|
||||
gainRatesForTask: ITaskTracker = createTaskTracker();
|
||||
|
||||
/**
|
||||
* String that stores what stat the sleeve is training at the gym
|
||||
*/
|
||||
gymStatType: string = "";
|
||||
|
||||
/**
|
||||
* Keeps track of events/notifications for this sleeve
|
||||
*/
|
||||
@ -196,7 +201,37 @@ export class Sleeve extends Person {
|
||||
* Earn experience for any stats (supports multiple)
|
||||
* This function also handles experience propogating to Player and other sleeves
|
||||
*/
|
||||
gainExperience(p: IPlayer, exp: ITaskTracker, numCycles: number=1): ITaskTracker {
|
||||
gainExperience(p: IPlayer, exp: ITaskTracker, numCycles: number=1, fromOtherSleeve: boolean=false): ITaskTracker {
|
||||
// If the experience is coming from another sleeve, it is not multiplied by anything.
|
||||
// Also the player does not earn anything
|
||||
if (fromOtherSleeve) {
|
||||
if (exp.hack > 0) {
|
||||
this.hacking_exp += exp.hack;
|
||||
}
|
||||
|
||||
if (exp.str > 0) {
|
||||
this.strength_exp += exp.str;
|
||||
}
|
||||
|
||||
if (exp.def > 0) {
|
||||
this.defense_exp += exp.def;
|
||||
}
|
||||
|
||||
if (exp.dex > 0) {
|
||||
this.dexterity_exp += exp.dex;
|
||||
}
|
||||
|
||||
if (exp.agi > 0) {
|
||||
this.agility_exp += exp.agi;
|
||||
}
|
||||
|
||||
if (exp.cha > 0) {
|
||||
this.charisma_exp += exp.cha;
|
||||
}
|
||||
|
||||
return createTaskTracker();
|
||||
}
|
||||
|
||||
// Experience is first multiplied by shock. Then 'synchronization'
|
||||
// is accounted for
|
||||
const multFac = (this.shock / 100) * (this.sync / 100) * numCycles;
|
||||
@ -696,6 +731,7 @@ export class Sleeve extends Person {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.gymStatType = stat;
|
||||
this.currentTask = SleeveTaskType.Gym;
|
||||
|
||||
return true;
|
||||
|
@ -7,8 +7,10 @@ import { SleeveFaq } from "./data/SleeveFaq";
|
||||
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { Locations } from "../../Locations";
|
||||
|
||||
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
import { Crimes } from "../../Crime/Crimes";
|
||||
|
||||
@ -23,9 +25,12 @@ import { exceptionAlert } from "../../../utils/helpers/exceptionAlert";
|
||||
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { createPopup } from "../../../utils/uiHelpers/createPopup";
|
||||
import { createPopupCloseButton } from "../../../utils/uiHelpers/createPopupCloseButton";
|
||||
import { getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||
import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
||||
|
||||
// Object that keeps track of all DOM elements for the UI for a single Sleeve
|
||||
interface ISleeveUIElems {
|
||||
@ -33,6 +38,7 @@ interface ISleeveUIElems {
|
||||
statsPanel: HTMLElement | null;
|
||||
stats: HTMLElement | null;
|
||||
moreStatsButton: HTMLElement | null;
|
||||
travelButton: HTMLElement | null;
|
||||
taskPanel: HTMLElement | null;
|
||||
taskSelector: HTMLSelectElement | null;
|
||||
taskDetailsSelector: HTMLSelectElement | null;
|
||||
@ -156,6 +162,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
statsPanel: null,
|
||||
stats: null,
|
||||
moreStatsButton: null,
|
||||
travelButton: null,
|
||||
taskPanel: null,
|
||||
taskSelector: null,
|
||||
taskDetailsSelector: null,
|
||||
@ -212,8 +219,49 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
);
|
||||
}
|
||||
});
|
||||
elems.travelButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Travel",
|
||||
clickListener: () => {
|
||||
const popupId: string = "sleeve-travel-popup";
|
||||
const popupArguments: HTMLElement[] = [];
|
||||
popupArguments.push(createPopupCloseButton(popupId, { class: "std-button" }));
|
||||
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)}.` +
|
||||
"It will also CANCEL the sleeve's current task (setting it to idle)",
|
||||
}));
|
||||
for (const label in Cities) {
|
||||
if (sleeve.city === Cities[label]) { continue; }
|
||||
(function(sleeve, label) {
|
||||
popupArguments.push(createElement("div", {
|
||||
// Reusing this css class. It adds a border and makes it so that
|
||||
// the background color changes when you hover
|
||||
class: "cmpy-mgmt-find-employee-option",
|
||||
innerText: Cities[label],
|
||||
clickListener: () => {
|
||||
if (!playerRef!.canAfford(CONSTANTS.TravelCost)) {
|
||||
dialogBoxCreate("You cannot afford to have this sleeve travel to another city", false);
|
||||
return false;
|
||||
}
|
||||
sleeve.city = Cities[label];
|
||||
playerRef!.loseMoney(CONSTANTS.TravelCost);
|
||||
sleeve.resetTaskStatus();
|
||||
removeElementById(popupId);
|
||||
updateSleeveUi(sleeve, elems);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
})(sleeve, label);
|
||||
}
|
||||
|
||||
createPopup(popupId, popupArguments);
|
||||
}
|
||||
})
|
||||
elems.statsPanel.appendChild(elems.stats);
|
||||
elems.statsPanel.appendChild(elems.moreStatsButton);
|
||||
elems.statsPanel.appendChild(elems.travelButton);
|
||||
|
||||
elems.taskPanel = createElement("div", { class: "sleeve-panel", width: "40%" });
|
||||
elems.taskSelector = createElement("select") as HTMLSelectElement;
|
||||
@ -225,13 +273,13 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
elems.taskSelector.add(createOptionElement("Workout at Gym"));
|
||||
elems.taskSelector.add(createOptionElement("Shock Recovery"));
|
||||
elems.taskSelector.add(createOptionElement("Synchronize"));
|
||||
elems.taskSelector.addEventListener("change", () => {
|
||||
updateSleeveTaskSelector(sleeve, elems, allSleeves);
|
||||
});
|
||||
elems.taskDetailsSelector = createElement("select") as HTMLSelectElement;
|
||||
elems.taskDetailsSelector2 = createElement("select") as HTMLSelectElement;
|
||||
elems.taskDescription = createElement("p");
|
||||
elems.taskProgressBar = createElement("p");
|
||||
elems.taskSelector.addEventListener("change", () => {
|
||||
updateSleeveTaskSelector(sleeve, elems, allSleeves);
|
||||
});
|
||||
elems.taskSelector.selectedIndex = sleeve.currentTask; // Set initial value for Task Selector
|
||||
elems.taskSelector.dispatchEvent(new Event('change'));
|
||||
updateSleeveTaskDescription(sleeve, elems);
|
||||
@ -308,7 +356,8 @@ function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
|
||||
`Dexterity: ${numeralWrapper.format(sleeve.dexterity, "0,0")}`,
|
||||
`Agility: ${numeralWrapper.format(sleeve.agility, "0,0")}`,
|
||||
`Charisma: ${numeralWrapper.format(sleeve.charisma, "0,0")}`,
|
||||
`HP: ${numeralWrapper.format(sleeve.hp, "0,0")} / ${numeralWrapper.format(sleeve.max_hp, "0,0")}<br>`,
|
||||
`HP: ${numeralWrapper.format(sleeve.hp, "0,0")} / ${numeralWrapper.format(sleeve.max_hp, "0,0")}`,
|
||||
`City: ${sleeve.city}`,
|
||||
`Shock: ${numeralWrapper.format(100 - sleeve.shock, "0,0.000")}`,
|
||||
`Sync: ${numeralWrapper.format(sleeve.sync, "0,0.000")}`].join("<br>");
|
||||
|
||||
@ -405,6 +454,7 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
const value: string = getSelectValue(elems.taskSelector);
|
||||
switch(value) {
|
||||
case "Work for Company":
|
||||
let companyCount: number = 0;
|
||||
const allJobs: string[] = Object.keys(playerRef!.jobs!);
|
||||
for (let i = 0; i < allJobs.length; ++i) {
|
||||
if (!forbiddenCompanies.includes(allJobs[i])) {
|
||||
@ -412,14 +462,17 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
|
||||
// Set initial value of the 'Details' selector
|
||||
if (sleeve.currentTaskLocation === allJobs[i]) {
|
||||
elems.taskDetailsSelector!.selectedIndex = i;
|
||||
elems.taskDetailsSelector!.selectedIndex = companyCount;
|
||||
}
|
||||
|
||||
++companyCount;
|
||||
}
|
||||
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||
}
|
||||
break;
|
||||
case "Work for Faction":
|
||||
let factionCount: number = 0;
|
||||
for (let i = 0; i < playerRef!.factions!.length; ++i) {
|
||||
const fac: string = playerRef!.factions[i]!;
|
||||
if (!forbiddenFactions.includes(fac)) {
|
||||
@ -427,13 +480,30 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
|
||||
// Set initial value of the 'Details' Selector
|
||||
if (sleeve.currentTaskLocation === fac) {
|
||||
elems.taskDetailsSelector!.selectedIndex = i;
|
||||
elems.taskDetailsSelector!.selectedIndex = factionCount;
|
||||
}
|
||||
|
||||
++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;
|
||||
}
|
||||
break;
|
||||
case "Commit Crime":
|
||||
for (const crimeLabel in Crimes) {
|
||||
@ -469,17 +539,37 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
// First selector has what stat is being trained
|
||||
for (let i = 0; i < gymSelectorOptions.length; ++i) {
|
||||
elems.taskDetailsSelector!.add(createOptionElement(gymSelectorOptions[i]));
|
||||
|
||||
// Set initial value
|
||||
if (sleeve.gymStatType === gymSelectorOptions[i]) {
|
||||
elems.taskDetailsSelector!.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Second selector has gym
|
||||
// In this switch statement we also set the initial value of the second selector
|
||||
switch (sleeve.city) {
|
||||
case Cities.Aevum:
|
||||
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumCrushFitnessGym));
|
||||
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSnapFitnessGym));
|
||||
|
||||
// Set initial value
|
||||
if (sleeve.currentTaskLocation === Locations.AevumCrushFitnessGym) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||
} else if (sleeve.currentTaskLocation === Locations.AevumSnapFitnessGym) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = 1;
|
||||
}
|
||||
break;
|
||||
case Cities.Sector12:
|
||||
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12IronGym));
|
||||
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12PowerhouseGym));
|
||||
|
||||
// Set initial value
|
||||
if (sleeve.currentTaskLocation === Locations.Sector12IronGym) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||
} else if (sleeve.currentTaskLocation === Locations.Sector12PowerhouseGym) {
|
||||
elems.taskDetailsSelector2!.selectedIndex = 1;
|
||||
}
|
||||
break;
|
||||
case Cities.Volhaven:
|
||||
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenMilleniumFitnessGym));
|
||||
@ -552,6 +642,11 @@ function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): boolean {
|
||||
|
||||
if (routing.isOn(Page.Sleeves)) {
|
||||
updateSleevesPage();
|
||||
|
||||
// Update the task selector for all sleeves by triggering a change event
|
||||
for (const e of UIElems.sleeves!) {
|
||||
e.taskSelector!.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -279,6 +279,12 @@ PlayerObject.prototype.prestigeAugmentation = function() {
|
||||
|
||||
this.resleeves = [];
|
||||
|
||||
for (let i = 0; i < this.sleeves.length; ++i) {
|
||||
if (this.sleeves[i] instanceof Sleeve) {
|
||||
this.sleeves[i].resetTaskStatus();
|
||||
}
|
||||
}
|
||||
|
||||
this.isWorking = false;
|
||||
this.currentWorkFactionName = "";
|
||||
this.currentWorkFactionDescription = "";
|
||||
|
@ -483,8 +483,11 @@ async function parseOnlyRamCalculate(server, code, workerScript) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
const script = server.getScript(nextModule);
|
||||
if (!script) return -1; // No such script on the server.
|
||||
const script = server.getScript(nextModule.startsWith("./") ? nextModule.slice(2) : nextModule);
|
||||
if (!script) {
|
||||
console.warn("Invalid script");
|
||||
return -1; // No such script on the server.
|
||||
}
|
||||
code = script.code;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,13 @@ export class Stock {
|
||||
*/
|
||||
readonly symbol: string;
|
||||
|
||||
/**
|
||||
* Total number of shares of this stock
|
||||
* This is different than maxShares, as this is like authorized stock while
|
||||
* maxShares is outstanding stock.
|
||||
*/
|
||||
readonly totalShares: number;
|
||||
|
||||
constructor(name: string = "",
|
||||
symbol: string = "",
|
||||
mv: number = 1,
|
||||
@ -97,9 +104,13 @@ export class Stock {
|
||||
this.otlkMag = otlkMag;
|
||||
this.cap = getRandomInt(initPrice * 1e3, initPrice * 25e3);
|
||||
|
||||
// Maximum shares is determined by market cap, and is rounded to nearest millions
|
||||
let maxSharesUnrounded: number = (marketCap / initPrice);
|
||||
this.maxShares = Math.round(maxSharesUnrounded / 1e6) * 1e6;
|
||||
// Total shares is determined by market cap, and is rounded to nearest millions
|
||||
let totalSharesUnrounded: number = (marketCap / initPrice);
|
||||
this.totalShares = Math.round(totalSharesUnrounded / 1e6) * 1e6;
|
||||
|
||||
// Max Shares (Outstanding shares) is a percentage of total shares
|
||||
const outstandingSharePercentage: number = 0.25;
|
||||
this.maxShares = Math.round((this.totalShares * outstandingSharePercentage) / 1e6) * 1e6;
|
||||
|
||||
this.posTxtEl = null;
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ function initStockMarket() {
|
||||
StockMarket[vitalife] = vitalifeStk;
|
||||
|
||||
var icarus = Locations.Sector12IcarusMicrosystems;
|
||||
var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3), 800e12);
|
||||
var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3), 800e9);
|
||||
StockMarket[icarus] = icarusStk;
|
||||
|
||||
var universalenergy = Locations.Sector12UniversalEnergy;
|
||||
|
@ -969,7 +969,7 @@ const Engine = {
|
||||
if (expForOtherSleeves == null) { continue; }
|
||||
for (let j = 0; j < Player.sleeves.length; ++j) {
|
||||
if (j === i) { continue; }
|
||||
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCycles);
|
||||
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCycles, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1336,7 +1336,7 @@ const Engine = {
|
||||
if (expForOtherSleeves == null) { continue; }
|
||||
for (let j = 0; j < Player.sleeves.length; ++j) {
|
||||
if (j === i) { continue; }
|
||||
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCyclesOffline);
|
||||
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCyclesOffline, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
export function getSelectValue(selector: HTMLSelectElement | null): string {
|
||||
if (selector == null) { return ""; }
|
||||
if (selector.options.length <= 0) { return ""; }
|
||||
if (selector.selectedIndex < 0) { return ""; }
|
||||
return selector.options[selector.selectedIndex].value;
|
||||
}
|
||||
|
||||
export function getSelectText(selector: HTMLSelectElement | null): string {
|
||||
if (selector == null) { return ""; }
|
||||
if (selector.options.length <= 0) { return ""; }
|
||||
if (selector.selectedIndex < 0) { return ""; }
|
||||
return selector.options[selector.selectedIndex].text;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user