Implemented Sleeve UI. Compiled but untested

This commit is contained in:
danielyxie 2019-01-14 19:34:04 -08:00
parent d9b865ef17
commit bcb231a966
19 changed files with 1058 additions and 573 deletions

@ -164,9 +164,9 @@ getCharacterInformation
{
bitnode: Current BitNode number
city: Name of city you are currently in
company: Name of company
factions: Array of factions you are currently a member of
jobTitle: Name of job
jobs: Array of all companies at which you have jobs
jobTitle: Array of job positions for all companies you are employed at. Same order as 'jobs'
tor: Boolean indicating whether or not you have a tor router
// The following is an object with many of the player's multipliers from Augmentations/Source Files

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -84,7 +84,7 @@ function sanitizeRewardType(rewardType) {
if (type === CodingContractRewardType.FactionReputationAll && factionsThatAllowHacking.length === 0) {
type = CodingContractRewardType.CompanyReputation;
}
if (type === CodingContractRewardType.CompanyReputation && Player.companyName === "") {
if (type === CodingContractRewardType.CompanyReputation && Object.keys(Player.jobs).length === 0) {
type = CodingContractRewardType.Money;
}
@ -115,8 +115,9 @@ function getRandomReward() {
reward.name = randFaction;
break;
case CodingContractRewardType.CompanyReputation:
if (Player.companyName !== "") {
reward.name = Player.companyName;
const allJobs = Object.keys(Player.jobs);
if (allJobs.length > 0) {
reward.name = allJobs[getRandomInt(0, allJobs.length - 1)];
} else {
reward.type = CodingContractRewardType.Money;
}

@ -511,7 +511,10 @@ export let CONSTANTS: IMap<any> = {
* Stock Market Changes:
** Each stock now has a maximum number of shares you can purchase (both Long and Short positions combined)
** Added getStockMaxShares() Netscript function to the TIX API
* Job Changes:
** You can now hold multiple jobs at once. This means you no longer lose reputation when leaving a company
** Because of this change, the getCharacterInformation() Netscript function returns a slightly different value
* Home Computer RAM is now capped at 2 ^ 30 GB (1073741824 GB)
`

147
src/Crime/Crime.ts Normal file

@ -0,0 +1,147 @@
import { CONSTANTS } from "../Constants";
export interface IConstructorParams {
hacking_success_weight?: number;
strength_success_weight?: number;
defense_success_weight?: number;
dexterity_success_weight?: number;
agility_success_weight?: number;
charisma_success_weight?: number;
hacking_exp?: number;
strength_exp?: number;
defense_exp?: number;
dexterity_exp?: number;
agility_exp?: number;
charisma_exp?: number;
intelligence_exp?: number;
kills?: number;
}
interface IPlayer {
startCrime(crimeType: string,
hackExp: number,
strExp: number,
defExp: number,
dexExp: number,
agiExp: number,
chaExp: number,
money: number,
time: number,
singParams: any): void;
hacking_skill: number;
strength: number;
defense: number;
dexterity: number;
agility: number;
charisma: number;
intelligence: number;
crime_success_mult: number;
}
export class Crime {
// Number representing the difficulty of the crime. Used for success chance calculations
difficulty: number = 0;
// Amount of karma lost for SUCCESSFULLY committing this crime
karma: number = 0;
// How many people die as a result of this crime
kills: number = 0;
// How much money is given by the
money: number = 0;
// Name of crime
name: string = "";
// Milliseconds it takes to attempt the crime
time: number = 0;
// Corresponding type in CONSTANTS. Contains a description for the crime activity
type: string = "";
// Weighting factors that determine how stats affect the success rate of this crime
hacking_success_weight: number = 0;
strength_success_weight: number = 0;
defense_success_weight: number = 0;
dexterity_success_weight: number = 0;
agility_success_weight: number = 0;
charisma_success_weight: number = 0;
// How much stat experience is granted by this crime
hacking_exp: number = 0;
strength_exp: number = 0;
defense_exp: number = 0;
dexterity_exp: number = 0;
agility_exp: number = 0;
charisma_exp: number = 0;
intelligence_exp: number = 0;
constructor(name: string = "",
type: string = "",
time: number = 0,
money: number = 0,
difficulty: number = 0,
karma: number = 0,
params: IConstructorParams={}) {
this.name = name;
this.type = type;
this.time = time;
this.money = money;
this.difficulty = difficulty;
this.karma = karma;
this.hacking_success_weight = params.hacking_success_weight ? params.hacking_success_weight : 0;
this.strength_success_weight = params.strength_success_weight ? params.strength_success_weight : 0;
this.defense_success_weight = params.defense_success_weight ? params.defense_success_weight : 0;
this.dexterity_success_weight = params.dexterity_success_weight ? params.dexterity_success_weight : 0;
this.agility_success_weight = params.agility_success_weight ? params.agility_success_weight : 0;
this.charisma_success_weight = params.charisma_success_weight ? params.charisma_success_weight : 0;
this.hacking_exp = params.hacking_exp ? params.hacking_exp : 0;
this.strength_exp = params.strength_exp ? params.strength_exp : 0;
this.defense_exp = params.defense_exp ? params.defense_exp : 0;
this.dexterity_exp = params.dexterity_exp ? params.dexterity_exp : 0;
this.agility_exp = params.agility_exp ? params.agility_exp : 0;
this.charisma_exp = params.charisma_exp ? params.charisma_exp : 0;
this.intelligence_exp = params.intelligence_exp ? params.intelligence_exp : 0;
this.kills = params.kills ? params.kills : 0;
}
commit(p: IPlayer, div: number=1, singParams: any=null): number {
if (div <= 0) { div = 1; }
p.startCrime(
this.type,
this.hacking_exp/div,
this.strength_exp/div,
this.defense_exp/div,
this.dexterity_exp/div,
this.agility_exp/div,
this.charisma_exp/div,
this.money/div,
this.time,
singParams
);
return this.time;
}
successRate(p: IPlayer): number {
let chance: number = (this.hacking_success_weight * p.hacking_skill +
this.strength_success_weight * p.strength +
this.defense_success_weight * p.defense +
this.dexterity_success_weight * p.dexterity +
this.agility_success_weight * p.agility +
this.charisma_success_weight * p.charisma +
CONSTANTS.IntelligenceCrimeWeight * p.intelligence);
chance /= CONSTANTS.MaxSkillLevel;
chance /= this.difficulty;
chance *= p.crime_success_mult;
return Math.min(chance, 1);
}
}

57
src/Crime/CrimeHelpers.js Normal file

@ -0,0 +1,57 @@
export function determineCrimeSuccess(type, moneyGained) {
var chance = 0;
var found = false;
for(const i in Crimes) {
const crime = Crimes[i];
if(crime.type == type) {
chance = crime.successRate(Player);
found = true;
break;
}
}
if(!found) {
console.log(crime);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
return;
}
if (Math.random() <= chance) {
//Success
Player.gainMoney(moneyGained);
return true;
} else {
//Failure
return false;
}
}
export function findCrime(roughName) {
if (roughName.includes("shoplift")) {
return Crimes.Shoplift;
} else if (roughName.includes("rob") && roughName.includes("store")) {
return Crimes.RobStore;
} else if (roughName.includes("mug")) {
return Crimes.Mug;
} else if (roughName.includes("larceny")) {
return Crimes.Larceny;
} else if (roughName.includes("drugs")) {
return Crimes.DealDrugs;
} else if (roughName.includes("bond") && roughName.includes("forge")) {
return Crimes.BondForgery;
} else if (roughName.includes("traffick") && roughName.includes("arms")) {
return Crimes.TraffickArms;
} else if (roughName.includes("homicide")) {
return Crimes.Homicide;
} else if (roughName.includes("grand") && roughName.includes("auto")) {
return Crimes.GrandTheftAuto;
} else if (roughName.includes("kidnap")) {
return Crimes.Kidnap;
} else if (roughName.includes("assassinate")) {
return Crimes.Assassination;
} else if (roughName.includes("heist")) {
return Crimes.Heist;
}
return null;
}

163
src/Crime/Crimes.ts Normal file

@ -0,0 +1,163 @@
import { Crime } from "./Crime";
import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
export const Crimes: IMap<Crime> = {
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1/20, 0.1, {
dexterity_success_weight: 1,
agility_success_weight: 1,
dexterity_exp: 2,
agility_exp: 2,
}),
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1/5, 0.5, {
hacking_exp: 30,
dexterity_exp: 45,
agility_exp: 45,
hacking_success_weight: 0.5 ,
dexterity_success_weight: 2,
agility_success_weight: 1,
intelligence_exp: 0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1/5, 0.25, {
strength_exp: 3,
defense_exp: 3,
dexterity_exp: 3,
agility_exp: 3,
strength_success_weight: 1.5,
defense_success_weight: 0.5,
dexterity_success_weight: 1.5,
agility_success_weight: 0.5,
}),
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1/3, 1.5, {
hacking_exp: 45,
dexterity_exp: 60,
agility_exp: 60,
hacking_success_weight: 0.5,
dexterity_success_weight: 1,
agility_success_weight: 1,
intelligence_exp: 0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
dexterity_exp: 5,
agility_exp: 5,
charisma_exp: 10,
charisma_success_weight: 3,
dexterity_success_weight: 2,
agility_success_weight: 1,
}),
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1/2, 0.1, {
hacking_exp: 100,
dexterity_exp: 150,
charisma_exp: 15,
hacking_success_weight: 0.05,
dexterity_success_weight: 1.25,
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
agility_exp: 20,
charisma_exp: 40,
charisma_success_weight: 1,
strength_success_weight: 1,
defense_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
}),
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
strength_exp: 2,
defense_exp: 2,
dexterity_exp: 2,
agility_exp: 2,
strength_success_weight: 2,
defense_success_weight: 2,
dexterity_success_weight: 0.5,
agility_success_weight: 0.5,
kills: 1,
}),
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
agility_exp: 80,
charisma_exp: 40,
hacking_success_weight: 1,
strength_success_weight: 1,
dexterity_success_weight: 4,
agility_success_weight: 2,
charisma_success_weight: 2,
intelligence_exp: CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
strength_exp: 80,
defense_exp: 80,
dexterity_exp: 80,
agility_exp: 80,
charisma_exp: 80,
charisma_success_weight: 1,
strength_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
strength_exp: 300,
defense_exp: 300,
dexterity_exp: 300,
agility_exp: 300,
strength_success_weight: 1,
dexterity_success_weight: 2,
agility_success_weight: 1,
intelligence_exp: 5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
kills: 1,
}),
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
hacking_exp: 450,
strength_exp: 450,
defense_exp: 450,
dexterity_exp: 450,
agility_exp: 450,
charisma_exp: 450,
hacking_success_weight: 1,
strength_success_weight: 1,
defense_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
charisma_success_weight: 1,
intelligence_exp: 10 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
};

@ -1,275 +0,0 @@
import {CONSTANTS} from "./Constants";
import {Player} from "./Player";
import {dialogBoxCreate} from "../utils/DialogBox";
function Crime(name, type, time, money, difficulty, karma, params) {
this.name = name;
this.type = type;
this.time = time;
this.money = money;
this.difficulty = difficulty;
this.karma = karma;
this.hacking_success_weight = params.hacking_success_weight ? params.hacking_success_weight : 0;
this.strength_success_weight = params.strength_success_weight ? params.strength_success_weight : 0;
this.defense_success_weight = params.defense_success_weight ? params.defense_success_weight : 0;
this.dexterity_success_weight = params.dexterity_success_weight ? params.dexterity_success_weight : 0;
this.agility_success_weight = params.agility_success_weight ? params.agility_success_weight : 0;
this.charisma_success_weight = params.charisma_success_weight ? params.charisma_success_weight : 0;
this.hacking_exp = params.hacking_exp ? params.hacking_exp : 0;
this.strength_exp = params.strength_exp ? params.strength_exp : 0;
this.defense_exp = params.defense_exp ? params.defense_exp : 0;
this.dexterity_exp = params.dexterity_exp ? params.dexterity_exp : 0;
this.agility_exp = params.agility_exp ? params.agility_exp : 0;
this.charisma_exp = params.charisma_exp ? params.charisma_exp : 0;
this.intelligence_exp = params.intelligence_exp ? params.intelligence_exp : 0;
this.kills = params.kills ? params.kills : 0;
}
Crime.prototype.commit = function(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = this.type;
Player.startCrime(
this.hacking_exp/div,
this.strength_exp/div,
this.defense_exp/div,
this.dexterity_exp/div,
this.agility_exp/div,
this.charisma_exp/div,
this.money/div, this.time, singParams);
return this.time;
}
Crime.prototype.successRate = function() {
var chance = (this.hacking_success_weight * Player.hacking_skill +
this.strength_success_weight * Player.strength +
this.defense_success_weight * Player.defense +
this.dexterity_success_weight * Player.dexterity +
this.agility_success_weight * Player.agility +
this.charisma_success_weight * Player.charisma +
CONSTANTS.IntelligenceCrimeWeight * Player.intelligence);
chance /= CONSTANTS.MaxSkillLevel;
chance /= this.difficulty;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
const Crimes = {
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1/20, 0.1, {
dexterity_success_weight: 1,
agility_success_weight: 1,
dexterity_exp: 2,
agility_exp: 2,
}),
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1/5, 0.5, {
hacking_exp: 30,
dexterity_exp: 45,
agility_exp: 45,
hacking_success_weight: 0.5 ,
dexterity_success_weight: 2,
agility_success_weight: 1,
intelligence_exp: 0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1/5, 0.25, {
strength_exp: 3,
defense_exp: 3,
dexterity_exp: 3,
agility_exp: 3,
strength_success_weight: 1.5,
defense_success_weight: 0.5,
dexterity_success_weight: 1.5,
agility_success_weight: 0.5,
}),
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1/3, 1.5, {
hacking_exp: 45,
dexterity_exp: 60,
agility_exp: 60,
hacking_success_weight: 0.5,
dexterity_success_weight: 1,
agility_success_weight: 1,
intelligence_exp: 0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
dexterity_exp: 5,
agility_exp: 5,
charisma_exp: 10,
charisma_success_weight: 3,
dexterity_success_weight: 2,
agility_success_weight: 1,
}),
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1/2, 0.1, {
hacking_exp: 100,
dexterity_exp: 150,
charisma_exp: 15,
hacking_success_weight: 0.05,
dexterity_success_weight: 1.25,
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
agility_exp: 20,
charisma_exp: 40,
charisma_success_weight: 1,
strength_success_weight: 1,
defense_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
}),
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
strength_exp: 2,
defense_exp: 2,
dexterity_exp: 2,
agility_exp: 2,
strength_success_weight: 2,
defense_success_weight: 2,
dexterity_success_weight: 0.5,
agility_success_weight: 0.5,
kills: 1,
}),
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
agility_exp: 80,
charisma_exp: 40,
hacking_success_weight: 1,
strength_success_weight: 1,
dexterity_success_weight: 4,
agility_success_weight: 2,
charisma_success_weight: 2,
intelligence_exp: CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
strength_exp: 80,
defense_exp: 80,
dexterity_exp: 80,
agility_exp: 80,
charisma_exp: 80,
charisma_success_weight: 1,
strength_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
strength_exp: 300,
defense_exp: 300,
dexterity_exp: 300,
agility_exp: 300,
strength_success_weight: 1,
dexterity_success_weight: 2,
agility_success_weight: 1,
intelligence_exp: 5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
kills: 1,
}),
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
hacking_exp: 450,
strength_exp: 450,
defense_exp: 450,
dexterity_exp: 450,
agility_exp: 450,
charisma_exp: 450,
hacking_success_weight: 1,
strength_success_weight: 1,
defense_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
charisma_success_weight: 1,
intelligence_exp: 10 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
};
function determineCrimeSuccess(type, moneyGained) {
var chance = 0;
var found = false;
for(const i in Crimes) {
const crime = Crimes[i];
if(crime.type == type) {
chance = crime.successRate();
found = true;
break;
}
}
if(!found) {
console.log(crime);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
return;
}
if (Math.random() <= chance) {
//Success
Player.gainMoney(moneyGained);
return true;
} else {
//Failure
return false;
}
}
function findCrime(roughName) {
if (roughName.includes("shoplift")) {
return Crimes.Shoplift;
} else if (roughName.includes("rob") && roughName.includes("store")) {
return Crimes.RobStore;
} else if (roughName.includes("mug")) {
return Crimes.Mug;
} else if (roughName.includes("larceny")) {
return Crimes.Larceny;
} else if (roughName.includes("drugs")) {
return Crimes.DealDrugs;
} else if (roughName.includes("bond") && roughName.includes("forge")) {
return Crimes.BondForgery;
} else if (roughName.includes("traffick") && roughName.includes("arms")) {
return Crimes.TraffickArms;
} else if (roughName.includes("homicide")) {
return Crimes.Homicide;
} else if (roughName.includes("grand") && roughName.includes("auto")) {
return Crimes.GrandTheftAuto;
} else if (roughName.includes("kidnap")) {
return Crimes.Kidnap;
} else if (roughName.includes("assassinate")) {
return Crimes.Assassination;
} else if (roughName.includes("heist")) {
return Crimes.Heist;
}
return null;
}
export {determineCrimeSuccess,findCrime,Crimes};

@ -5,7 +5,7 @@ import {getJobRequirementText} from "./Company/GetJobRequiremen
import * as posNames from "./Company/data/CompanyPositionNames";
import { Corporation } from "./Corporation/Corporation";
import {CONSTANTS} from "./Constants";
import {Crimes} from "./Crimes";
import { Crimes } from "./Crime/Crimes";
import {Engine} from "./engine";
import {beginInfiltration} from "./Infiltration";
import {hasBladeburnerSF} from "./NetscriptFunctions";
@ -240,7 +240,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) {
if (loc != "" && Object.keys(Player.jobs).includes(loc)) {
let company = Companies[loc];
jobTitle.style.display = "block";
@ -249,7 +249,7 @@ function displayLocationContent() {
locationTxtDiv1.style.display = "block";
locationTxtDiv2.style.display = "block";
locationTxtDiv3.style.display = "block";
jobTitle.innerHTML = "Job Title: " + Player.companyPosition;
jobTitle.innerHTML = `Job Title: ${Player.jobs[loc]}`;
let repGain = company.getFavorGain();
if (repGain.length != 2) {repGain = 0;}
repGain = repGain[0];
@ -264,7 +264,7 @@ function displayLocationContent() {
"favor you gain depends on how much reputation you have with the company</span>";
work.style.display = "block";
let currPos = CompanyPositions[Player.companyPosition];
let currPos = CompanyPositions[Player.jobs[loc]];
if (currPos == null) {
throw new Error("Player's companyPosition property has an invalid value");
}
@ -1043,8 +1043,8 @@ function displayLocationContent() {
// 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 (Object.keys(Player.jobs).includes(loc)) {
var currPos = Player.jobs[loc];
if (currPos == "Employee") {
employeeJob.style.display = "none";
@ -1874,73 +1874,73 @@ function initLocationButtons() {
slumsShoplift.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Shoplift.commit();
Crimes.Shoplift.commit(Player);
return false;
});
slumsRobStore.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.RobStore.commit();
Crimes.RobStore.commit(Player);
return false;
});
slumsMug.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Mug.commit();
Crimes.Mug.commit(Player);
return false;
});
slumsLarceny.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Larceny.commit();
Crimes.Larceny.commit(Player);
return false;
});
slumsDealDrugs.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.DealDrugs.commit();
Crimes.DealDrugs.commit(Player);
return false;
});
slumsBondForgery.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.BondForgery.commit();
Crimes.BondForgery.commit(Player);
return false;
});
slumsTrafficArms.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.TraffickArms.commit();
Crimes.TraffickArms.commit(Player);
return false;
});
slumsHomicide.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Homicide.commit();
Crimes.Homicide.commit(Player);
return false;
});
slumsGta.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.GrandTheftAuto.commit();
Crimes.GrandTheftAuto.commit(Player);
return false;
});
slumsKidnap.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Kidnap.commit();
Crimes.Kidnap.commit(Player);
return false;
});
slumsAssassinate.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Assassination.commit();
Crimes.Assassination.commit(Player);
return false;
});
slumsHeist.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;}
Crimes.Heist.commit();
Crimes.Heist.commit(Player);
return false;
});

@ -6,7 +6,7 @@ import {Augmentations, Augmentation,
augmentationExists, installAugmentations,
AugmentationNames} from "./Augmentations";
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {determineCrimeSuccess, findCrime} from "./Crimes";
import { determineCrimeSuccess, findCrime } from "./Crime/CrimeHelpers";
import {Bladeburner} from "./Bladeburner";
import {Company} from "./Company/Company";
import {Companies, companyExists} from "./Company/Companies";
@ -2902,16 +2902,12 @@ function NetscriptFunctions(workerScript) {
}
}
var companyPositionTitle = "";
if (CompanyPositions[Player.companyPosition] instanceof CompanyPosition) {
companyPositionTitle = Player.companyPosition;
}
return {
bitnode: Player.bitNodeN,
city: Player.city,
company: Player.companyName,
factions: Player.factions.slice(),
jobTitle: companyPositionTitle,
jobs: Object.keys(Player.jobs),
jobTitles: Object.values(Player.jobs),
mult: {
agility: Player.agility_mult,
agilityExp: Player.agility_exp_mult,
@ -3030,7 +3026,7 @@ function NetscriptFunctions(workerScript) {
return Player.getUpgradeHomeRamCost();
},
workForCompany : function() {
workForCompany : function(companyName) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) {
@ -3044,13 +3040,33 @@ function NetscriptFunctions(workerScript) {
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: workForCompany() failed because you are in the middle of a mission.");
return;
// Sanitize input
if (companyName == null) {
companyName = Player.companyName;
}
const companyPosition = CompanyPositions[Player.companyPosition];
if (Player.companyPosition === "" || !(companyPosition instanceof CompanyPosition)) {
// Make sure its a valid company
if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) {
workerScript.scriptRef.log(`ERROR: workForCompany() failed because of an invalid company specified: ${companyName}`);
return false;
}
// Make sure player is actually employed at the comapny
if (!Object.keys(Player.jobs).includes(companyName)) {
workerScript.scriptRef.log(`ERROR: workForCompany() failed because you do not have a job at ${companyName}`);
return false;
}
// Cant work while in a mission
if (inMission) {
workerScript.scriptRef.log("ERROR: workForCompany() failed because you are in the middle of a mission.");
return false;
}
// Check to make sure company position data is valid
const companyPositionName = Player.jobs[companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) {
workerScript.scriptRef.log("ERROR: workForCompany() failed because you do not have a job");
return false;
}
@ -3062,13 +3078,14 @@ function NetscriptFunctions(workerScript) {
}
}
Player.companyName = companyName;
if (companyPosition.isPartTimeJob()) {
Player.startWorkPartTime();
} else {
Player.startWork();
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.workForCompany == null) {
workerScript.log(`Began working at ${Player.companyName} as a ${Player.companyPosition}`);
workerScript.log(`Began working at ${Player.companyName} as a ${companyPositionName}`);
}
return true;
},
@ -3144,7 +3161,7 @@ function NetscriptFunctions(workerScript) {
}
if (res) {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
workerScript.log(`You were offered a new job at ${companyName} as a ${Player.companyPosition}`);
workerScript.log(`You were offered a new job at ${companyName} as a ${Player.jobs[companyName]}`);
}
} else {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
@ -3582,7 +3599,7 @@ function NetscriptFunctions(workerScript) {
if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.commitCrime == null) {
workerScript.scriptRef.log("Attempting to commit crime: "+crime.name+"...");
}
return crime.commit(1, {workerscript: workerScript});
return crime.commit(Player, 1, {workerscript: workerScript});
},
getCrimeChance : function(crimeRoughName) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;

@ -2,6 +2,7 @@
import { BitNodeMultipliers } from "../BitNodeMultipliers";
import { Cities } from "../Locations/Cities";
import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
// Interface for an object that represents the player (PlayerObject)
// Used because at the time of implementation, the PlayerObject
@ -11,7 +12,19 @@ import { CONSTANTS } from "../Constants";
export interface IPlayer {
companyName: string;
factions: string[];
jobs: IMap<string>;
money: any;
hacking_skill: number;
strength: number;
defense: number;
dexterity: number;
agility: number;
charisma: number;
intelligence: number;
crime_success_mult: number;
gainHackingExp(exp: number): void;
gainStrengthExp(exp: number): void;
gainDefenseExp(exp: number): void;
@ -20,35 +33,16 @@ export interface IPlayer {
gainCharismaExp(exp: number): void;
gainMoney(money: number): void;
loseMoney(money: number): void;
}
// Interface for a Crime object
// Used because at the time of implementation, the Crime object has not been converted
// to Typescript
export interface ICrime {
name: string;
type: string;
time: number;
money: number;
difficulty: number;
karma: number;
hacking_success_weight: number;
strength_success_weight: number;
defense_success_weight: number;
dexterity_success_weight: number;
agility_success_weight: number;
charisma_success_weight: number;
hacking_exp: number;
strength_exp: number;
defense_exp: number;
dexterity_exp: number;
agility_exp: number;
charisma_exp: number;
intelligence_exp: number;
kills: number;
startCrime(crimeType: string,
hackExp: number,
strExp: number,
defExp: number,
dexExp: number,
agiExp: number,
chaExp: number,
money: number,
time: number,
singParams: any): void;
}
// Interface that defines a generic object used to track experience/money
@ -79,102 +73,60 @@ export abstract class Person {
/**
* Stats
*/
hacking_skill: number;
strength: number;
defense: number;
dexterity: number;
agility: number;
charisma: number;
hp: number;
max_hp: number;
hacking_skill: number = 1;
strength: number = 1;
defense: number = 1;
dexterity: number = 1;
agility: number = 1;
charisma: number = 1;
hp: number = 10;
max_hp: number = 10;
/**
* Multipliers
*/
hacking_exp: number;
strength_exp: number;
defense_exp: number;
dexterity_exp: number;
agility_exp: number;
charisma_exp: number;
intelligence_exp: number;
hacking_exp: number = 0;
strength_exp: number = 0;
defense_exp: number = 0;
dexterity_exp: number = 0;
agility_exp: number = 0;
charisma_exp: number = 0;
intelligence_exp: number = 0;
hacking_mult: number;
strength_mult: number;
defense_mult: number;
dexterity_mult: number;
agility_mult: number;
charisma_mult: number;
hacking_mult: number = 1;
strength_mult: number = 1;
defense_mult: number = 1;
dexterity_mult: number = 1;
agility_mult: number = 1;
charisma_mult: number = 1;
hacking_exp_mult: number;
strength_exp_mult: number;
defense_exp_mult: number;
dexterity_exp_mult: number;
agility_exp_mult: number;
charisma_exp_mult: number;
hacking_exp_mult: number = 1;
strength_exp_mult: number = 1;
defense_exp_mult: number = 1;
dexterity_exp_mult: number = 1;
agility_exp_mult: number = 1;
charisma_exp_mult: number = 1;
company_rep_mult: number;
faction_rep_mult: number;
company_rep_mult: number = 1;
faction_rep_mult: number = 1;
crime_money_mult: number;
crime_success_mult: number;
crime_money_mult: number = 1;
crime_success_mult: number = 1;
work_money_mult: number;
work_money_mult: number = 1;
/**
* Augmentations
*/
this.augmentations = [];
this.queuedAugmentations = [];
augmentations: string[] = [];
queuedAugmentations: string[] = [];
/**
* City that the person is in
*/
city: string;
city: string = Cities.Sector12;
constructor() {
this.hacking_skill = 1;
this.strength = 1;
this.defense = 1;
this.dexterity = 1;
this.agility = 1;
this.charisma = 1;
this.hp = 10;
this.max_hp = 10;
// Multipliers
this.hacking_exp = 0;
this.strength_exp = 0;
this.defense_exp = 0;
this.dexterity_exp = 0;
this.agility_exp = 0;
this.charisma_exp = 0;
this.intelligence_exp = 0;
this.hacking_mult = 1;
this.strength_mult = 1;
this.defense_mult = 1;
this.dexterity_mult = 1;
this.agility_mult = 1;
this.charisma_mult = 1;
this.hacking_exp_mult = 1;
this.strength_exp_mult = 1;
this.defense_exp_mult = 1;
this.dexterity_exp_mult = 1;
this.agility_exp_mult = 1;
this.charisma_exp_mult = 1;
this.company_rep_mult = 1;
this.faction_rep_mult = 1;
this.crime_money_mult = 1;
this.crime_success_mult = 1;
this.work_money_mult = 1;
this.city = Cities.Sector12;
}
constructor() {}
/**
* Given an experience amount and stat multiplier, calculates the

@ -10,18 +10,26 @@ import { SleeveTaskType } from "./SleeveTaskTypesEnum";
import { Person,
IPlayer,
ICrime,
ITaskTracker,
createTaskTracker } from "../Person";
import { BitNodeMultipliers } from "../../BitNodeMultipliers";
import { Crime } from "../../Crime/Crime";
import { Cities } from "../../Locations/Cities";
import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition";
import { CompanyPositions } from "../../Company/CompanyPositions";
import { CONSTANTS } from "../../Constants";
import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
import { Locations } from "../../Locations";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
@ -45,8 +53,11 @@ export class Sleeve extends Person {
currentTaskDescription: string = "";
/**
* For what company/faction the current task is assigned to.
* Only applicable when working for faction or company, obviously
* Contains details about the sleeve's current task. The info stored
* in this depends on the task type
*
* Faction/Company Work: Name of Faction/Company
* Crime: Success rate of current crime, in decimal form
*/
currentTaskLocation: string = "";
@ -119,29 +130,14 @@ export class Sleeve extends Person {
constructor() {
super();
/*
this.currentTask = SleeveTaskType.Idle;
this.currentTaskDescription = "";
this.currentTaskTime = 0;
this.currentTaskMaxTime = 0;
this.earningsForSleeves = createTaskTracker();
this.earningsForPlayer = createTaskTracker();
this.earningsForTask = createTaskTracker();
this.gainRatesForTask = createTaskTracker();
this.logs = [];
this.memory = 0;
this.shock = 1;
this.storedCycles = 0;
this.sync = 1;
*/
}
/**
* Commit crimes
*/
commitCrime(p: IPlayer, crime: ICrime): void {
commitCrime(p: IPlayer, crime: Crime): void {
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
this.finishTask(p);
} else {
this.resetTaskStatus();
}
@ -152,19 +148,38 @@ export class Sleeve extends Person {
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.money = crime.money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
// We'll determine success now and adjust the earnings accordingly
if (Math.random() < crime.successRate(p)) {
this.gainRatesForTask.hack *= 2;
this.gainRatesForTask.str *= 2;
this.gainRatesForTask.def *= 2;
this.gainRatesForTask.dex *= 2;
this.gainRatesForTask.agi *= 2;
this.gainRatesForTask.cha *= 2;
} else {
this.gainRatesForTask.money = 0;
}
this.currentTaskMaxTime = crime.time;
this.currentTask = SleeveTaskType.Crime;
}
/**
* Called to stop the current task
*/
finishTask(): void {
finishTask(p: IPlayer): void {
if (this.currentTask === SleeveTaskType.Crime) {
} else {
// For crimes, all experience and money is gained at the end
if (this.currentTaskTime >= this.currentTaskMaxTime) {
let retValue: ITaskTracker = createTaskTracker(); // Amount of exp to be gained by other sleeves
retValue = this.gainExperience(p, this.gainRatesForTask);
this.gainMoney(p, this.gainRatesForTask);
}
} else {
// For other crimes... I dont think anything else needs to be done
}
this.resetTaskStatus();
@ -336,14 +351,19 @@ export class Sleeve extends Person {
break;
}
const repGainPerCycle: number = this.getRepGain();
fac.playerReputation += (repGainPerCycle * cyclesUsed);
fac.playerReputation += (this.getRepGain() * cyclesUsed);
break;
case SleeveTaskType.Company:
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
// TODO Rep gain for this
const company: Company = Companies[this.currentTaskLocation];
if (!(company instanceof Company)) {
console.error(`Invalid company for Sleeve task: ${this.currentTaskLocation}`);
break;
}
company.playerReputation *= (this.getRepGain() * cyclesUsed);
break;
case SleeveTaskType.Recovery:
this.shock = Math.max(100, this.shock + (0.001 * this.storedCycles));
@ -356,9 +376,11 @@ export class Sleeve extends Person {
}
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
this.finishTask();
this.finishTask(p);
}
this.updateStatLevels();
this.storedCycles -= cyclesUsed;
// TODO Finish this
@ -382,7 +404,7 @@ export class Sleeve extends Person {
*/
takeUniversityCourse(p: IPlayer, universityName: string, className: string): boolean {
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
this.finishTask(p);
} else {
this.resetTaskStatus();
}
@ -471,22 +493,68 @@ export class Sleeve extends Person {
}
/**
* Work for a company
* Start work for one of the player's companies
* Returns boolean indicating success
*/
workForCompany(p: IPlayer): boolean {
return true;
}
/**
* Work for one of the player's factions
*/
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
workForCompany(p: IPlayer, companyName: string): boolean {
if (!(Companies[companyName] instanceof Company) || p.jobs[companyName] == null) {
return false;
}
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
this.finishTask(p);
} else {
this.resetTaskStatus();
}
const company: Company | null = Companies[companyName];
const companyPosition: CompanyPosition | null = CompanyPositions[p.jobs[companyName]];
if (company == null) { throw new Error(`Invalid company name specified in Sleeve.workForCompany(): ${companyName}`); }
if (companyPosition == null) { throw new Error(`Invalid CompanyPosition data in Sleeve.workForCompany(): ${companyName}`); }
this.gainRatesForTask.hack = companyPosition.hackingExpGain *
company.expMultiplier *
this.hacking_exp_mult *
BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.str = companyPosition.strengthExpGain *
company.expMultiplier *
this.strength_exp_mult *
BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.def = companyPosition.defenseExpGain *
company.expMultiplier *
this.defense_exp_mult *
BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.dex = companyPosition.dexterityExpGain *
company.expMultiplier *
this.dexterity_exp_mult *
BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.agi = companyPosition.agilityExpGain *
company.expMultiplier *
this.agility_exp_mult *
BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.cha = companyPosition.charismaExpGain *
company.expMultiplier *
this.charisma_exp_mult *
BitNodeMultipliers.FactionWorkExpGain;
this.currentTaskLocation = companyName;
this.currentTask = SleeveTaskType.Company;
return true;
}
/**
* Start work for one of the player's factions
* Returns boolean indicating success
*/
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
throw new Error(`Invalid Faction specified for Sleeve.workForFaction(): ${factionName}`);
return false;
}
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask(p);
} else {
this.resetTaskStatus();
}
@ -526,7 +594,7 @@ export class Sleeve extends Person {
*/
workoutAtGym(p: IPlayer, gymName: string, stat: string): boolean {
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
this.finishTask(p);
} else {
this.resetTaskStatus();
}

@ -4,31 +4,45 @@
import { Sleeve } from "./Sleeve";
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
import { IPlayer } from "../Person";
import { Locations } from "../../Locations";
import { Cities } from "../../Locations/Cities";
import { Crimes } from "../../Crime/Crimes";
import { IMap } from "../../types";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Page,
routing } from "../../ui/navigationTracking";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { exceptionAlert } from "../../../utils/helpers/exceptionAlert";
import { createElement } from "../../../utils/uiHelpers/createElement";
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
import { getSelectValue } from "../../../utils/uiHelpers/getSelectData";
import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement";
import { removeElement } from "../../../utils/uiHelpers/removeElement";
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
// Object that keeps track of all DOM elements for the UI for a single Sleeve
interface ISleeveUIElems {
container: Element | null,
statsPanel: Element | null,
stats: Element | null,
statsTooltip: Element | null,
taskPanel: Element | null,
taskSelector: Element | null,
taskDetailsSelector: Element | null,
taskDescription: Element | null,
earningsPanel: Element | null,
currentEarningsInfo: Element | null,
totalEarningsInfo: Element | null,
container: HTMLElement | null,
statsPanel: HTMLElement | null,
stats: HTMLElement | null,
moreStatsButton: HTMLElement | null,
taskPanel: HTMLElement | null,
taskSelector: HTMLSelectElement | null,
taskDetailsSelector: HTMLSelectElement | null,
taskDetailsSelector2: HTMLSelectElement | null,
taskDescription: HTMLElement | null,
taskSetButton: HTMLElement | null,
earningsPanel: HTMLElement | null,
currentEarningsInfo: HTMLElement | null,
totalEarningsButton: HTMLElement | null,
}
// Object that keeps track of all DOM elements for the entire Sleeve UI
@ -47,15 +61,18 @@ const UIElems: IPageUIElems = {
}
// Interface for Player object
interface IPlayer {
interface ISleeveUiPlayer extends IPlayer {
sleeves: Sleeve[];
}
// Creates the UI for the entire Sleeves page
export function createSleevesPage(p: IPlayer) {
let playerRef: ISleeveUiPlayer | null;
export function createSleevesPage(p: ISleeveUiPlayer) {
if (!routing.isOn(Page.Sleeves)) { return; }
try {
playerRef = p;
UIElems.container = createElement("div", {
class: "generic-menupage-container",
id: "sleeves-container",
@ -73,8 +90,11 @@ export function createSleevesPage(p: IPlayer) {
UIElems.sleeveList = createElement("ul");
UIElems.sleeves = [];
// Create UI modules for all Sleeve
for (const sleeve of p.sleeves) {
UIElems.sleeves.push(this.createSleeveUi(sleeve, p.sleeves));
const sleeveUi = createSleeveUi(sleeve, p.sleeves);
UIElems.sleeveList.appendChild(sleeveUi.container!);
UIElems.sleeves.push(sleeveUi);
}
UIElems.container.appendChild(UIElems.info);
@ -94,29 +114,33 @@ export function updateSleevesPage() {
export function clearSleevesPage() {
removeElement(UIElems.container);
for (const prop in UIElems) {
UIElems[prop] = null;
(<any>UIElems)[prop] = null;
}
playerRef = null;
}
// Creates the UI for a single Sleeve
// Returns an object containing the DOM elements in the UI (ISleeveUIElems)
function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]) {
if (!routing.isOn(Page.Sleeves)) { return; }
function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
const elems: ISleeveUIElems = {
container: null,
statsPanel: null,
stats: null,
statsTooltip: null,
moreStatsButton: null,
taskPanel: null,
taskSelector: null,
taskDetailsSelector: null,
taskDetailsSelector2: null,
taskDescription: null,
taskSetButton: null,
earningsPanel: null,
currentEarningsInfo: null,
totalEarningsButton: null,
}
if (!routing.isOn(Page.Sleeves)) { return elems; }
elems.container = createElement("div", {
class: "sleeve-container",
display: "block",
@ -124,12 +148,46 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]) {
elems.statsPanel = createElement("div", { class: "sleeve-panel" });
elems.stats = createElement("p", { class: "sleeve-stats-text tooltip" });
elems.statsTooltip = createElement("span", { class: "tooltiptext" });
elems.stats.appendChild(elems.statsTooltip);
elems.moreStatsButton = createElement("button", {
class: "std-button",
innerText: "More Stats",
clickListener: () => {
dialogBoxCreate(
[
"<h2><u>Stats:</u></h2>",
`Hacking: ${sleeve.hacking_skill} (${numeralWrapper.formatBigNumber(sleeve.hacking_exp)} exp)`,
`Strength: ${sleeve.strength} (${numeralWrapper.formatBigNumber(sleeve.strength_exp)} exp)`,
`Defense: ${sleeve.defense} (${numeralWrapper.formatBigNumber(sleeve.defense_exp)} exp)`,
`Dexterity: ${sleeve.dexterity} (${numeralWrapper.formatBigNumber(sleeve.dexterity_exp)} exp)`,
`Agility: ${sleeve.agility} (${numeralWrapper.formatBigNumber(sleeve.agility_exp)} exp)`,
`Charisma: ${sleeve.charisma} (${numeralWrapper.formatBigNumber(sleeve.charisma_exp)} exp)<br>`,
"<h2><u>Multipliers:</u></h2>",
`Hacking Level multiplier: ${numeralWrapper.formatPercentage(sleeve.hacking_mult)}`,
`Hacking Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.hacking_exp_mult)}`,
`Strength Level multiplier: ${numeralWrapper.formatPercentage(sleeve.strength_mult)}`,
`Strength Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.strength_exp_mult)}`,
`Defense Level multiplier: ${numeralWrapper.formatPercentage(sleeve.defense_mult)}`,
`Defense Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.defense_exp_mult)}`,
`Dexterity Level multiplier: ${numeralWrapper.formatPercentage(sleeve.dexterity_mult)}`,
`Dexterity Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.dexterity_exp_mult)}`,
`Agility Level multiplier: ${numeralWrapper.formatPercentage(sleeve.agility_mult)}`,
`Agility Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.agility_exp_mult)}`,
`Charisma Level multiplier: ${numeralWrapper.formatPercentage(sleeve.charisma_mult)}`,
`Charisma Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.charisma_exp_mult)}`,
`Faction Reputation Gain multiplier: ${numeralWrapper.formatPercentage(sleeve.faction_rep_mult)}`,
`Company Reputation Gain multiplier: ${numeralWrapper.formatPercentage(sleeve.company_rep_mult)}`,
`Salary multiplier: ${numeralWrapper.formatPercentage(sleeve.work_money_mult)}`,
`Crime Money multiplier: ${numeralWrapper.formatPercentage(sleeve.crime_money_mult)}`,
`Crime Success multiplier: ${numeralWrapper.formatPercentage(sleeve.crime_success_mult)}`,
].join("<br>"), false
);
}
});
elems.statsPanel.appendChild(elems.stats);
elems.statsPanel.appendChild(elems.moreStatsButton);
elems.taskPanel = createElement("div", { class: "sleeve-panel" });
elems.taskSelector = createElement("select");
elems.taskSelector = createElement("select") as HTMLSelectElement;
elems.taskSelector.add(createOptionElement("------"));
elems.taskSelector.add(createOptionElement("Work for Company"));
elems.taskSelector.add(createOptionElement("Work for Faction"));
@ -142,25 +200,290 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]) {
updateSleeveTaskSelector(sleeve, elems, allSleeves);
});
// TODO Set initial value for task selector
elems.taskDetailsSelector = createElement("select");
elems.taskDetailsSelector = createElement("select") as HTMLSelectElement;
elems.taskDetailsSelector2 = createElement("select") as HTMLSelectElement;
elems.taskDescription = createElement("p");
elems.taskSetButton = createElement("button", {
class: "std-button",
innerText: "Set Task",
clickListener: () => {
setSleeveTask(sleeve, elems);
}
});
elems.taskPanel.appendChild(elems.taskSelector);
elems.taskPanel.appendChild(elems.taskDetailsSelector);
elems.taskPanel.appendChild(elems.taskSetButton);
elems.taskPanel.appendChild(elems.taskDescription);
elems.earningsPanel = createElement("div", { class: "sleeve-panel" });
elems.currentEarningsInfo = createElement("p");
elems.totalEarningsButton = createElement("button", { class: "std-button" });
elems.totalEarningsButton = createElement("button", {
class: "std-button",
innerText: "More Earnings Info",
clickListener: () => {
dialogBoxCreate(
[
"<h2><u>Total Earnings for Current Task:</u></h2>",
`Money: ${numeralWrapper.formatMoney(sleeve.earningsForTask.money)}`,
`Hacking Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.hack)}`,
`Strength Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.str)}`,
`Defense Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.def)}`,
`Dexterity Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.dex)}`,
`Agility Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.agi)}`,
`Charisma Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.cha)}`,
"<h2><u>Earnings for Host Consciousness:</u></h2>",
`Money: ${numeralWrapper.formatMoney(sleeve.earningsForPlayer.money)}`,
`Hacking Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.hack)}`,
`Strength Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.str)}`,
`Defense Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.def)}`,
`Dexterity Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.dex)}`,
`Agility Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.agi)}`,
`Charisma Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.cha)}`,
"<h2><u>Earnings for Other Sleeves:</u></h2>",
`Money: ${numeralWrapper.formatMoney(sleeve.earningsForSleeves.money)}`,
`Hacking Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.hack)}`,
`Strength Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.str)}`,
`Defense Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.def)}`,
`Dexterity Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.dex)}`,
`Agility Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.agi)}`,
`Charisma Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.cha)}`,
].join("<br>"), false
);
}
});
return elems;
}
// Updates the UI for a single Sleeve
function updateSleeveUi() {
function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
if (!routing.isOn(Page.Sleeves)) { return; }
elems.stats!.innerHTML = [`Hacking: ${numeralWrapper.format(sleeve.hacking_skill, "0,0")}`,
`Strength: ${numeralWrapper.format(sleeve.strength, "0,0")}`,
`Defense: ${numeralWrapper.format(sleeve.defense, "0,0")}`,
`Dexterity: ${numeralWrapper.format(sleeve.dexterity, "0,0")}`,
`Agility: ${numeralWrapper.format(sleeve.agility, "0,0")}`,
`Charisma: ${numeralWrapper.format(sleeve.charisma, "0,0")}`,
`HP: ${numeralWrapper.format(sleeve.hp, "0,0")} / ${numeralWrapper.format(sleeve.max_hp, "0,0")}<br>`,
`Shock: ${numeralWrapper.format(100 - sleeve.shock, "0,0")}`,
`Synchronization: ${numeralWrapper.format(sleeve.sync, "0,0")}`].join("<br>");
if (sleeve.currentTask === SleeveTaskType.Crime) {
elems.currentEarningsInfo!.innerHTML = [
`Money: ${numeralWrapper.formatMoney(sleeve.gainRatesForTask.money)} if successful`,
`Hacking Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.hack, "0.00")} (2x if successful)`,
`Strength Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.str, "0.00")} (2x if successful)`,
`Defense Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.def, "0.00")} (2x if successful)`,
`Dexterity Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.dex, "0.00")} (2x if successful)`,
`Agility Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.agi, "0.00")} (2x if successful)`,
`Charisma Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.cha, "0.00")} (2x if successful)`
].join("<br>");
} else {
elems.currentEarningsInfo!.innerHTML = [
`Money: ${numeralWrapper.formatMoney(sleeve.gainRatesForTask.money)} / s`,
`Hacking Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.hack, "0.00")} / s`,
`Strength Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.str, "0.00")} / s`,
`Defense Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.def, "0.00")} / s`,
`Dexterity Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.dex, "0.00")} / s`,
`Agility Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.agi, "0.00")} / s`,
`Charisma Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.cha, "0.00")} / s`
].join("<br>");
}
}
const factionWorkTypeSelectorOptions: string[] = [
"Hacking Contracts",
"Security Work",
"Field Work"
];
const universitySelectorOptions: string[] = [
"Study Computer Science",
"Data Structures",
"Networks",
"Algorithms",
"Management",
"Leadership"
];
const gymSelectorOptions: string[] = [
"Train Strength",
"Train Defense",
"Train Dexterity",
"Train Agility"
];
// Whenever a new task is selected, the "details" selector must update accordingly
function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSleeves: Sleeve[]) {
const value: string =
if (playerRef == null) {
throw new Error(`playerRef is null in updateSleeveTaskSelector()`);
}
// Array of all companies that other sleeves are working at
const forbiddenCompanies: string[] = [];
for (const otherSleeve of allSleeves) {
if (sleeve === otherSleeve) { continue; }
if (otherSleeve.currentTask === SleeveTaskType.Company) {
forbiddenCompanies.push(otherSleeve.currentTaskLocation);
}
}
// Array of all factions that other sleeves are working for
const forbiddenFactions: string[] = [];
for (const otherSleeve of allSleeves) {
if (sleeve === otherSleeve) { continue; }
if (otherSleeve.currentTask === SleeveTaskType.Faction) {
forbiddenFactions.push(otherSleeve.currentTaskLocation);
}
}
removeChildrenFromElement(elems.taskDetailsSelector);
const value: string = getSelectValue(elems.taskSelector);
switch(value) {
case "Work for Company":
const allJobs: string[] = Object.keys(playerRef!.jobs!);
for (let i = 0; i < allJobs.length; ++i) {
if (!forbiddenCompanies.includes(allJobs[i])) {
elems.taskDetailsSelector!.add(createOptionElement(allJobs[i]));
}
}
break;
case "Work for Faction":
for (let i = 0; i < playerRef!.factions!.length; ++i) {
const fac: string = playerRef!.factions[i]!;
if (!forbiddenFactions.includes(fac)) {
elems.taskDetailsSelector!.add(createOptionElement(fac));
}
}
for (let i = 0; i < factionWorkTypeSelectorOptions.length; ++i) {
elems.taskDetailsSelector2!.add(createOptionElement(factionWorkTypeSelectorOptions[i]));
}
break;
case "Commit Crime":
for (const crimeLabel in Crimes) {
const name: string = Crimes[crimeLabel].name;
elems.taskDetailsSelector!.add(createOptionElement(name, crimeLabel));
}
break;
case "Take University Course":
// First selector has class type
for (let i = 0; i < universitySelectorOptions.length; ++i) {
elems.taskDetailsSelector!.add(createOptionElement(universitySelectorOptions[i]));
}
// Second selector has which university
switch (sleeve.city) {
case Cities.Aevum:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSummitUniversity));
break;
case Cities.Sector12:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12RothmanUniversity));
break;
case Cities.Volhaven:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenZBInstituteOfTechnology));
break;
default:
elems.taskDetailsSelector2!.add(createOptionElement("No university available in city!"));
break;
}
break;
case "Workout at Gym":
// First selector has what stat is being trained
for (let i = 0; i < gymSelectorOptions.length; ++i) {
elems.taskDetailsSelector!.add(createOptionElement(gymSelectorOptions[i]));
}
// Second selector has gym
switch (sleeve.city) {
case Cities.Aevum:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumCrushFitnessGym));
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSnapFitnessGym));
break;
case Cities.Sector12:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12IronGym));
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12PowerhouseGym));
break;
case Cities.Volhaven:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenMilleniumFitnessGym));
break;
default:
elems.taskDetailsSelector2!.add(createOptionElement("No gym available in city!"));
break;
}
break;
case "Shock Recovery":
// No options in "Details" selector
return;
case "Synchronize":
// No options in "Details" selector
return;
default:
break;
}
}
function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): void {
try {
if (playerRef == null) {
throw new Error("playerRef is null in Sleeve UI's setSleeveTask()");
}
const taskValue: string = getSelectValue(elems.taskSelector);
const detailValue: string = getSelectValue(elems.taskDetailsSelector);
const detailValue2: string = getSelectValue(elems.taskDetailsSelector);
let res: boolean = false;
switch(taskValue) {
case "Work for Company":
res = sleeve.workForCompany(playerRef!, detailValue);
if (res) {
elems.taskDescription!.innerText = `This sleeve is currently working your ` +
`job at ${sleeve.currentTaskLocation}.`;
} else {
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
}
break;
case "Work for Faction":
res = sleeve.workForFaction(playerRef!, detailValue, detailValue2);
if (res) {
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ` +
`${sleeve.currentTaskLocation}.`;
} else {
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
}
break;
case "Commit Crime":
sleeve.commitCrime(playerRef!, Crimes[detailValue]);
elems.taskDescription!.innerText = `This sleeve is currently attempting to ` +
`${Crimes[detailValue]}.`;
break;
case "Take University Course":
res = sleeve.takeUniversityCourse(playerRef!, detailValue2, detailValue);
break;
case "Workout at Gym":
res = sleeve.workoutAtGym(playerRef!, detailValue2, detailValue);
break;
case "Shock Recovery":
sleeve.currentTask = SleeveTaskType.Recovery;
elems.taskDescription!.innerText = "This sleeve is currently set to focus on shock recovery. This causes " +
"the Sleeve's shock to decrease at a faster rate.";
break;
case "Synchronize":
sleeve.currentTask = SleeveTaskType.Sync;
elems.taskDescription!.innerText = "This sleeve is currently set to synchronize with the original consciousness. " +
"This causes the Sleeve's synchronization to increase."
break;
default:
console.error(`Invalid/Unrecognized taskValue in setSleeveTask(): ${taskValue}`);
}
if (routing.isOn(Page.Sleeves)) {
updateSleevesPage();
}
} catch(e) {
exceptionAlert(e);
}
}

@ -13,7 +13,8 @@ import * as posNames from "./Company/data/CompanyPosi
import {CONSTANTS} from "./Constants";
import { Corporation } from "./Corporation/Corporation";
import { Programs } from "./Programs/Programs";
import {determineCrimeSuccess, Crimes} from "./Crimes";
import { determineCrimeSuccess } from "./Crime/CrimeHelpers";
import { Crimes } from "./Crime/Crimes";
import {Engine} from "./engine";
import { Faction } from "./Faction/Faction";
import { Factions } from "./Faction/Factions";
@ -98,9 +99,13 @@ function PlayerObject() {
this.city = Locations.Sector12;
this.location = "";
//Company Information
// Jobs that the player holds
// Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object)
// The CompanyPosition name must match a key value in CompanyPositions
this.jobs = {};
// Company at which player is CURRENTLY working (only valid when the player is actively working)
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
@ -259,7 +264,7 @@ PlayerObject.prototype.prestigeAugmentation = function() {
this.location = "";
this.companyName = "";
this.companyPosition = "";
this.jobs = {};
this.purchasedServers = [];
@ -339,7 +344,7 @@ PlayerObject.prototype.prestigeSourceFile = function() {
this.location = "";
this.companyName = "";
this.companyPosition = "";
this.jobs = {};
this.purchasedServers = [];
@ -721,8 +726,10 @@ PlayerObject.prototype.work = function(numCycles) {
companyRep = comp.playerReputation;
}
const position = this.jobs[this.companyName];
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition +
txt.innerHTML = "You are currently working as a " + position +
" at " + this.companyName + " (Current Company Reputation: " +
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
@ -841,9 +848,11 @@ PlayerObject.prototype.workPartTime = function(numCycles) {
companyRep = comp.playerReputation;
}
const position = this.jobs[this.companyName];
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition +
" at " + Player.companyName + " (Current Company Reputation: " +
txt.innerHTML = "You are currently working as a " + position +
" at " + this.companyName + " (Current Company Reputation: " +
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"You have earned: <br><br>" +
@ -1076,9 +1085,10 @@ PlayerObject.prototype.getWorkMoneyGain = function() {
if (hasBn11SF) { bn11Mult = 1 + (company.favor / 100); }
// Get base salary
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (companyPosition == null) {
console.error(`Could not find CompanyPosition object for ${this.companyPosition}. Work salary will be 0`);
console.error(`Could not find CompanyPosition object for ${companyPositionName}. Work salary will be 0`);
return 0;
}
@ -1088,10 +1098,11 @@ PlayerObject.prototype.getWorkMoneyGain = function() {
//Hack exp gained per game cycle
PlayerObject.prototype.getWorkHackExpGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work hack exp gain will be 0`].join(" "));
return 0;
}
@ -1102,10 +1113,11 @@ PlayerObject.prototype.getWorkHackExpGain = function() {
//Str exp gained per game cycle
PlayerObject.prototype.getWorkStrExpGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work str exp gain will be 0`].join(" "));
return 0;
}
@ -1116,10 +1128,11 @@ PlayerObject.prototype.getWorkStrExpGain = function() {
//Def exp gained per game cycle
PlayerObject.prototype.getWorkDefExpGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work def exp gain will be 0`].join(" "));
return 0;
}
@ -1130,10 +1143,11 @@ PlayerObject.prototype.getWorkDefExpGain = function() {
//Dex exp gained per game cycle
PlayerObject.prototype.getWorkDexExpGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work dex exp gain will be 0`].join(" "));
return 0;
}
@ -1144,10 +1158,11 @@ PlayerObject.prototype.getWorkDexExpGain = function() {
//Agi exp gained per game cycle
PlayerObject.prototype.getWorkAgiExpGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work agi exp gain will be 0`].join(" "));
return 0;
}
@ -1158,10 +1173,11 @@ PlayerObject.prototype.getWorkAgiExpGain = function() {
//Charisma exp gained per game cycle
PlayerObject.prototype.getWorkChaExpGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work cha exp gain will be 0`].join(" "));
return 0;
}
@ -1172,10 +1188,11 @@ PlayerObject.prototype.getWorkChaExpGain = function() {
//Reputation gained per game cycle
PlayerObject.prototype.getWorkRepGain = function() {
const company = Companies[this.companyName];
const companyPosition = CompanyPositions[this.companyPosition];
const companyPositionName = this.jobs[this.companyName];
const companyPosition = CompanyPositions[companyPositionName];
if (company == null || companyPosition == null) {
console.error([`Could not find Company object for ${this.companyName}`,
`or CompanyPosition object for ${this.companyPosition}.`,
`or CompanyPosition object for ${companyPositionName}.`,
`Work rep gain will be 0`].join(" "));
return 0;
}
@ -1458,7 +1475,9 @@ PlayerObject.prototype.finishClass = function(sing=false) {
}
//The EXP and $ gains are hardcoded. Time is in ms
PlayerObject.prototype.startCrime = function(hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams=null) {
PlayerObject.prototype.startCrime = function(crimeType, hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams=null) {
this.crimeType = crimeType;
this.resetWorkStatus();
this.isWorking = true;
this.workType = CONSTANTS.WorkTypeCrime;
@ -1672,7 +1691,7 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
if (this.companyName !== "") {
currCompany = Companies[this.companyName];
}
const currPositionName = this.companyPosition;
const currPositionName = this.jobs[this.companyName];
// Get company that's being applied to
const company = Companies[this.location]; //Company being applied to
@ -1729,33 +1748,14 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
}
}
//Lose reputation from a Company if you are leaving it for another job
let leaveCompany = false;
let oldCompanyName = "";
if (currCompany != null) {
if (currCompany.name != company.name) {
leaveCompany = true;
oldCompanyName = currCompany.name;
currCompany.playerReputation -= 1000;
if (currCompany.playerReputation < 0) { currCompany.playerReputation = 0; }
}
}
this.companyName = company.name;
this.companyPosition = pos.name;
this.jobs[company.name] = 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.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.name + "!");
}
if (sing) { return true; }
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
Engine.loadLocationContent();
}
@ -1775,7 +1775,8 @@ PlayerObject.prototype.getNextCompanyPosition = function(company, 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.
const currentPosition = CompanyPositions[this.companyPosition];
const currentPositionName = this.jobs[this.companyName];
const currentPosition = CompanyPositions[currentPositionName];
if ((currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) ||
(currentPosition.isITJob() && entryPosType.isITJob()) ||
(currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) ||
@ -1852,7 +1853,7 @@ PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
this.companyName = company.name;
this.companyPosition = posNames.MiscCompanyPositions[1];
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1868,7 +1869,7 @@ PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
this.companyName = company.name;
this.companyPosition = posNames.PartTimeCompanyPositions[1];
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1884,7 +1885,7 @@ PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
this.companyName = company.name;
this.companyPosition = posNames.MiscCompanyPositions[0];
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1900,7 +1901,7 @@ PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
this.companyName = company.name;
this.companyPosition = posNames.PartTimeCompanyPositions[0];
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
if (sing) {return true;}
@ -1995,6 +1996,9 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
companyRep = company.playerReputation;
}
const allCompanies = Object.keys(this.jobs);
const allPositions = Object.values(this.jobs);
//Illuminati
var illuminatiFac = Factions["Illuminati"];
if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited &&
@ -2033,14 +2037,14 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
//ECorp
var ecorpFac = Factions["ECorp"];
if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited &&
this.companyName == Locations.AevumECorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.AevumECorp) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(ecorpFac);
}
//MegaCorp
var megacorpFac = Factions["MegaCorp"];
if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited &&
this.companyName == Locations.Sector12MegaCorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.Sector12MegaCorp) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(megacorpFac);
}
@ -2048,42 +2052,42 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
var bachmanandassociatesFac = Factions["Bachman & Associates"];
if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember &&
!bachmanandassociatesFac.alreadyInvited &&
this.companyName == Locations.AevumBachmanAndAssociates && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.AevumBachmanAndAssociates) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(bachmanandassociatesFac);
}
//Blade Industries
var bladeindustriesFac = Factions["Blade Industries"];
if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited &&
this.companyName == Locations.Sector12BladeIndustries && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.Sector12BladeIndustries) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(bladeindustriesFac);
}
//NWO
var nwoFac = Factions["NWO"];
if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited &&
this.companyName == Locations.VolhavenNWO && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.VolhavenNWO) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(nwoFac);
}
//Clarke Incorporated
var clarkeincorporatedFac = Factions["Clarke Incorporated"];
if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited &&
this.companyName == Locations.AevumClarkeIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.AevumClarkeIncorporated) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(clarkeincorporatedFac);
}
//OmniTek Incorporated
var omnitekincorporatedFac = Factions["OmniTek Incorporated"];
if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited &&
this.companyName == Locations.VolhavenOmniTekIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.VolhavenOmniTekIncorporated) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(omnitekincorporatedFac);
}
//Four Sigma
var foursigmaFac = Factions["Four Sigma"];
if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited &&
this.companyName == Locations.Sector12FourSigma && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.Sector12FourSigma) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(foursigmaFac);
}
@ -2091,7 +2095,7 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
var kuaigonginternationalFac = Factions["KuaiGong International"];
if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember &&
!kuaigonginternationalFac.alreadyInvited &&
this.companyName == Locations.ChongqingKuaiGongInternational && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
allCompanies.includes(Locations.ChongqingKuaiGongInternational) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
invitedFactions.push(kuaigonginternationalFac);
}
@ -2104,7 +2108,7 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
!fulcrumsecrettechonologiesFac.alreadyInvited &&
fulcrumSecretServer.manuallyHacked &&
this.companyName == Locations.AevumFulcrumTechnologies && companyRep >= 250000) {
allCompanies.includes(Locations.AevumFulcrumTechnologies) && companyRep >= 250000) {
invitedFactions.push(fulcrumsecrettechonologiesFac);
}
}
@ -2187,8 +2191,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited &&
this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 &&
this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 &&
this.karma <= -45 && this.companyName != Locations.Sector12CIA &&
this.companyName != Locations.Sector12NSA) {
this.karma <= -45 && !allCompanies.includes(Locations.Sector12CIA) &&
!allCompanies.includes(Locations.Sector12NSA)) {
invitedFactions.push(speakersforthedeadFac);
}
@ -2197,8 +2201,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited &&
this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 &&
this.dexterity >= 300 && this.agility >= 300 && this.city == Locations.Chongqing &&
this.numPeopleKilled >= 5 && this.karma <= -45 && this.companyName != Locations.Sector12CIA &&
this.companyName != Locations.Sector12NSA) {
this.numPeopleKilled >= 5 && this.karma <= -45 && !allCompanies.includes(Locations.Sector12CIA) &&
!allCompanies.includes(Locations.Sector12NSA)) {
invitedFactions.push(thedarkarmyFac);
}
@ -2209,18 +2213,16 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
this.dexterity >= 200 && this.agility >= 200 &&
(this.city == Locations.Aevum || this.city == Locations.Sector12) &&
this.money.gte(10000000) && this.karma <= -90 &&
this.companyName != Locations.Sector12CIA && this.companyName != Locations.Sector12NSA) {
!allCompanies.includes(Locations.Sector12CIA) && !allCompanies.includes(Locations.Sector12NSA)) {
invitedFactions.push(thesyndicateFac);
}
//Silhouette
var silhouetteFac = Factions["Silhouette"];
const companyPosition = CompanyPositions[this.companyPosition];
if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited &&
companyPosition != null &&
(companyPosition.name == "Chief Technology Officer" ||
companyPosition.name == "Chief Financial Officer" ||
companyPosition.name == "Chief Executive Officer") &&
(allPositions.includes("Chief Technology Officer") ||
allPositions.includes("Chief Financial Officer") ||
allPositions.includes("Chief Executive Officer")) &&
this.money.gte(15000000) && this.karma <= -22) {
invitedFactions.push(silhouetteFac);
}

@ -151,6 +151,16 @@ function evaluateVersionCompatibility(ver) {
}
}
}
// This version allowed players to hold multiple jobs
if (ver <= "0.43.0") {
if (Player.companyName !== "" && Player.companyPosition !== "") {
console.log("Copied player's companyName and companyPosition properties to the Player.jobs map for v0.43.0");
Player.jobs[Player.companyName] = Player.companyPosition;
}
delete Player.companyPosition;
}
}
function loadGame(saveString) {

@ -557,9 +557,9 @@ const Engine = {
displayCharacterInfo: function() {
removeChildrenFromElement(Engine.Display.characterInfo);
var companyPosition = "";
if (Player.companyPosition !== "") {
companyPosition = Player.companyPosition;
let companyPosition = "";
if (Player.companyName !== "") {
companyPosition = Player.jobs[Player.companyName];
}
var intText = "";
@ -576,8 +576,9 @@ const Engine = {
innerHTML:
'<b>General</b><br><br>' +
'Current City: ' + Player.city + '<br><br>' +
'Employer: ' + Player.companyName + '<br>' +
'Job Title: ' + companyPosition + '<br><br>' +
`Employer at which you last worked: ${Player.companyName}<br>` +
`Job you last worked: ${companyPosition}<br>` +
`All Employers: ${Object.keys(Player.jobs).join(", ")}<br><br>` +
'Money: $' + formatNumber(Player.money.toNumber(), 2) + '<br><br><br>' +
'<b>Stats</b><br><br>' +
'Hacking Level: ' + (Player.hacking_skill).toLocaleString() +
@ -1306,7 +1307,7 @@ const Engine = {
else {factions.style.display = "none";}
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
else {augmentations.style.display = "none";}
if (Player.companyPosition !== "") {visibleMenuTabs.push(job);}
if (Player.companyName !== "") {visibleMenuTabs.push(job);}
else {job.style.display = "none";}
if (Player.firstTimeTraveled) {visibleMenuTabs.push(travel);}
else {travel.style.display = "none";}
@ -1589,7 +1590,7 @@ const Engine = {
var gangLink = document.getElementById("gang-menu-link");
// Determine whether certain links should show up
job.style.display = Player.companyPosition !== "" ? "list-item" : "none";
job.style.display = Player.companyName !== "" ? "list-item" : "none";
stockmarket.style.display = Player.hasWseAccount ? "list-item" : "none";
bladeburner.style.display = Player.bladeburner instanceof Bladeburner ? "list-item" : "none";
corporation.style.display = Player.corporation instanceof Corporation ? "list-item" : "none";

@ -40,13 +40,20 @@ class NumeralFormatter {
return numeral(n).format(format);
}
formatBigNumber(n: number): string {
return this.format(n, "0.000a");
}
formatMoney(n: number): string {
return this.format(n, "$0.000a");
}
formatBigNumber(n: number): string {
return this.format(n, "0.000a");
formatPercentage(n: number, decimalPlaces: number=2): string {
const formatter: string = "0." + "0".repeat(decimalPlaces) + "%";
return this.format(n, formatter);
}
}
export const numeralWrapper = new NumeralFormatter();

@ -1,11 +1,11 @@
import { createElement } from "./createElement";
export function createOptionElement(text: string, value: string="") {
const sanitizedValue: string = value;
export function createOptionElement(text: string, value: string=""): HTMLOptionElement {
let sanitizedValue: string = value;
if (sanitizedValue === "") { sanitizedValue = text; }
return createElement("option", {
text: text,
value: sanitizedValue,
});
}) as HTMLOptionElement;
}

@ -0,0 +1,9 @@
export function getSelectValue(selector: HTMLSelectElement | null): string {
if (selector == null) { return ""; }
return selector[selector.selectedIndex].value;
}
export function getSelectText(selector: HTMLSelectElement | null): string {
if (selector == null) { return ""; }
return selector[selector.selectedIndex].text;
}