Merge pull request #512 from danielyxie/company-code-refactor

Company code refactor
This commit is contained in:
danielyxie 2018-11-17 16:25:57 -08:00 committed by GitHub
commit 0647399356
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 171505 additions and 1553 deletions

58610
dist/engine.bundle.js vendored

File diff suppressed because one or more lines are too long

111062
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bitburner</title>
<title>Bitburner - development</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
@ -112,7 +112,7 @@
<div id="script-editor-filename-wrapper">
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
</div>
<div id="javascript-editor"></div>
@ -162,7 +162,7 @@
<fieldset>
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"/>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr" />
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset>
</div> <!-- End script editor options panel -->
@ -173,7 +173,7 @@
<table id="terminal">
<tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" />
</td>
</tr>
</table>
@ -190,7 +190,7 @@
provides information about each script's production. The scripts are categorized by the hostname of the servers on which
they are running. </p>
<p id="active-scripts-total-prod">Total online production of
Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br/>
Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br />
Total online production since last Aug installation: <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span>
(<span class="money-gold"><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span>)</p>
<ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;">
@ -204,19 +204,19 @@
The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced.
<br/><br/>
<br /><br />
Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its
resources to the Hacknet network. This allows you to take a small percentage of profits
from hacks performed on the network. Essentially, you are renting out your Node's computing power.
<br/><br/>
<br /><br />
Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded
in order to increase its computing power and thereby increase the profit you earn from it.
</p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br/>
<br />
<div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br/>
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br />
<span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span>
</p>
<span id="hacknet-nodes-multipliers">
@ -474,7 +474,8 @@
<!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container">
<a id="tutorial-getting-started-link" class="a-link-button" href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
<a id="tutorial-getting-started-link" class="a-link-button"
href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
<a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a>
<a id="tutorial-hacking-link" class="a-link-button"> Hacking </a>
<a id="tutorial-scripts-link" class="a-link-button"> Scripts </a>
@ -483,7 +484,8 @@
<a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a>
<a id="tutorial-factions-link" class="a-link-button"> Factions </a>
<a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a>
<a id="tutorial-shortcuts-link" class="a-link-button" href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
<a id="tutorial-shortcuts-link" class="a-link-button"
href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
<a id="tutorial-back-button" class="a-link-button"> Back </a>
<p id="tutorial-text"> </p>
@ -574,7 +576,7 @@
<p id="location-slums-description">
You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and
other shadowy entities. The city's government and police have neglected this area for years...
<br/><br/><br/>
<br /><br /><br />
In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always
successful. Your chance at successfully committing a crime is determined by your stats.
</p>
@ -621,7 +623,7 @@
<div id="stock-market-container" class="generic-menupage-container">
<p>
Welcome to the World Stock Exchange (WSE)! <br/><br/>
Welcome to the World Stock Exchange (WSE)! <br /><br />
To begin trading, you must first purchase an account. WSE accounts will persist
after you 'reset' by installing Augmentations.
@ -634,7 +636,7 @@
TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE.
Purchasing access to the TIX API lets you write code to create your own algorithmic/automated
trading strategies.
<br/><br/>
<br /><br />
If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations.
</p>
@ -644,7 +646,7 @@
<p>
Four Sigma's (4S) Market Data Feed provides information about stocks
that will help your trading strategies.
<br/><br/>
<br /><br />
If you purchase access to 4S Market Data and/or the 4S TIX API, you will
retain that access even after you 'reset' by installing Augmentations.
</p>
@ -662,7 +664,7 @@
<a id="stock-market-mode" class="a-link-button tooltip"></a>
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
<br/><br/>
<br /><br />
<input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/>
<a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a>
<ul id="stock-market-list" style="list-style:none;">
@ -692,7 +694,7 @@
<div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"> </p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30"/>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<button id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </button>
<button id="yes-no-text-input-box-no" class="popup-box-button"> No </button>
</div>
@ -704,7 +706,7 @@
<p id="faction-invitation-box-text"> </p>
<p id="faction-invitation-box-message"> </p>
<p id="faction-invitation-box-warning">
Would you like to join? <br/> <br/>
Would you like to join? <br /> <br />
Warning: Joining this faction may prevent you from joining other factions during this run!
</p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
@ -717,8 +719,8 @@
<div id="infiltration-box-content" class="popup-box-content">
<p id="infiltration-box-text"> </p>
<button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br/><br/>
<select id="infiltration-faction-select"> </select> <br/>
<button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br /><br />
<select id="infiltration-faction-select"> </select> <br />
<button id="infiltration-box-faction" class="a-link-button"> Give to Faction for Reputation </button>
</div>
@ -804,7 +806,7 @@
<div id="game-options-content" class="game-options-box">
<button id="game-options-close-button">&times;</button>
<h1> Game Options </h1>
<br/>
<br />
<div id="game-options-left-panel">
<!-- Netscript execution time -->
<fieldset>
@ -816,7 +818,7 @@
</span>
</label>
<input type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/>
<input type ="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25" />
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -830,7 +832,7 @@
</span>
</label>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -844,7 +846,7 @@
</span>
</label>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -856,7 +858,7 @@
</span>
</label>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset>
@ -968,7 +970,7 @@
<a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a>
<a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a>
<a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a>
<input type="file" id="import-game-file-selector" name="file"/>
<input type="file" id="import-game-file-selector" name="file" />
<a id="import-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Import Game </a>
<a id="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;">
(DEBUG) Delete Active Scripts

File diff suppressed because it is too large Load Diff

50
src/Company/Companies.ts Normal file

@ -0,0 +1,50 @@
// Constructs all CompanyPosition objects using the metadata in data/companypositions.ts
import { companiesMetadata } from "./data/CompaniesMetadata";
import { Company, IConstructorParams } from "./Company";
import { IMap } from "../types";
import { Reviver } from "../../utils/JSONReviver";
export let Companies: IMap<Company> = {};
function addCompany(params: IConstructorParams) {
if (Companies[params.name] != null) {
console.warn(`Duplicate Company Position being defined: ${params.name}`);
}
Companies[params.name] = new Company(params);
}
// Used to initialize new Company objects for the Companies map
// Called when creating new game or after a prestige/reset
export function initCompanies() {
// Save Old Company data for 'favor'
const oldCompanies = Companies;
// Re-construct all Companies
Companies = {};
companiesMetadata.forEach((e) => {
addCompany(e);
});
// Reset data
for (const companyName in Companies) {
const company = Companies[companyName];
const oldCompany = oldCompanies[companyName];
if (!(oldCompany instanceof Company)) {
// New game, so no OldCompanies data
company.favor = 0;
} else {
company.favor = oldCompanies[companyName].favor;
if (isNaN(company.favor)) { company.favor = 0; }
}
}
}
// Used to load Companies map from a save
export function loadCompanies(saveString: string) {
Companies = JSON.parse(saveString, Reviver);
}
// Utility function to check if a string is valid company name
export function companyExists(name: string) {
return Companies.hasOwnProperty(name);
}

135
src/Company/Company.ts Normal file

@ -0,0 +1,135 @@
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { CompanyPosition } from "./CompanyPosition";
import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
export interface IConstructorParams {
name: string;
info: string;
companyPositions: IMap<boolean>;
expMultiplier: number;
salaryMultiplier: number;
jobStatReqOffset: number;
}
const DefaultConstructorParams: IConstructorParams = {
name: "",
info: "",
companyPositions: {},
expMultiplier: 1,
salaryMultiplier: 1,
jobStatReqOffset: 0,
}
export class Company {
/**
* Initiatizes a Company from a JSON save state.
*/
static fromJSON(value: any): Company {
return Generic_fromJSON(Company, value.data);
}
/**
* Company name
*/
name: string;
/**
* Description and general information about company
*/
info: string;
/**
* Object that holds all available positions in this Company.
* Position names are held in keys.
* The values for the keys don't matter, but we'll make them booleans
*
* Must match names of Company Positions, defined in data/companypositionnames.ts
*/
companyPositions: IMap<boolean>;
/**
* Company-specific multiplier for earnings
*/
expMultiplier: number;
salaryMultiplier: number;
/**
* The additional levels of stats you need to quality for a job
* in this company.
*
* For example, the base stat requirement for an intern position is 1.
* But if a company has a offset of 200, then you would need stat(s) of 201
*/
jobStatReqOffset: number;
/**
* Properties to track the player's progress in this company
*/
isPlayerEmployed: boolean;
playerReputation: number;
favor: number;
rolloverRep: number;
constructor(p: IConstructorParams = DefaultConstructorParams) {
this.name = p.name;
this.info = p.info;
this.companyPositions = p.companyPositions;
this.expMultiplier = p.expMultiplier;
this.salaryMultiplier = p.salaryMultiplier;
this.jobStatReqOffset = p.jobStatReqOffset;
this.isPlayerEmployed = false;
this.playerReputation = 1;
this.favor = 0;
this.rolloverRep = 0;
}
hasPosition(pos: CompanyPosition | string): boolean {
if (pos instanceof CompanyPosition) {
return (this.companyPositions[pos.name] != null);
} else {
return (this.companyPositions[pos] != null);
}
}
gainFavor(): void {
if (this.favor == null) { this.favor = 0; }
if (this.rolloverRep == null) { this.rolloverRep = 0; }
var res = this.getFavorGain();
if (res.length != 2) {
console.error("Invalid result from getFavorGain() function");
return;
}
this.favor += res[0];
this.rolloverRep = res[1];
}
getFavorGain(): number[] {
if (this.favor == null) { this.favor = 0; }
if (this.rolloverRep == null) { this.rolloverRep = 0; }
let favorGain = 0, rep = this.playerReputation + this.rolloverRep;
let reqdRep = CONSTANTS.CompanyReputationToFavorBase *
Math.pow(CONSTANTS.CompanyReputationToFavorMult, this.favor);
while(rep > 0) {
if (rep >= reqdRep) {
++favorGain;
rep -= reqdRep;
} else {
break;
}
reqdRep *= CONSTANTS.FactionReputationToFavorMult;
}
return [favorGain, rep];
}
/**
* Serialize the current file to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("Company", this);
}
}
Reviver.constructors.Company = Company;

@ -0,0 +1,182 @@
import { CONSTANTS } from "../Constants";
import * as names from "./data/CompanyPositionNames";
/* tslint:disable:completed-docs */
export interface IConstructorParams {
name: string;
nextPosition: string | null;
baseSalary: number;
repMultiplier: number;
reqdHacking?: number;
reqdStrength?: number;
reqdDefense?: number;
reqdDexterity?: number;
reqdAgility?: number;
reqdCharisma?: number;
reqdReputation?: number;
hackingEffectiveness?: number;
strengthEffectiveness?: number;
defenseEffectiveness?: number;
dexterityEffectiveness?: number;
agilityEffectiveness?: number;
charismaEffectiveness?: number;
hackingExpGain?: number;
strengthExpGain?: number;
defenseExpGain?: number;
dexterityExpGain?: number;
agilityExpGain?: number;
charismaExpGain?: number;
}
export class CompanyPosition {
/**
* Position title
*/
name: string;
/**
* Title of next position to be promoted to
*/
nextPosition: string | null;
/**
* Base salary for this position ($ per 200ms game cycle)
* Will be multiplier by a company-specific multiplier for final salary
*/
baseSalary: number;
/**
* Reputation multiplier
*/
repMultiplier: number;
/**
* Required stats to earn this position
*/
requiredAgility: number;
requiredCharisma: number;
requiredDefense: number;
requiredDexterity: number;
requiredHacking: number;
requiredStrength: number;
/**
* Required company reputation to earn this position
*/
requiredReputation: number;
/**
* Effectiveness of each stat time for job performance
*/
hackingEffectiveness: number;
strengthEffectiveness: number;
defenseEffectiveness: number;
dexterityEffectiveness: number;
agilityEffectiveness: number;
charismaEffectiveness: number;
/**
* Experience gain for performing job (per 200ms game cycle)
*/
hackingExpGain: number;
strengthExpGain: number;
defenseExpGain: number;
dexterityExpGain: number;
agilityExpGain: number;
charismaExpGain: number;
constructor(p: IConstructorParams) {
this.name = p.name;
this.nextPosition = p.nextPosition;
this.baseSalary = p.baseSalary;
this.repMultiplier = p.repMultiplier;
this.requiredHacking = (p.reqdHacking != null) ? p.reqdHacking : 0;
this.requiredStrength = (p.reqdStrength != null) ? p.reqdStrength : 0;
this.requiredDefense = (p.reqdDefense != null) ? p.reqdDefense : 0;
this.requiredDexterity = (p.reqdDexterity != null) ? p.reqdDexterity : 0;
this.requiredAgility = (p.reqdAgility != null) ? p.reqdAgility : 0;
this.requiredCharisma = (p.reqdCharisma != null) ? p.reqdCharisma : 0;
this.requiredReputation = (p.reqdReputation != null) ? p.reqdReputation : 0;
this.hackingEffectiveness = (p.hackingEffectiveness != null) ? p.hackingEffectiveness : 0;
this.strengthEffectiveness = (p.strengthEffectiveness != null) ? p.strengthEffectiveness : 0;
this.defenseEffectiveness = (p.defenseEffectiveness != null) ? p.defenseEffectiveness : 0;
this.dexterityEffectiveness = (p.dexterityEffectiveness != null) ? p.dexterityEffectiveness : 0;
this.agilityEffectiveness = (p.agilityEffectiveness != null) ? p.agilityEffectiveness : 0;
this.charismaEffectiveness = (p.charismaEffectiveness != null) ? p.charismaEffectiveness : 0;
if (Math.round(this.hackingEffectiveness + this.strengthEffectiveness + this.defenseEffectiveness +
this.dexterityEffectiveness + this.agilityEffectiveness + this.charismaEffectiveness) !== 100) {
console.error(`CompanyPosition ${this.name} parameters do not sum to 100`);
}
this.hackingExpGain = (p.hackingExpGain != null) ? p.hackingExpGain : 0;
this.strengthExpGain = (p.strengthExpGain != null) ? p.strengthExpGain : 0;
this.defenseExpGain = (p.defenseExpGain != null) ? p.defenseExpGain : 0;
this.dexterityExpGain = (p.dexterityExpGain != null) ? p.dexterityExpGain : 0;
this.agilityExpGain = (p.agilityExpGain != null) ? p.agilityExpGain : 0;
this.charismaExpGain = (p.charismaExpGain != null) ? p.charismaExpGain : 0;
}
calculateJobPerformance(hack: number, str: number, def: number, dex: number, agi: number, cha: number): number {
const hackRatio: number = this.hackingEffectiveness * hack / CONSTANTS.MaxSkillLevel;
const strRatio: number = this.strengthEffectiveness * str / CONSTANTS.MaxSkillLevel;
const defRatio: number = this.defenseEffectiveness * def / CONSTANTS.MaxSkillLevel;
const dexRatio: number = this.dexterityEffectiveness * dex / CONSTANTS.MaxSkillLevel;
const agiRatio: number = this.agilityEffectiveness * agi / CONSTANTS.MaxSkillLevel;
const chaRatio: number = this.charismaEffectiveness * cha / CONSTANTS.MaxSkillLevel;
let reputationGain: number = this.repMultiplier * (hackRatio + strRatio + defRatio + dexRatio + agiRatio + chaRatio) / 100;
if (isNaN(reputationGain)) {
console.error("Company reputation gain calculated to be NaN");
reputationGain = 0;
}
return reputationGain;
}
isSoftwareJob(): boolean {
return names.SoftwareCompanyPositions.includes(this.name);
}
isITJob(): boolean {
return names.ITCompanyPositions.includes(this.name);
}
isSecurityEngineerJob(): boolean {
return names.SecurityEngineerCompanyPositions.includes(this.name);
}
isNetworkEngineerJob(): boolean {
return names.NetworkEngineerCompanyPositions.includes(this.name);
}
isBusinessJob(): boolean {
return names.BusinessCompanyPositions.includes(this.name);
}
isSecurityJob(): boolean {
return names.SecurityCompanyPositions.includes(this.name);
}
isAgentJob(): boolean {
return names.AgentCompanyPositions.includes(this.name);
}
isSoftwareConsultantJob(): boolean {
return names.SoftwareConsultantCompanyPositions.includes(this.name);
}
isBusinessConsultantJob(): boolean {
return names.BusinessConsultantCompanyPositions.includes(this.name);
}
isPartTimeJob(): boolean {
return names.PartTimeCompanyPositions.includes(this.name);
}
}

@ -0,0 +1,17 @@
// Constructs all CompanyPosition objects using the metadata in data/companypositions.ts
import { companyPositionMetadata } from "./data/CompanyPositionsMetadata";
import { CompanyPosition, IConstructorParams } from "./CompanyPosition";
import { IMap } from "../types";
export const CompanyPositions: IMap<CompanyPosition> = {};
function addCompanyPosition(params: IConstructorParams) {
if (CompanyPositions[params.name] != null) {
console.warn(`Duplicate Company Position being defined: ${params.name}`);
}
CompanyPositions[params.name] = new CompanyPosition(params);
}
companyPositionMetadata.forEach((e) => {
addCompanyPosition(e);
});

@ -0,0 +1,40 @@
import { Company } from "./Company";
import { CompanyPosition } from "./CompanyPosition";
/**
* Returns a string with the given CompanyPosition's stat requirements
*/
export function getJobRequirementText(company: Company, pos: CompanyPosition, tooltiptext: boolean = false): string {
let reqText: string = "";
const offset: number = company.jobStatReqOffset;
const reqHacking: number = pos.requiredHacking > 0 ? pos.requiredHacking+offset : 0;
const reqStrength: number = pos.requiredStrength > 0 ? pos.requiredStrength+offset : 0;
const reqDefense: number = pos.requiredDefense > 0 ? pos.requiredDefense+offset : 0;
const reqDexterity: number = pos.requiredDexterity > 0 ? pos.requiredDexterity+offset : 0;
const reqAgility: number = pos.requiredDexterity > 0 ? pos.requiredDexterity+offset : 0;
const reqCharisma: number = pos.requiredCharisma > 0 ? pos.requiredCharisma+offset : 0;
const reqRep: number = pos.requiredReputation;
if (tooltiptext) {
reqText = "Requires:<br>";
reqText += (reqHacking.toString() + " hacking<br>");
reqText += (reqStrength.toString() + " strength<br>");
reqText += (reqDefense.toString() + " defense<br>");
reqText += (reqDexterity.toString() + " dexterity<br>");
reqText += (reqAgility.toString() + " agility<br>");
reqText += (reqCharisma.toString() + " charisma<br>");
reqText += (reqRep.toString() + " reputation");
} else {
reqText = "(Requires ";
if (reqHacking > 0) {reqText += (reqHacking + " hacking, ");}
if (reqStrength > 0) {reqText += (reqStrength + " strength, ");}
if (reqDefense > 0) {reqText += (reqDefense + " defense, ");}
if (reqDexterity > 0) {reqText += (reqDexterity + " dexterity, ");}
if (reqAgility > 0) {reqText += (reqAgility + " agility, ");}
if (reqCharisma > 0) {reqText += (reqCharisma + " charisma, ");}
if (reqRep > 1) {reqText += (reqRep + " reputation, ");}
reqText = reqText.substring(0, reqText.length - 2);
reqText += ")";
}
return reqText;
}

@ -0,0 +1,13 @@
// Function that returns the next Company Position in the "ladder"
// i.e. the next position to get promoted to
import { CompanyPosition } from "./CompanyPosition";
import { CompanyPositions } from "./CompanyPositions";
export function getNextCompanyPosition(currPos: CompanyPosition | null): CompanyPosition | null {
if (currPos == null) { return null; }
const nextPosName: string | null = currPos.nextPosition;
if (nextPosName == null) { return null; }
return CompanyPositions[nextPosName];
}

1
src/Company/README.md Normal file

@ -0,0 +1 @@
Implementation of Company and Job related mechanics

@ -0,0 +1,544 @@
import { IConstructorParams } from "../Company";
import { Locations } from "../../Locations";
import * as posNames from "./CompanyPositionNames";
import { IMap } from "../../types";
// Create Objects containing Company Positions by category
// Will help in metadata construction later
const AllSoftwarePositions: IMap<boolean> = {};
const AllITPositions: IMap<boolean> = {};
const AllNetworkEngineerPositions: IMap<boolean> = {};
const AllTechnologyPositions: IMap<boolean> = {};
const AllBusinessPositions: IMap<boolean> = {};
const AllAgentPositions: IMap<boolean> = {};
const AllSecurityPositions: IMap<boolean> = {};
const AllSoftwareConsultantPositions: IMap<boolean> = {};
const AllBusinessConsultantPositions: IMap<boolean> = {};
const SoftwarePositionsUpToHeadOfEngineering: IMap<boolean> = {};
const SoftwarePositionsUpToLeadDeveloper: IMap<boolean> = {};
const BusinessPositionsUpToOperationsManager: IMap<boolean> = {};
const WaiterOnly: IMap<boolean> = {};
const EmployeeOnly: IMap<boolean> = {};
const PartTimeWaiterOnly: IMap<boolean> = {};
const PartTimeEmployeeOnly: IMap<boolean> = {};
const OperationsManagerOnly: IMap<boolean> = {};
const CEOOnly: IMap<boolean> = {};
posNames.SoftwareCompanyPositions.forEach((e) => {
AllSoftwarePositions[e] = true;
AllTechnologyPositions[e] = true;
});
posNames.ITCompanyPositions.forEach((e) => {
AllITPositions[e] = true;
AllTechnologyPositions[e] = true;
});
posNames.NetworkEngineerCompanyPositions.forEach((e) => {
AllNetworkEngineerPositions[e] = true;
AllTechnologyPositions[e] = true;
});
AllTechnologyPositions[posNames.SecurityEngineerCompanyPositions[0]] = true;
posNames.BusinessCompanyPositions.forEach((e) => {
AllBusinessPositions[e] = true;
});
posNames.SecurityCompanyPositions.forEach((e) => {
AllSecurityPositions[e] = true;
});
posNames.AgentCompanyPositions.forEach((e) => {
AllAgentPositions[e] = true;
});
posNames.SoftwareConsultantCompanyPositions.forEach((e) => {
AllSoftwareConsultantPositions[e] = true;
});
posNames.BusinessConsultantCompanyPositions.forEach((e) => {
AllBusinessConsultantPositions[e] = true;
});
for (let i = 0; i < posNames.SoftwareCompanyPositions.length; ++i) {
const e = posNames.SoftwareCompanyPositions[i];
if (i <= 5) {
SoftwarePositionsUpToHeadOfEngineering[e] = true;
}
if (i <= 3) {
SoftwarePositionsUpToLeadDeveloper[e] = true;
}
}
for (let i = 0; i < posNames.BusinessCompanyPositions.length; ++i) {
const e = posNames.BusinessCompanyPositions[i];
if (i <= 3) {
BusinessPositionsUpToOperationsManager[e] = true;
}
}
WaiterOnly[posNames.MiscCompanyPositions[0]] = true;
EmployeeOnly[posNames.MiscCompanyPositions[1]] = true;
PartTimeWaiterOnly[posNames.PartTimeCompanyPositions[0]] = true;
PartTimeEmployeeOnly[posNames.PartTimeCompanyPositions[1]] = true;
OperationsManagerOnly[posNames.BusinessCompanyPositions[3]] = true;
CEOOnly[posNames.BusinessCompanyPositions[5]] = true;
// Metadata
export const companiesMetadata: IConstructorParams[] = [
{
name: Locations.AevumECorp,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 3,
salaryMultiplier: 3,
jobStatReqOffset: 249,
},
{
name: Locations.Sector12MegaCorp,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 3,
salaryMultiplier: 3,
jobStatReqOffset: 249,
},
{
name: Locations.AevumBachmanAndAssociates,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.6,
salaryMultiplier: 2.6,
jobStatReqOffset: 224,
},
{
name: Locations.Sector12BladeIndustries,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.75,
salaryMultiplier: 2.75,
jobStatReqOffset: 224,
},
{
name: Locations.VolhavenNWO,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.75,
salaryMultiplier: 2.75,
jobStatReqOffset: 249,
},
{
name: Locations.AevumClarkeIncorporated,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.25,
salaryMultiplier: 2.25,
jobStatReqOffset: 224,
},
{
name: Locations.VolhavenOmniTekIncorporated,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.25,
salaryMultiplier: 2.25,
jobStatReqOffset: 224,
},
{
name: Locations.Sector12FourSigma,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.5,
salaryMultiplier: 2.5,
jobStatReqOffset: 224,
},
{
name: Locations.ChongqingKuaiGongInternational,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 2.2,
salaryMultiplier: 2.2,
jobStatReqOffset: 224,
},
{
name: Locations.AevumFulcrumTechnologies,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions
),
expMultiplier: 2,
salaryMultiplier: 2,
jobStatReqOffset: 224,
},
{
name: Locations.IshimaStormTechnologies,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllSoftwareConsultantPositions,
AllBusinessPositions
),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 199,
},
{
name: Locations.NewTokyoDefComm,
info: "",
companyPositions: Object.assign({},
CEOOnly,
AllTechnologyPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 1.75,
salaryMultiplier: 1.75,
jobStatReqOffset: 199,
},
{
name: Locations.VolhavenHeliosLabs,
info: "",
companyPositions: Object.assign({},
CEOOnly,
AllTechnologyPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 199,
},
{
name: Locations.NewTokyoVitaLife,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 199,
},
{
name: Locations.Sector12IcarusMicrosystems,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 1.9,
salaryMultiplier: 1.9,
jobStatReqOffset: 199,
},
{
name: Locations.Sector12UniversalEnergy,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 2,
salaryMultiplier: 2,
jobStatReqOffset: 199,
},
{
name: Locations.AevumGalacticCybersystems,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 1.9,
salaryMultiplier: 1.9,
jobStatReqOffset: 199,
},
{
name: Locations.AevumAeroCorp,
info: "",
companyPositions: Object.assign({},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions
),
expMultiplier: 1.7,
salaryMultiplier: 1.7,
jobStatReqOffset: 199,
},
{
name: Locations.VolhavenOmniaCybersystems,
info: "",
companyPositions: Object.assign({},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
expMultiplier: 1.7,
salaryMultiplier: 1.7,
jobStatReqOffset: 199,
},
{
name: Locations.ChongqingSolarisSpaceSystems,
info: "",
companyPositions: Object.assign({},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
expMultiplier: 1.7,
salaryMultiplier: 1.7,
jobStatReqOffset: 199,
},
{
name: Locations.Sector12DeltaOne,
info: "",
companyPositions: Object.assign({},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
expMultiplier: 1.6,
salaryMultiplier: 1.6,
jobStatReqOffset: 199,
},
{
name: Locations.NewTokyoGlobalPharmaceuticals,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions,
AllSecurityPositions
),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 224,
},
{
name: Locations.IshimaNovaMedical,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions,
AllSecurityPositions
),
expMultiplier: 1.75,
salaryMultiplier: 1.75,
jobStatReqOffset: 199,
},
{
name: Locations.Sector12CIA,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToHeadOfEngineering,
AllNetworkEngineerPositions,
AllITPositions,
AllSecurityPositions,
AllAgentPositions
),
expMultiplier: 2,
salaryMultiplier: 2,
jobStatReqOffset: 149,
},
{
name: Locations.Sector12NSA,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToHeadOfEngineering,
AllNetworkEngineerPositions,
AllITPositions,
AllSecurityPositions,
AllAgentPositions
),
expMultiplier: 2,
salaryMultiplier: 2,
jobStatReqOffset: 149,
},
{
name: Locations.AevumWatchdogSecurity,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToHeadOfEngineering,
AllNetworkEngineerPositions,
AllITPositions,
AllSecurityPositions,
AllAgentPositions,
AllSoftwareConsultantPositions
),
expMultiplier: 1.5,
salaryMultiplier: 1.5,
jobStatReqOffset: 124,
},
{
name: Locations.VolhavenLexoCorp,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllSoftwareConsultantPositions,
AllBusinessPositions,
AllSecurityPositions
),
expMultiplier: 1.4,
salaryMultiplier: 1.4,
jobStatReqOffset: 99,
},
{
name: Locations.AevumRhoConstruction,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToLeadDeveloper,
BusinessPositionsUpToOperationsManager
),
expMultiplier: 1.3,
salaryMultiplier: 1.3,
jobStatReqOffset: 49,
},
{
name: Locations.Sector12AlphaEnterprises,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToLeadDeveloper,
BusinessPositionsUpToOperationsManager,
AllSoftwareConsultantPositions
),
expMultiplier: 1.5,
salaryMultiplier: 1.5,
jobStatReqOffset: 99,
},
{
name: Locations.AevumPolice,
info: "",
companyPositions: Object.assign({},
AllSecurityPositions,
SoftwarePositionsUpToLeadDeveloper
),
expMultiplier: 1.3,
salaryMultiplier: 1.3,
jobStatReqOffset: 99,
},
{
name: Locations.VolhavenSysCoreSecurities,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions
),
expMultiplier: 1.3,
salaryMultiplier: 1.3,
jobStatReqOffset: 124,
},
{
name: Locations.VolhavenCompuTek,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions
),
expMultiplier: 1.2,
salaryMultiplier: 1.2,
jobStatReqOffset: 74,
},
{
name: Locations.AevumNetLinkTechnologies,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions
),
expMultiplier: 1.2,
salaryMultiplier: 1.2,
jobStatReqOffset: 99,
},
{
name: Locations.Sector12CarmichaelSecurity,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
AllAgentPositions,
AllSecurityPositions
),
expMultiplier: 1.2,
salaryMultiplier: 1.2,
jobStatReqOffset: 74,
},
{
name: Locations.Sector12FoodNStuff,
info: "",
companyPositions: Object.assign({},
EmployeeOnly, PartTimeEmployeeOnly
),
expMultiplier: 1,
salaryMultiplier: 1,
jobStatReqOffset: 0,
},
{
name: Locations.Sector12JoesGuns,
info: "",
companyPositions: Object.assign({},
EmployeeOnly, PartTimeEmployeeOnly
),
expMultiplier: 1,
salaryMultiplier: 1,
jobStatReqOffset: 0,
},
{
name: Locations.IshimaOmegaSoftware,
info: "",
companyPositions: Object.assign({},
AllSoftwarePositions,
AllSoftwareConsultantPositions,
AllITPositions
),
expMultiplier: 1.1,
salaryMultiplier: 1.1,
jobStatReqOffset: 49,
},
{
name: Locations.NewTokyoNoodleBar,
info: "",
companyPositions: Object.assign({},
WaiterOnly, PartTimeWaiterOnly
),
expMultiplier: 1,
salaryMultiplier: 1,
jobStatReqOffset: 0,
},
]

@ -0,0 +1,602 @@
// Metadata used for constructing Company Positions
import { IConstructorParams } from "../CompanyPosition";
import * as posNames from "./CompanyPositionNames";
export const companyPositionMetadata: IConstructorParams[] = [
{
name: posNames.SoftwareCompanyPositions[0], // Software Enginering Intern
nextPosition: posNames.SoftwareCompanyPositions[1], // Junior Software Engineer
baseSalary: 33,
charismaEffectiveness: 15,
charismaExpGain: 0.02,
hackingEffectiveness: 85,
hackingExpGain: 0.05,
reqdHacking: 1,
repMultiplier: 0.9,
},
{
name: posNames.SoftwareCompanyPositions[1], // Junior Software Engineer
nextPosition: posNames.SoftwareCompanyPositions[2], // Senior Software Engineer
baseSalary: 80,
charismaEffectiveness: 15,
charismaExpGain: 0.05,
hackingEffectiveness: 85,
hackingExpGain: 0.1,
reqdHacking: 51,
reqdReputation: 8e3,
repMultiplier: 1.1,
},
{
name: posNames.SoftwareCompanyPositions[2], // Senior Software Engineer
nextPosition: posNames.SoftwareCompanyPositions[3], // Lead Software Developer
baseSalary: 165,
charismaEffectiveness: 20,
charismaExpGain: 0.08,
hackingEffectiveness: 80,
hackingExpGain: 0.4,
reqdCharisma: 51,
reqdHacking: 251,
reqdReputation: 40e3,
repMultiplier: 1.3,
},
{
name: posNames.SoftwareCompanyPositions[3], // Lead Software Developer
nextPosition: posNames.SoftwareCompanyPositions[4], // Head of Software
baseSalary: 500,
charismaEffectiveness: 25,
charismaExpGain: 0.1,
hackingEffectiveness: 75,
hackingExpGain: 0.8,
reqdCharisma: 151,
reqdHacking: 401,
reqdReputation: 200e3,
repMultiplier: 1.5,
},
{
name: posNames.SoftwareCompanyPositions[4], // Head of Software
nextPosition: posNames.SoftwareCompanyPositions[5], // Head of Engineering
baseSalary: 800,
charismaEffectiveness: 25,
charismaExpGain: 0.5,
hackingEffectiveness: 75,
hackingExpGain: 1,
reqdCharisma: 251,
reqdHacking: 501,
reqdReputation: 400e3,
repMultiplier: 1.6,
},
{
name: posNames.SoftwareCompanyPositions[5], // Head of Engineering
nextPosition: posNames.SoftwareCompanyPositions[6], // Vice President of Technology
baseSalary: 1650,
charismaEffectiveness: 25,
charismaExpGain: 0.5,
hackingEffectiveness: 75,
hackingExpGain: 1.1,
reqdCharisma: 251,
reqdHacking: 501,
reqdReputation: 800e3,
repMultiplier: 1.6,
},
{
name: posNames.SoftwareCompanyPositions[6], // Vice President of Technology
nextPosition: posNames.SoftwareCompanyPositions[7], // Chief Technology Officer
baseSalary: 2310,
charismaEffectiveness: 30,
charismaExpGain: 0.6,
hackingEffectiveness: 70,
hackingExpGain: 1.2,
reqdCharisma: 401,
reqdHacking: 601,
reqdReputation: 1.6e6,
repMultiplier: 1.75,
},
{
name: posNames.SoftwareCompanyPositions[7], // Chief Technology Officer
nextPosition: null,
baseSalary: 2640,
charismaEffectiveness: 35,
charismaExpGain: 1,
hackingEffectiveness: 65,
hackingExpGain: 1.5,
reqdCharisma: 501,
reqdHacking: 751,
reqdReputation: 3.2e6,
repMultiplier: 2,
},
{
name: posNames.ITCompanyPositions[0], // IT Intern
nextPosition: posNames.ITCompanyPositions[1], // IT Analyst
baseSalary: 26,
charismaEffectiveness: 10,
charismaExpGain: 0.01,
hackingEffectiveness: 90,
hackingExpGain: 0.04,
reqdHacking: 1,
repMultiplier: 0.9,
},
{
name: posNames.ITCompanyPositions[1], // IT Analyst
nextPosition: posNames.ITCompanyPositions[2], // IT Manager
baseSalary: 66,
charismaEffectiveness: 15,
charismaExpGain: 0.02,
hackingEffectiveness: 85,
hackingExpGain: 0.08,
reqdHacking: 26,
reqdReputation: 7e3,
repMultiplier: 1.1,
},
{
name: posNames.ITCompanyPositions[2], // IT Manager
nextPosition: posNames.ITCompanyPositions[3], // Systems Administrator
baseSalary: 132,
charismaEffectiveness: 20,
charismaExpGain: 0.1,
hackingEffectiveness: 80,
hackingExpGain: 0.3,
reqdCharisma: 51,
reqdHacking: 151,
reqdReputation: 35e3,
repMultiplier: 1.3,
},
{
name: posNames.ITCompanyPositions[3], // Systems Administrator
nextPosition: posNames.SoftwareCompanyPositions[5], // Head of Engineering
baseSalary: 410,
charismaEffectiveness: 20,
charismaExpGain: 0.2,
hackingEffectiveness: 80,
hackingExpGain: 0.5,
reqdCharisma: 76,
reqdHacking: 251,
reqdReputation: 175e3,
repMultiplier: 1.4,
},
{
name: posNames.SecurityEngineerCompanyPositions[0], // Security Engineer
nextPosition: posNames.SoftwareCompanyPositions[5], // Head of Engineering
baseSalary: 121,
charismaEffectiveness: 15,
charismaExpGain: 0.05,
hackingEffectiveness: 85,
hackingExpGain: 0.4,
reqdCharisma: 26,
reqdHacking: 151,
reqdReputation: 35e3,
repMultiplier: 1.2,
},
{
name: posNames.NetworkEngineerCompanyPositions[0], // Network Engineer
nextPosition: posNames.NetworkEngineerCompanyPositions[1], // Network Adminsitrator
baseSalary: 121,
charismaEffectiveness: 15,
charismaExpGain: 0.05,
hackingEffectiveness: 85,
hackingExpGain: 0.4,
reqdCharisma: 26,
reqdHacking: 151,
reqdReputation: 35e3,
repMultiplier: 1.2,
},
{
name: posNames.NetworkEngineerCompanyPositions[1], // Network Administrator
nextPosition: posNames.SoftwareCompanyPositions[5], // Head of Engineering
baseSalary: 410,
charismaEffectiveness: 20,
charismaExpGain: 0.1,
hackingEffectiveness: 80,
hackingExpGain: 0.5,
reqdCharisma: 76,
reqdHacking: 251,
reqdReputation: 175e3,
repMultiplier: 1.3,
},
{
name: posNames.BusinessCompanyPositions[0], // Business Intern
nextPosition: posNames.BusinessCompanyPositions[1], // Business Analyst
baseSalary: 46,
charismaEffectiveness: 90,
charismaExpGain: 0.08,
hackingEffectiveness: 10,
hackingExpGain: 0.01,
reqdCharisma: 1,
reqdHacking: 1,
repMultiplier: 0.9,
},
{
name: posNames.BusinessCompanyPositions[1], // Business Analyst
nextPosition: posNames.BusinessCompanyPositions[2], // Business Manager
baseSalary: 100,
charismaEffectiveness: 85,
charismaExpGain: 0.15,
hackingEffectiveness: 15,
hackingExpGain: 0.02,
reqdCharisma: 51,
reqdHacking: 6,
reqdReputation: 8e3,
repMultiplier: 1.1,
},
{
name: posNames.BusinessCompanyPositions[2], // Business Manager
nextPosition: posNames.BusinessCompanyPositions[3], // Operations Manager
baseSalary: 200,
charismaEffectiveness: 85,
charismaExpGain: 0.3,
hackingEffectiveness: 15,
hackingExpGain: 0.02,
reqdCharisma: 101,
reqdHacking: 51,
reqdReputation: 40e3,
repMultiplier: 1.3,
},
{
name: posNames.BusinessCompanyPositions[3], // Operations Manager
nextPosition: posNames.BusinessCompanyPositions[4], // Chief Financial Officer
baseSalary: 660,
charismaEffectiveness: 85,
charismaExpGain: 0.4,
hackingEffectiveness: 15,
hackingExpGain: 0.02,
reqdCharisma: 226,
reqdHacking: 51,
reqdReputation: 200e3,
repMultiplier: 1.5,
},
{
name: posNames.BusinessCompanyPositions[4], // Chief Financial Officer
nextPosition: posNames.BusinessCompanyPositions[5], // Chief Executive Officer
baseSalary: 1950,
charismaEffectiveness: 90,
charismaExpGain: 1,
hackingEffectiveness: 10,
hackingExpGain: 0.05,
reqdCharisma: 501,
reqdHacking: 76,
reqdReputation: 800e3,
repMultiplier: 1.6,
},
{
name: posNames.BusinessCompanyPositions[5], // Chief Executive Officer
nextPosition: null,
baseSalary: 3900,
charismaEffectiveness: 90,
charismaExpGain: 1.5,
hackingEffectiveness: 10,
hackingExpGain: 0.05,
reqdCharisma: 751,
reqdHacking: 101,
reqdReputation: 3.2e6,
repMultiplier: 1.75,
},
{
name: posNames.SecurityCompanyPositions[0], // Police Officer
nextPosition: posNames.SecurityCompanyPositions[1], // Police Chief
baseSalary: 82,
hackingEffectiveness: 5,
strengthEffectiveness: 20,
defenseEffectiveness: 20,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 15,
hackingExpGain: 0.02,
strengthExpGain: 0.08,
defenseExpGain: 0.08,
dexterityExpGain: 0.08,
agilityExpGain: 0.08,
charismaExpGain: 0.04,
reqdHacking: 11,
reqdStrength: 101,
reqdDefense: 101,
reqdDexterity: 101,
reqdAgility: 101,
reqdCharisma: 51,
reqdReputation: 8e3,
repMultiplier: 1,
},
{
name: posNames.SecurityCompanyPositions[1], // Police Chief
nextPosition: null,
baseSalary: 460,
hackingEffectiveness: 5,
strengthEffectiveness: 20,
defenseEffectiveness: 20,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 15,
hackingExpGain: 0.02,
strengthExpGain: 0.1,
defenseExpGain: 0.1,
dexterityExpGain: 0.1,
agilityExpGain: 0.1,
charismaExpGain: 0.1,
reqdHacking: 101,
reqdStrength: 301,
reqdDefense: 301,
reqdDexterity: 301,
reqdAgility: 301,
reqdCharisma: 151,
reqdReputation: 36e3,
repMultiplier: 1.25,
},
{
name: posNames.SecurityCompanyPositions[2], // Security Guard
nextPosition: posNames.SecurityCompanyPositions[3], // Security Officer
baseSalary: 50,
hackingEffectiveness: 5,
strengthEffectiveness: 20,
defenseEffectiveness: 20,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 15,
hackingExpGain: 0.01,
strengthExpGain: 0.04,
defenseExpGain: 0.04,
dexterityExpGain: 0.04,
agilityExpGain: 0.04,
charismaExpGain: 0.02,
reqdStrength: 51,
reqdDefense: 51,
reqdDexterity: 51,
reqdAgility: 51,
reqdCharisma: 1,
repMultiplier: 1,
},
{
name: posNames.SecurityCompanyPositions[3], // Security Officer
nextPosition: posNames.SecurityCompanyPositions[4], // Security Supervisor
baseSalary: 195,
hackingEffectiveness: 10,
strengthEffectiveness: 20,
defenseEffectiveness: 20,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 10,
hackingExpGain: 0.02,
strengthExpGain: 0.1,
defenseExpGain: 0.1,
dexterityExpGain: 0.1,
agilityExpGain: 0.1,
charismaExpGain: 0.05,
reqdHacking: 26,
reqdStrength: 151,
reqdDefense: 151,
reqdDexterity: 151,
reqdAgility: 151,
reqdCharisma: 51,
reqdReputation: 8e3,
repMultiplier: 1.1,
},
{
name: posNames.SecurityCompanyPositions[4], // Security Supervisor
nextPosition: posNames.SecurityCompanyPositions[5], // Head of Security
baseSalary: 660,
hackingEffectiveness: 10,
strengthEffectiveness: 15,
defenseEffectiveness: 15,
dexterityEffectiveness: 15,
agilityEffectiveness: 15,
charismaEffectiveness: 30,
hackingExpGain: 0.02,
strengthExpGain: 0.12,
defenseExpGain: 0.12,
dexterityExpGain: 0.12,
agilityExpGain: 0.12,
charismaExpGain: 0.1,
reqdHacking: 26,
reqdStrength: 251,
reqdDefense: 251,
reqdDexterity: 251,
reqdAgility: 251,
reqdCharisma: 101,
reqdReputation: 36e3,
repMultiplier: 1.25,
},
{
name: posNames.SecurityCompanyPositions[5], // Head of Security
nextPosition: null,
baseSalary: 1320,
hackingEffectiveness: 10,
strengthEffectiveness: 15,
defenseEffectiveness: 15,
dexterityEffectiveness: 15,
agilityEffectiveness: 15,
charismaEffectiveness: 30,
hackingExpGain: 0.05,
strengthExpGain: 0.15,
defenseExpGain: 0.15,
dexterityExpGain: 0.15,
agilityExpGain: 0.15,
charismaExpGain: 0.15,
reqdHacking: 51,
reqdStrength: 501,
reqdDefense: 501,
reqdDexterity: 501,
reqdAgility: 501,
reqdCharisma: 151,
reqdReputation: 144e3,
repMultiplier: 1.4,
},
{
name: posNames.AgentCompanyPositions[0], // Field Agent
nextPosition: posNames.AgentCompanyPositions[1], // Secret Agent
baseSalary: 330,
hackingEffectiveness: 10,
strengthEffectiveness: 15,
defenseEffectiveness: 15,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 20,
hackingExpGain: 0.04,
strengthExpGain: 0.08,
defenseExpGain: 0.08,
dexterityExpGain: 0.08,
agilityExpGain: 0.08,
charismaExpGain: 0.05,
reqdHacking: 101,
reqdStrength: 101,
reqdDefense: 101,
reqdDexterity: 101,
reqdAgility: 101,
reqdCharisma: 101,
reqdReputation: 8e3,
repMultiplier: 1,
},
{
name: posNames.AgentCompanyPositions[1], // Secret Agent
nextPosition: posNames.AgentCompanyPositions[2], // Special Operative
baseSalary: 990,
hackingEffectiveness: 15,
strengthEffectiveness: 15,
defenseEffectiveness: 15,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 15,
hackingExpGain: 0.1,
strengthExpGain: 0.15,
defenseExpGain: 0.15,
dexterityExpGain: 0.15,
agilityExpGain: 0.15,
charismaExpGain: 0.1,
reqdHacking: 201,
reqdStrength: 251,
reqdDefense: 251,
reqdDexterity: 251,
reqdAgility: 251,
reqdCharisma: 201,
reqdReputation: 32e3,
repMultiplier: 1.25,
},
{
name: posNames.AgentCompanyPositions[2], // Special Operative
nextPosition: null,
baseSalary: 2000,
hackingEffectiveness: 15,
strengthEffectiveness: 15,
defenseEffectiveness: 15,
dexterityEffectiveness: 20,
agilityEffectiveness: 20,
charismaEffectiveness: 15,
hackingExpGain: 0.15,
strengthExpGain: 0.2,
defenseExpGain: 0.2,
dexterityExpGain: 0.2,
agilityExpGain: 0.2,
charismaExpGain: 0.15,
reqdHacking: 251,
reqdStrength: 501,
reqdDefense: 501,
reqdDexterity: 501,
reqdAgility: 501,
reqdCharisma: 251,
reqdReputation: 162e3,
repMultiplier: 1.5,
},
{
name: posNames.MiscCompanyPositions[0], // Waiter
nextPosition: null,
baseSalary: 22,
strengthEffectiveness: 10,
dexterityEffectiveness: 10,
agilityEffectiveness: 10,
charismaEffectiveness: 70,
strengthExpGain: 0.02,
defenseExpGain: 0.02,
dexterityExpGain: 0.02,
agilityExpGain: 0.02,
charismaExpGain: 0.05,
repMultiplier: 1,
},
{
name: posNames.MiscCompanyPositions[1], // Employee
nextPosition: null,
baseSalary: 22,
strengthEffectiveness: 10,
dexterityEffectiveness: 10,
agilityEffectiveness: 10,
charismaEffectiveness: 70,
strengthExpGain: 0.02,
defenseExpGain: 0.02,
dexterityExpGain: 0.02,
agilityExpGain: 0.02,
charismaExpGain: 0.04,
repMultiplier: 1,
},
{
name: posNames.SoftwareConsultantCompanyPositions[0], // Software Consultant
nextPosition: posNames.SoftwareConsultantCompanyPositions[1], // Senior Software Consultant
baseSalary: 66,
hackingEffectiveness: 80,
charismaEffectiveness: 20,
hackingExpGain: 0.08,
charismaExpGain: 0.03,
reqdHacking: 51,
repMultiplier: 1,
},
{
name: posNames.SoftwareConsultantCompanyPositions[1], // Senior Software Consultant
nextPosition: null,
baseSalary: 132,
hackingEffectiveness: 75,
charismaEffectiveness: 25,
hackingExpGain: 0.25,
charismaExpGain: 0.06,
reqdHacking: 251,
reqdCharisma: 51,
repMultiplier: 1.2,
},
{
name: posNames.BusinessConsultantCompanyPositions[0], // Business Consultant
nextPosition: posNames.BusinessConsultantCompanyPositions[1], // Senior Business Consultant
baseSalary: 66,
hackingEffectiveness: 20,
charismaEffectiveness: 80,
hackingExpGain: 0.015,
charismaExpGain: 0.15,
reqdHacking: 6,
reqdCharisma: 51,
repMultiplier: 1,
},
{
name: posNames.BusinessConsultantCompanyPositions[1], // Senior Business Consultant
nextPosition: null,
baseSalary: 525,
hackingEffectiveness: 15,
charismaEffectiveness: 85,
hackingExpGain: 0.015,
charismaExpGain: 0.3,
reqdHacking: 51,
reqdCharisma: 226,
repMultiplier: 1.2,
},
{
name: posNames.PartTimeCompanyPositions[0], // Part-time waiter
nextPosition: null,
baseSalary: 20,
strengthEffectiveness: 10,
dexterityEffectiveness: 10,
agilityEffectiveness: 10,
charismaEffectiveness: 70,
strengthExpGain: 0.0075,
defenseExpGain: 0.0075,
dexterityExpGain: 0.0075,
agilityExpGain: 0.0075,
charismaExpGain: 0.04,
repMultiplier: 1,
},
{
name: posNames.PartTimeCompanyPositions[1], // Part-time employee
nextPosition: null,
baseSalary: 20,
strengthEffectiveness: 10,
dexterityEffectiveness: 10,
agilityEffectiveness: 10,
charismaEffectiveness: 70,
strengthExpGain: 0.0075,
defenseExpGain: 0.0075,
dexterityExpGain: 0.0075,
agilityExpGain: 0.0075,
charismaExpGain: 0.03,
repMultiplier: 1,
},
]

@ -0,0 +1,72 @@
// Defs for job titles, stored in arrays and categorized by job "type"
export const SoftwareCompanyPositions: string[] = [
"Software Engineering Intern",
"Junior Software Engineer",
"Senior Software Engineer",
"Lead Software Developer",
"Head of Software",
"Head of Engineering",
"Vice President of Technology",
"Chief Technology Officer"
];
export const ITCompanyPositions: string[] = [
"IT Intern",
"IT Analyst",
"IT Manager",
"Systems Administrator"
];
export const SecurityEngineerCompanyPositions: string[] = [
"Security Engineer"
];
export const NetworkEngineerCompanyPositions: string[] = [
"Network Engineer",
"Network Administrator"
];
export const BusinessCompanyPositions: string[] = [
"Business Intern",
"Business Analyst",
"Business Manager",
"Operations Manager",
"Chief Financial Officer",
"Chief Executive Officer"
];
export const SecurityCompanyPositions: string[] = [
"Police Officer",
"Police Chief",
"Security Guard",
"Security Officer",
"Security Supervisor",
"Head of Security"
];
export const AgentCompanyPositions: string[] = [
"Field Agent",
"Secret Agent",
"Special Operative"
];
export const MiscCompanyPositions: string[] = [
"Waiter",
"Employee"
];
export const SoftwareConsultantCompanyPositions: string[] = [
"Software Consultant",
"Senior Software Consultant"
];
export const BusinessConsultantCompanyPositions: string[] = [
"Business Consultant",
"Senior Business Consultant"
];
export const PartTimeCompanyPositions: string[] = [
"Part-time Waiter",
"Part-time Employee"
];

@ -1,5 +1,7 @@
let CONSTANTS = {
Version: "0.41.1",
import {IMap} from "./types";
export let CONSTANTS: IMap<any> = {
Version: "0.41.2",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -509,8 +511,9 @@ let CONSTANTS = {
* Gang Changes:
** UI now displays your chance to win a clash with other gangs
** Added getChanceToWinClash() function to the Gang API
* Added the terminal command 'expr', which can be used to evaluate simple mathematical expressions
* Bug Fix: scp() should no longer throw errors when used with 2-arguments and an array of files
`
}
export {CONSTANTS};

@ -10,6 +10,7 @@ export const TerminalHelpText: string =
"cls See 'clear' command <br>" +
"connect [ip/hostname] Connects to a remote server<br>" +
"download [script/text file] Downloads scripts or text files to your computer<br>" +
"expr [math expression] Evaluate a mathematical expression<br>" +
"free Check the machine's memory (RAM) usage<br>" +
"hack Hack the current machine<br>" +
"help [command] Display this help text, or the help text for a command<br>" +
@ -96,6 +97,12 @@ export const HelpTexts: IMap<string> = {
"Download all scripts and text files: download *<br>" +
"Download all scripts: download *.script<br>" +
"Download all text files: download *.txt<br>",
expr: "expr [mathematical expression]<br>" +
"Evaluate a simple mathematical expression. Supports native JavaScript operators:<br>" +
"+, -, /, *, **, %<br>" +
"Example:<br>" +
"expr 25 * 2 ** 10<br>" +
"Note that letters (non-digits) are not allowed and will be removed from the input.",
free: "free<br>" +
"Display's the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as " +
"how much of it is being used.",

@ -1,6 +1,8 @@
import {Bladeburner} from "./Bladeburner";
import {CompanyPositions, initCompanies,
Companies, getJobRequirementText} from "./Company";
import {CompanyPositions} from "./Company/CompanyPositions";
import {Companies} from "./Company/Companies";
import {getJobRequirementText} from "./Company/GetJobRequirementText";
import * as posNames from "./Company/data/CompanyPositionNames";
import {Corporation} from "./CompanyManagement";
import {CONSTANTS} from "./Constants";
import {Crimes} from "./Crimes";
@ -233,7 +235,7 @@ function displayLocationContent() {
//Check if the player is employed at this Location. If he is, display the "Work" button,
//update the job title, etc.
if (loc != "" && loc === Player.companyName) {
var company = Companies[loc];
let company = Companies[loc];
jobTitle.style.display = "block";
jobReputation.style.display = "inline";
@ -241,8 +243,8 @@ function displayLocationContent() {
locationTxtDiv1.style.display = "block";
locationTxtDiv2.style.display = "block";
locationTxtDiv3.style.display = "block";
jobTitle.innerHTML = "Job Title: " + Player.companyPosition.positionName;
var repGain = company.getFavorGain();
jobTitle.innerHTML = "Job Title: " + Player.companyPosition;
let repGain = company.getFavorGain();
if (repGain.length != 2) {repGain = 0;}
repGain = repGain[0];
jobReputation.innerHTML = "Company reputation: " + formatNumber(company.playerReputation, 4) +
@ -256,7 +258,10 @@ function displayLocationContent() {
"favor you gain depends on how much reputation you have with the company</span>";
work.style.display = "block";
var currPos = Player.companyPosition;
let currPos = CompanyPositions[Player.companyPosition];
if (currPos == null) {
throw new Error("Player's companyPosition property has an invalid value");
}
work.addEventListener("click", function() {
if (currPos.isPartTimeJob()) {
@ -301,19 +306,19 @@ function displayLocationContent() {
var hospitalTreatmentCost = (Player.max_hp - Player.hp) * CONSTANTS.HospitalCostPerHp;
//Set tooltip for job requirements
setJobRequirementTooltip(loc, CompanyPositions.SoftwareIntern, softwareJob);
setJobRequirementTooltip(loc, CompanyPositions.SoftwareConsultant, softwareConsultantJob);
setJobRequirementTooltip(loc, CompanyPositions.ITIntern, itJob);
setJobRequirementTooltip(loc, CompanyPositions.SecurityEngineer, securityEngineerJob);
setJobRequirementTooltip(loc, CompanyPositions.NetworkEngineer, networkEngineerJob);
setJobRequirementTooltip(loc, CompanyPositions.BusinessIntern, businessJob);
setJobRequirementTooltip(loc, CompanyPositions.BusinessConsultant, businessConsultantJob);
setJobRequirementTooltip(loc, CompanyPositions.SecurityGuard, securityJob);
setJobRequirementTooltip(loc, CompanyPositions.FieldAgent, agentJob);
setJobRequirementTooltip(loc, CompanyPositions.Employee, employeeJob);
setJobRequirementTooltip(loc, CompanyPositions.PartTimeEmployee, employeePartTimeJob);
setJobRequirementTooltip(loc, CompanyPositions.Waiter, waiterJob);
setJobRequirementTooltip(loc, CompanyPositions.PartTimeWaiter, waiterPartTimeJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.SoftwareCompanyPositions[0]], softwareJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], softwareConsultantJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.ITCompanyPositions[0]], itJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], securityEngineerJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], networkEngineerJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessCompanyPositions[0]], businessJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], businessConsultantJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.SecurityCompanyPositions[0]], securityJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.AgentCompanyPositions[0]], agentJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.MiscCompanyPositions[1]], employeeJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.PartTimeCompanyPositions[1]], employeePartTimeJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.MiscCompanyPositions[0]], waiterJob);
setJobRequirementTooltip(loc, CompanyPositions[posNames.PartTimeCompanyPositions[0]], waiterPartTimeJob);
switch (loc) {
case Locations.AevumTravelAgency:
@ -1030,18 +1035,18 @@ function displayLocationContent() {
console.log("ERROR: INVALID LOCATION");
}
//Make the "Apply to be Employee and Waiter" texts disappear if you already hold the job
//Includes part-time stuff
// Make the "Apply to be Employee and Waiter" texts disappear if you already hold the job
// Includes part-time stuff
if (loc == Player.companyName) {
var currPos = Player.companyPosition;
if (currPos.positionName == CompanyPositions.Employee.positionName) {
if (currPos == "Employee") {
employeeJob.style.display = "none";
} else if (currPos.positionName == CompanyPositions.Waiter.positionName) {
} else if (currPos == "Waiter") {
waiterJob.style.display = "none";
} else if (currPos.positionName == CompanyPositions.PartTimeEmployee.positionName) {
} else if (currPos == "Part-time Employee") {
employeePartTimeJob.style.display = "none";
} else if (currPos.positionName == CompanyPositions.PartTimeWaiter.positionName) {
} else if (currPos == "Part-time Waiter") {
waiterPartTimeJob.style.display = "none";
}
}
@ -2173,8 +2178,8 @@ function setJobRequirementTooltip(loc, entryPosType, btn) {
var company = Companies[loc];
if (company == null) {return;}
var pos = Player.getNextCompanyPosition(company, entryPosType);
if (pos == null) {return};
if (!company.hasPosition(pos)) {return;}
if (pos == null) { return };
if (!company.hasPosition(pos)) { return; }
var reqText = getJobRequirementText(company, pos, true);
btn.innerHTML += "<span class='tooltiptext'>" + reqText + "</span>";
}

@ -8,8 +8,10 @@ import {Augmentations, Augmentation,
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {determineCrimeSuccess, findCrime} from "./Crimes";
import {Bladeburner} from "./Bladeburner";
import {Companies, Company, CompanyPosition,
CompanyPositions, companyExists} from "./Company";
import {Company} from "./Company/Company";
import {Companies, companyExists} from "./Company/Companies";
import {CompanyPosition} from "./Company/CompanyPosition";
import {CompanyPositions} from "./Company/CompanyPositions";
import {CONSTANTS} from "./Constants";
import {Programs} from "./CreateProgram";
import {DarkWebItems} from "./DarkWeb";
@ -919,7 +921,7 @@ function NetscriptFunctions(workerScript) {
var destServer, currServ;
if (arguments.length === 3) { //scriptname, source, destination
if (ip2 != null) { // 3 Argument version: scriptname, source, destination
if (scriptname === undefined || ip1 === undefined || ip2 === undefined) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
}
@ -932,7 +934,7 @@ function NetscriptFunctions(workerScript) {
if (currServ == null) {
throw makeRuntimeRejectMsg(workerScript, `ERROR: Invalid hostname/ip passed into scp() command: ${ip1}`);
}
} else if (arguments.length === 2) { //scriptname, destination
} else if (ip1 != null) { // 2 Argument version: scriptname, destination
if (scriptname === undefined || ip1 === undefined) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
}
@ -945,6 +947,8 @@ function NetscriptFunctions(workerScript) {
if (currServ == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find server ip for this script. This is a bug please contact game developer");
}
} else {
throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
}
//Scp for lit files
@ -2783,8 +2787,8 @@ function NetscriptFunctions(workerScript) {
}
var companyPositionTitle = "";
if (Player.companyPosition instanceof CompanyPosition) {
companyPositionTitle = Player.companyPosition.positionName;
if (CompanyPositions[Player.companyPosition] instanceof CompanyPosition) {
companyPositionTitle = Player.companyPosition;
}
return {
bitnode: Player.bitNodeN,
@ -2925,7 +2929,8 @@ function NetscriptFunctions(workerScript) {
return;
}
if (Player.companyPosition == "" || !(Player.companyPosition instanceof CompanyPosition)) {
const companyPosition = CompanyPositions[Player.companyPosition];
if (Player.companyPosition === "" || !(companyPosition instanceof CompanyPosition)) {
workerScript.scriptRef.log("ERROR: workForCompany() failed because you do not have a job");
return false;
}
@ -2937,13 +2942,13 @@ function NetscriptFunctions(workerScript) {
}
}
if (Player.companyPosition.isPartTimeJob()) {
if (companyPosition.isPartTimeJob()) {
Player.startWorkPartTime();
} else {
Player.startWork();
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.workForCompany == null) {
workerScript.scriptRef.log("Began working at " + Player.companyName + " as a " + Player.companyPosition.positionName);
workerScript.log(`Began working at ${Player.companyName} as a ${Player.companyPosition}`);
}
return true;
},
@ -3019,11 +3024,11 @@ function NetscriptFunctions(workerScript) {
}
if (res) {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
workerScript.scriptRef.log("You were offered a new job at " + companyName + " as a " + Player.companyPosition.positionName);
workerScript.log(`You were offered a new job at ${companyName} as a ${Player.companyPosition}`);
}
} else {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
workerScript.scriptRef.log("You failed to get a new job/promotion at " + companyName + " in the " + field + " field.");
workerScript.log(`You failed to get a new job/promotion at ${companyName} in the ${field} field.`);
}
}
return res;

@ -3,9 +3,12 @@ import {Augmentations, applyAugmentation,
PlayerOwnedAugmentation} from "./Augmentations";
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {CodingContractRewardType} from "./CodingContracts";
import {Company, Companies, getNextCompanyPosition,
getJobRequirementText, CompanyPosition,
CompanyPositions} from "./Company";
import {Company} from "./Company/Company";
import {Companies} from "./Company/Companies";
import {getNextCompanyPosition} from "./Company/GetNextCompanyPosition";
import {getJobRequirementText} from "./Company/GetJobRequirementText";
import {CompanyPositions} from "./Company/CompanyPositions";
import * as posNames from "./Company/data/CompanyPositionNames";
import {CONSTANTS} from "./Constants";
import {Corporation} from "./CompanyManagement";
import {Programs} from "./CreateProgram";
@ -94,8 +97,8 @@ function PlayerObject() {
this.location = "";
//Company Information
this.companyName = ""; //Name of Company, equivalent to an object from Locations
this.companyPosition = ""; //CompanyPosition object
this.companyName = ""; // Name of Company. Must match a key value in Companies map
this.companyPosition = ""; // Name of Company Position. Must match a key value in CompanyPositions map
//Servers
this.currentServer = ""; //IP address of Server currently being accessed through terminal
@ -709,13 +712,13 @@ PlayerObject.prototype.work = function(numCycles) {
var comp = Companies[this.companyName], companyRep = "0";
if (comp == null || !(comp instanceof Company)) {
console.log("ERROR: Could not find Company: " + this.companyName);
console.error(`Could not find Company: ${this.companyName}`);
} else {
companyRep = comp.playerReputation;
}
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName +
txt.innerHTML = "You are currently working as a " + this.companyPosition +
" at " + this.companyName + " (Current Company Reputation: " +
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
@ -837,7 +840,7 @@ PlayerObject.prototype.workPartTime = function(numCycles) {
}
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName +
txt.innerHTML = "You are currently working as a " + this.companyPosition +
" at " + Player.companyName + " (Current Company Reputation: " +
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
@ -1069,70 +1072,126 @@ PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) {
//Money gained per game cycle
PlayerObject.prototype.getWorkMoneyGain = function() {
var bn11Mult = 1;
var company = Companies[this.companyName];
if (hasBn11SF) {
bn11Mult = 1 + (company.favor / 100);
// If player has SF-11, calculate salary multiplier from favor
let bn11Mult = 1;
const company = Companies[this.companyName];
if (hasBn11SF) { bn11Mult = 1 + (company.favor / 100); }
// Get base salary
const companyPosition = CompanyPositions[this.companyPosition];
if (companyPosition == null) {
console.error(`Could not find CompanyPosition object for ${this.companyPosition}. Work salary will be 0`);
return 0;
}
return this.companyPosition.baseSalary * company.salaryMultiplier *
this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney * bn11Mult;
return companyPosition.baseSalary * company.salaryMultiplier * this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney * bn11Mult;
}
//Hack exp gained per game cycle
PlayerObject.prototype.getWorkHackExpGain = function() {
var company = Companies[this.companyName];
return this.companyPosition.hackingExpGain * company.expMultiplier *
this.hacking_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work hack exp gain will be 0`].join(" "));
return 0;
}
return companyPosition.hackingExpGain * company.expMultiplier * this.hacking_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
}
//Str exp gained per game cycle
PlayerObject.prototype.getWorkStrExpGain = function() {
var company = Companies[this.companyName];
return this.companyPosition.strengthExpGain * company.expMultiplier *
this.strength_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work str exp gain will be 0`].join(" "));
return 0;
}
return companyPosition.strengthExpGain * company.expMultiplier * this.strength_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
}
//Def exp gained per game cycle
PlayerObject.prototype.getWorkDefExpGain = function() {
var company = Companies[this.companyName];
return this.companyPosition.defenseExpGain * company.expMultiplier *
this.defense_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work def exp gain will be 0`].join(" "));
return 0;
}
return companyPosition.defenseExpGain * company.expMultiplier * this.defense_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
}
//Dex exp gained per game cycle
PlayerObject.prototype.getWorkDexExpGain = function() {
var company = Companies[this.companyName];
return this.companyPosition.dexterityExpGain * company.expMultiplier *
this.dexterity_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work dex exp gain will be 0`].join(" "));
return 0;
}
return companyPosition.dexterityExpGain * company.expMultiplier * this.dexterity_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
}
//Agi exp gained per game cycle
PlayerObject.prototype.getWorkAgiExpGain = function() {
var company = Companies[this.companyName];
return this.companyPosition.agilityExpGain * company.expMultiplier *
this.agility_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work agi exp gain will be 0`].join(" "));
return 0;
}
return companyPosition.agilityExpGain * company.expMultiplier * this.agility_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
}
//Charisma exp gained per game cycle
PlayerObject.prototype.getWorkChaExpGain = function() {
var company = Companies[this.companyName];
return this.companyPosition.charismaExpGain * company.expMultiplier *
this.charisma_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work cha exp gain will be 0`].join(" "));
return 0;
}
return companyPosition.charismaExpGain * company.expMultiplier * this.charisma_exp_mult * BitNodeMultipliers.CompanyWorkExpGain;
}
//Reputation gained per game cycle
PlayerObject.prototype.getWorkRepGain = function() {
var company = Companies[this.companyName];
var jobPerformance = this.companyPosition.calculateJobPerformance(this.hacking_skill, this.strength,
this.defense, this.dexterity,
this.agility, this.charisma);
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`Work rep gain will be 0`].join(" "));
return 0;
}
var jobPerformance = companyPosition.calculateJobPerformance(this.hacking_skill, this.strength,
this.defense, this.dexterity,
this.agility, this.charisma);
//Intelligence provides a flat bonus to job performance
jobPerformance += (this.intelligence / CONSTANTS.MaxSkillLevel);
//Update reputation gain rate to account for company favor
var favorMult = 1 + (company.favor / 100);
if (isNaN(favorMult)) {favorMult = 1;}
if (isNaN(favorMult)) { favorMult = 1; }
return jobPerformance * this.company_rep_mult * favorMult;
}
@ -1611,20 +1670,25 @@ PlayerObject.prototype.hospitalize = function() {
//The 'sing' argument designates whether or not this is being called from
//the applyToCompany() Netscript Singularity function
PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
var currCompany = "";
if (this.companyName != "") {
// Get current company and job
let currCompany = null;
if (this.companyName !== "") {
currCompany = Companies[this.companyName];
}
var currPositionName = "";
if (this.companyPosition != "") {
currPositionName = this.companyPosition.positionName;
}
var company = Companies[this.location]; //Company being applied to
if (sing && !(company instanceof Company)) {
return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed";
const currPositionName = this.companyPosition;
// Get company that's being applied to
const company = Companies[this.location]; //Company being applied to
if (!(company instanceof Company)) {
if (sing) {
return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed";
} else {
console.error(`Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`);
return;
}
}
var pos = entryPosType;
let pos = entryPosType;
if (!this.isQualified(company, pos)) {
var reqText = getJobRequirementText(company, pos);
@ -1634,8 +1698,7 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
}
while (true) {
if (Engine.Debug) {console.log("Determining qualification for next Company Position");}
var newPos = getNextCompanyPosition(pos);
let newPos = getNextCompanyPosition(pos);
if (newPos == null) {break;}
//Check if this company has this position
@ -1651,9 +1714,8 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
}
//Check if the determined job is the same as the player's current job
if (currCompany != "") {
if (currCompany.companyName == company.companyName &&
pos.positionName == currPositionName) {
if (currCompany != null) {
if (currCompany.name == company.name && pos.name == currPositionName) {
var nextPos = getNextCompanyPosition(pos);
if (nextPos == null) {
if (sing) {return false;}
@ -1672,31 +1734,30 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
//Lose reputation from a Company if you are leaving it for another job
var leaveCompany = false;
var oldCompanyName = "";
if (currCompany != "") {
if (currCompany.companyName != company.companyName) {
let leaveCompany = false;
let oldCompanyName = "";
if (currCompany != null) {
if (currCompany.name != company.name) {
leaveCompany = true;
oldCompanyName = currCompany.companyName;
company.playerReputation -= 1000;
if (company.playerReputation < 0) {company.playerReputation = 0;}
oldCompanyName = currCompany.name;
currCompany.playerReputation -= 1000;
if (currCompany.playerReputation < 0) { currCompany.playerReputation = 0; }
}
}
this.companyName = company.companyName;
this.companyPosition = pos;
this.companyName = company.name;
this.companyPosition = pos.name;
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (leaveCompany) {
if (sing) {return true;}
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " +
pos.positionName + "!<br>" +
"You lost 1000 reputation at your old company " + oldCompanyName + " because you left.");
if (sing) { return true; }
dialogBoxCreate([`Congratulations! You were offered a new job at ${this.companyName} as a ${pos.name}!`,
`You lost 1000 reputation at your old company ${oldCompanyName} because you left.`].join("<br>"));
} else {
if (sing) {return true;}
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.positionName + "!");
if (sing) { return true; }
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
}
Engine.loadLocationContent();
@ -1705,51 +1766,51 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
//Returns your next position at a company given the field (software, business, etc.)
PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType) {
var currCompany = null;
if (this.companyName != "") {
if (this.companyName !== "") {
currCompany = Companies[this.companyName];
}
//Not employed at this company, so return the entry position
if (currCompany == null || (currCompany.companyName != company.companyName)) {
if (currCompany == null || (currCompany.name != company.name)) {
return entryPosType;
}
//If the entry pos type and the player's current position have the same type,
//return the player's "nextCompanyPosition". Otherwise return the entryposType
//Employed at this company, so just return the next position if it exists.
if ((this.companyPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) ||
(this.companyPosition.isITJob() && entryPosType.isITJob()) ||
(this.companyPosition.isBusinessJob() && entryPosType.isBusinessJob()) ||
(this.companyPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) ||
(this.companyPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) ||
(this.companyPosition.isSecurityJob() && entryPosType.isSecurityJob()) ||
(this.companyPosition.isAgentJob() && entryPosType.isAgentJob()) ||
(this.companyPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) ||
(this.companyPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) ||
(this.companyPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) {
return getNextCompanyPosition(this.companyPosition);
const currentPosition = CompanyPositions[this.companyPosition];
if ((currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) ||
(currentPosition.isITJob() && entryPosType.isITJob()) ||
(currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) ||
(currentPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) ||
(currentPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) ||
(currentPosition.isSecurityJob() && entryPosType.isSecurityJob()) ||
(currentPosition.isAgentJob() && entryPosType.isAgentJob()) ||
(currentPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) ||
(currentPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) ||
(currentPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) {
return getNextCompanyPosition(currentPosition);
}
return entryPosType;
}
PlayerObject.prototype.applyForSoftwareJob = function(sing=false) {
return this.applyForJob(CompanyPositions.SoftwareIntern, sing);
return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
}
PlayerObject.prototype.applyForSoftwareConsultantJob = function(sing=false) {
return this.applyForJob(CompanyPositions.SoftwareConsultant, sing);
return this.applyForJob(CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], sing);
}
PlayerObject.prototype.applyForItJob = function(sing=false) {
return this.applyForJob(CompanyPositions.ITIntern, sing);
return this.applyForJob(CompanyPositions[posNames.ITCompanyPositions[0]], sing);
}
PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.SecurityEngineer)) {
return this.applyForJob(CompanyPositions.SecurityEngineer, sing);
if (this.isQualified(company, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing);
} else {
if (sing) {return false;}
dialogBoxCreate("Unforunately, you do not qualify for this position");
@ -1758,8 +1819,8 @@ PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) {
PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.NetworkEngineer)) {
return this.applyForJob(CompanyPositions.NetworkEngineer, sing);
if (this.isQualified(company, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], sing);
} else {
if (sing) {return false;}
dialogBoxCreate("Unforunately, you do not qualify for this position");
@ -1767,22 +1828,23 @@ PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) {
}
PlayerObject.prototype.applyForBusinessJob = function(sing=false) {
return this.applyForJob(CompanyPositions.BusinessIntern, sing);
return this.applyForJob(CompanyPositions[posNames.BusinessCompanyPositions[0]], sing);
}
PlayerObject.prototype.applyForBusinessConsultantJob = function(sing=false) {
return this.applyForJob(CompanyPositions.BusinessConsultant, sing);
return this.applyForJob(CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], sing);
}
PlayerObject.prototype.applyForSecurityJob = function(sing=false) {
//TODO If case for POlice departments
return this.applyForJob(CompanyPositions.SecurityGuard, sing);
// TODO Police Jobs
// Indexing starts at 2 because 0 is for police officer
return this.applyForJob(CompanyPositions[posNames.SecurityCompanyPositions[2]], sing);
}
PlayerObject.prototype.applyForAgentJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.FieldAgent)) {
return this.applyForJob(CompanyPositions.FieldAgent, sing);
if (this.isQualified(company, CompanyPositions[posNames.AgentCompanyPositions[0]])) {
return this.applyForJob(CompanyPositions[posNames.AgentCompanyPositions[0]], sing);
} else {
if (sing) {return false;}
dialogBoxCreate("Unforunately, you do not qualify for this position");
@ -1791,9 +1853,9 @@ PlayerObject.prototype.applyForAgentJob = function(sing=false) {
PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.Employee)) {
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.Employee;
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
this.companyName = company.name;
this.companyPosition = posNames.MiscCompanyPositions[1];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1807,9 +1869,9 @@ PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.PartTimeEmployee)) {
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.PartTimeEmployee;
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
this.companyName = company.name;
this.companyPosition = posNames.PartTimeCompanyPositions[1];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1823,9 +1885,9 @@ PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.Waiter)) {
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.Waiter;
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
this.companyName = company.name;
this.companyPosition = posNames.MiscCompanyPositions[0];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1839,9 +1901,9 @@ PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.PartTimeWaiter)) {
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.PartTimeWaiter;
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
this.companyName = company.name;
this.companyPosition = posNames.PartTimeCompanyPositions[0];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -2156,10 +2218,12 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
//Silhouette
var silhouetteFac = Factions["Silhouette"];
const companyPosition = CompanyPositions[this.companyPosition];
if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited &&
(this.companyPosition.positionName == CompanyPositions.CTO.positionName ||
this.companyPosition.positionName == CompanyPositions.CFO.positionName ||
this.companyPosition.positionName == CompanyPositions.CEO.positionName) &&
companyPosition != null &&
(companyPosition.name == "Chief Technology Officer" ||
companyPosition.name == "Chief Financial Officer" ||
companyPosition.name == "Chief Executive Officer") &&
this.money.gte(15000000) && this.karma <= -22) {
invitedFactions.push(silhouetteFac);
}

@ -4,7 +4,7 @@ import {Augmentations, augmentationExists,
import {initBitNodeMultipliers} from "./BitNode";
import {Bladeburner} from "./Bladeburner";
import {writeCinematicText} from "./CinematicText";
import {Companies, Company, initCompanies} from "./Company";
import {Companies, initCompanies} from "./Company/Companies";
import {Programs} from "./CreateProgram";
import {Engine} from "./engine";
import {Factions, Faction, initFactions,

@ -1,7 +1,7 @@
import {loadAliases, loadGlobalAliases,
Aliases, GlobalAliases} from "./Alias";
import {loadCompanies, Companies,
CompanyPositions} from "./Company";
import {Companies, loadCompanies} from "./Company/Companies";
import {CompanyPosition} from "./Company/CompanyPosition";
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
import {loadFactions, Factions,
@ -110,6 +110,41 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
createStatusText("Game saved!");
}
// Makes necessary changes to the loaded/imported data to ensure
// the game stills works with new versions
function evaluateVersionCompatibility(ver) {
// This version refactored the Company/job-related code
if (ver <= "0.41.2") {
// Player's company position is now a string
if (Player.companyPosition != null && typeof Player.companyPosition !== "string") {
console.log("Changed Player.companyPosition value to be compatible with v0.41.2");
Player.companyPosition = Player.companyPosition.data.positionName;
if (Player.companyPosition == null) {
Player.companyPosition = "";
}
}
// The "companyName" property of all Companies is renamed to "name"
for (var companyName in Companies) {
const company = Companies[companyName];
if (company.name == null && company.companyName != null) {
console.log("Changed company name property to be compatible with v0.41.2");
company.name = company.companyName;
}
if (company.companyPositions instanceof Array) {
console.log("Changed company companyPositions property to be compatible with v0.41.2");
const pos = {};
for (let i = 0; i < company.companyPositions.length; ++i) {
pos[company.companyPositions[i]] = true;
}
company.companyPositions = pos;
}
}
}
}
function loadGame(saveString) {
if (saveString === "" || saveString == null || saveString === undefined) {
if (!window.localStorage.getItem("bitburnerSave")) {
@ -187,28 +222,8 @@ function loadGame(saveString) {
if (saveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(saveObj.VersionSave, Reviver);
if (Player.bitNodeN == null || Player.bitNodeN === 0) {
Player.setBitNodeNumber(1);
}
if (ver.startsWith("0.27.") || ver.startsWith("0.28.")) {
console.log("Evaluating changes needed for version compatibility");
if (Player.augmentations.length > 0 || Player.queuedAugmentations.length > 0 ||
Player.sourceFiles.length > 0) {
//If you have already purchased an Aug...you are far enough in the game
//that everything should be available
Player.firstFacInvRecvd = true;
Player.firstAugPurchased = true;
Player.firstTimeTraveled = true;
Player.firstProgramAvailable = true;
} else {
if (Player.factions.length > 0 || Player.factionInvitations.length > 0) {
Player.firstFacInvRecvd = true;
}
if (Player.hacking_skill >= 25) {
Player.firstScriptAvailable = true;
}
}
}
evaluateVersionCompatibility(ver);
if (window.location.href.toLowerCase().includes("bitburner-beta")) {
//Beta branch, always show changes
createBetaUpdateText();
@ -306,23 +321,11 @@ function loadImportedGame(saveObj, saveString) {
if (tempSaveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(tempSaveObj.VersionSave, Reviver);
if (ver.startsWith("0.27.") || ver.startsWith("0.28.")) {
if (tempPlayer.bitNodeN == null || tempPlayer.bitNodeN == 0) {
tempPlayer.bitNodeN = 1;
}
if (tempPlayer.sourceFiles == null) {
tempPlayer.sourceFiles = [];
}
}
if (ver != CONSTANTS.Version) {
//createNewUpdateText();
}
evaluateVersionCompatibility(ver);
} catch(e) {
console.log("Parsing Version save failed: " + e);
//createNewUpdateText();
console.error("Parsing Version save failed: " + e);
}
} else {
//createNewUpdateText();
}
if (tempPlayer.bitNodeN == 2 && tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
try {
@ -401,29 +404,8 @@ function loadImportedGame(saveObj, saveString) {
if (saveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(saveObj.VersionSave, Reviver);
if (Player.bitNodeN == null || Player.bitNodeN == 0) {
Player.setBitNodeNumber(1);
evaluateVersionCompatibility(ver);
}
if (ver.startsWith("0.27.") || ver.startsWith("0.28.")) {
console.log("Evaluating changes needed for version compatibility");
if (Player.augmentations.length > 0 || Player.queuedAugmentations.length > 0 ||
Player.sourceFiles.length > 0) {
//If you have already purchased an Aug...you are far enough in the game
//that everything should be available
Player.firstFacInvRecvd = true;
Player.firstAugPurchased = true;
Player.firstTimeTraveled = true;
Player.firstProgramAvailable = true;
} else {
if (Player.factions.length > 0 || Player.factionInvitations.length > 0) {
Player.firstFacInvRecvd = true;
}
if (Player.hacking_skill >= 25) {
Player.firstScriptAvailable = true;
}
}
}
if (ver != CONSTANTS.Version) {
createNewUpdateText();
}
@ -459,7 +441,6 @@ function loadImportedGame(saveObj, saveString) {
console.log("Importing game");
Engine.setDisplayElements(); //Sets variables for important DOM elements
Engine.init(); //Initialize buttons, work, etc.
CompanyPositions.init();
//Calculate the number of cycles have elapsed while offline
Engine._lastUpdate = new Date().getTime();

@ -1090,6 +1090,24 @@ let Terminal = {
}
}
post("Error: " + fn + " does not exist");
break;
case "expr":
if (commandArray.length <= 1) {
post("Incorrect usage of expr command. Usage: expr [math expression]");
return;
}
const expr = commandArray.slice(1).join("");
// Sanitize the math expression
const sanitizedExpr = expr.replace(/s+/g, '').replace(/[^-()\d/*+.]/g, '');
let result;
try {
result = eval(sanitizedExpr);
} catch(e) {
post(`Could not evaluate expression: ${sanitizedExpr}`);
return;
}
post(result);
break;
case "free":
Terminal.executeFreeCommand(commandArray);

@ -25,7 +25,8 @@ import {Bladeburner} from "./Bladeburner";
import {CharacterOverview} from "./CharacterOverview";
import {cinematicTextFlag} from "./CinematicText";
import {generateRandomContract} from "./CodingContractGenerator";
import {CompanyPositions, initCompanies} from "./Company";
import {CompanyPositions} from "./Company/CompanyPositions";
import {initCompanies} from "./Company/Companies";
import {Corporation} from "./CompanyManagement";
import {CONSTANTS} from "./Constants";
import {displayCreateProgramContent,
@ -338,7 +339,13 @@ const Engine = {
loadLocationContent: function() {
Engine.hideAllContent();
Engine.Display.locationContent.style.display = "block";
displayLocationContent();
try {
displayLocationContent();
} catch(e) {
exceptionAlert(e);
console.error(e);
}
routing.navigateTo(Page.Location);
},
@ -539,8 +546,8 @@ const Engine = {
removeChildrenFromElement(Engine.Display.characterInfo);
var companyPosition = "";
if (Player.companyPosition != "") {
companyPosition = Player.companyPosition.positionName;
if (Player.companyPosition !== "") {
companyPosition = Player.companyPosition;
}
var intText = "";
@ -1204,7 +1211,6 @@ const Engine = {
initSourceFiles();
Engine.setDisplayElements(); //Sets variables for important DOM elements
Engine.init(); //Initialize buttons, work, etc.
CompanyPositions.init();
initAugmentations(); //Also calls Player.reapplyAllAugmentations()
Player.reapplyAllSourceFiles();
initStockSymbols();
@ -1312,7 +1318,6 @@ const Engine = {
initForeignServers();
initCompanies();
initFactions();
CompanyPositions.init();
initAugmentations();
initMessages();
initStockSymbols();

@ -1,5 +1,6 @@
{
"compilerOptions": {
"baseUrl" : ".",
"lib" : ["es2016", "dom"],
"module": "commonjs",
"target": "es6",