mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-26 11:10:58 +02:00
prettify, sorry for the big ass commit
This commit is contained in:
+180
-175
@@ -8,185 +8,190 @@ import { Sleeve } from "./Sleeve/Sleeve";
|
||||
|
||||
import { IMap } from "../types";
|
||||
|
||||
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { Company } from "../Company/Company";
|
||||
import { CompanyPosition } from "../Company/CompanyPosition";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { HashManager } from "../Hacknet/HashManager";
|
||||
import { HacknetNode } from "../Hacknet/HacknetNode";
|
||||
import { LocationName } from "../Locations/data/LocationNames";
|
||||
import { Server } from "../Server/Server";
|
||||
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
|
||||
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
|
||||
import { Exploit } from "../Exploits/Exploit";
|
||||
import { ICorporation } from "../Corporation/ICorporation";
|
||||
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { Company } from "../Company/Company";
|
||||
import { CompanyPosition } from "../Company/CompanyPosition";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { HashManager } from "../Hacknet/HashManager";
|
||||
import { HacknetNode } from "../Hacknet/HacknetNode";
|
||||
import { LocationName } from "../Locations/data/LocationNames";
|
||||
import { Server } from "../Server/Server";
|
||||
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
|
||||
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
|
||||
import { Exploit } from "../Exploits/Exploit";
|
||||
import { ICorporation } from "../Corporation/ICorporation";
|
||||
|
||||
export interface IPlayer {
|
||||
// Class members
|
||||
augmentations: IPlayerOwnedAugmentation[];
|
||||
bladeburner: any;
|
||||
bitNodeN: number;
|
||||
city: CityName;
|
||||
companyName: string;
|
||||
corporation: ICorporation;
|
||||
currentServer: string;
|
||||
factions: string[];
|
||||
factionInvitations: string[];
|
||||
firstProgramAvailable: boolean;
|
||||
firstTimeTraveled: boolean;
|
||||
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
|
||||
has4SData: boolean;
|
||||
has4SDataTixApi: boolean;
|
||||
hashManager: HashManager;
|
||||
hasTixApiAccess: boolean;
|
||||
hasWseAccount: boolean;
|
||||
homeComputer: string;
|
||||
hp: number;
|
||||
jobs: IMap<string>;
|
||||
init: () => void;
|
||||
isWorking: boolean;
|
||||
karma: number;
|
||||
numPeopleKilled: number;
|
||||
location: LocationName;
|
||||
max_hp: number;
|
||||
money: any;
|
||||
moneySourceA: MoneySourceTracker;
|
||||
moneySourceB: MoneySourceTracker;
|
||||
playtimeSinceLastAug: number;
|
||||
playtimeSinceLastBitnode: number;
|
||||
purchasedServers: any[];
|
||||
queuedAugmentations: IPlayerOwnedAugmentation[];
|
||||
resleeves: Resleeve[];
|
||||
scriptProdSinceLastAug: number;
|
||||
sleeves: Sleeve[];
|
||||
sleevesFromCovenant: number;
|
||||
sourceFiles: IPlayerOwnedSourceFile[];
|
||||
exploits: Exploit[];
|
||||
totalPlaytime: number;
|
||||
// Class members
|
||||
augmentations: IPlayerOwnedAugmentation[];
|
||||
bladeburner: any;
|
||||
bitNodeN: number;
|
||||
city: CityName;
|
||||
companyName: string;
|
||||
corporation: ICorporation;
|
||||
currentServer: string;
|
||||
factions: string[];
|
||||
factionInvitations: string[];
|
||||
firstProgramAvailable: boolean;
|
||||
firstTimeTraveled: boolean;
|
||||
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
|
||||
has4SData: boolean;
|
||||
has4SDataTixApi: boolean;
|
||||
hashManager: HashManager;
|
||||
hasTixApiAccess: boolean;
|
||||
hasWseAccount: boolean;
|
||||
homeComputer: string;
|
||||
hp: number;
|
||||
jobs: IMap<string>;
|
||||
init: () => void;
|
||||
isWorking: boolean;
|
||||
karma: number;
|
||||
numPeopleKilled: number;
|
||||
location: LocationName;
|
||||
max_hp: number;
|
||||
money: any;
|
||||
moneySourceA: MoneySourceTracker;
|
||||
moneySourceB: MoneySourceTracker;
|
||||
playtimeSinceLastAug: number;
|
||||
playtimeSinceLastBitnode: number;
|
||||
purchasedServers: any[];
|
||||
queuedAugmentations: IPlayerOwnedAugmentation[];
|
||||
resleeves: Resleeve[];
|
||||
scriptProdSinceLastAug: number;
|
||||
sleeves: Sleeve[];
|
||||
sleevesFromCovenant: number;
|
||||
sourceFiles: IPlayerOwnedSourceFile[];
|
||||
exploits: Exploit[];
|
||||
totalPlaytime: number;
|
||||
|
||||
// Stats
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
intelligence: number;
|
||||
// Stats
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
intelligence: number;
|
||||
|
||||
// Experience
|
||||
hacking_exp: number;
|
||||
strength_exp: number;
|
||||
defense_exp: number;
|
||||
dexterity_exp: number;
|
||||
agility_exp: number;
|
||||
charisma_exp: number;
|
||||
// Experience
|
||||
hacking_exp: number;
|
||||
strength_exp: number;
|
||||
defense_exp: number;
|
||||
dexterity_exp: number;
|
||||
agility_exp: number;
|
||||
charisma_exp: number;
|
||||
|
||||
// Multipliers
|
||||
hacking_chance_mult: number;
|
||||
hacking_speed_mult: number;
|
||||
hacking_money_mult: number;
|
||||
hacking_grow_mult: number;
|
||||
hacking_mult: number;
|
||||
hacking_exp_mult: number;
|
||||
strength_mult: number;
|
||||
strength_exp_mult: number;
|
||||
defense_mult: number;
|
||||
defense_exp_mult: number;
|
||||
dexterity_mult: number;
|
||||
dexterity_exp_mult: number;
|
||||
agility_mult: number;
|
||||
agility_exp_mult: number;
|
||||
charisma_mult: number;
|
||||
charisma_exp_mult: number;
|
||||
hacknet_node_money_mult: number;
|
||||
hacknet_node_purchase_cost_mult: number;
|
||||
hacknet_node_ram_cost_mult: number;
|
||||
hacknet_node_core_cost_mult: number;
|
||||
hacknet_node_level_cost_mult: number;
|
||||
company_rep_mult: number;
|
||||
faction_rep_mult: number;
|
||||
work_money_mult: number;
|
||||
crime_success_mult: number;
|
||||
crime_money_mult: number;
|
||||
bladeburner_max_stamina_mult: number;
|
||||
bladeburner_stamina_gain_mult: number;
|
||||
bladeburner_analysis_mult: number;
|
||||
bladeburner_success_chance_mult: number;
|
||||
// Multipliers
|
||||
hacking_chance_mult: number;
|
||||
hacking_speed_mult: number;
|
||||
hacking_money_mult: number;
|
||||
hacking_grow_mult: number;
|
||||
hacking_mult: number;
|
||||
hacking_exp_mult: number;
|
||||
strength_mult: number;
|
||||
strength_exp_mult: number;
|
||||
defense_mult: number;
|
||||
defense_exp_mult: number;
|
||||
dexterity_mult: number;
|
||||
dexterity_exp_mult: number;
|
||||
agility_mult: number;
|
||||
agility_exp_mult: number;
|
||||
charisma_mult: number;
|
||||
charisma_exp_mult: number;
|
||||
hacknet_node_money_mult: number;
|
||||
hacknet_node_purchase_cost_mult: number;
|
||||
hacknet_node_ram_cost_mult: number;
|
||||
hacknet_node_core_cost_mult: number;
|
||||
hacknet_node_level_cost_mult: number;
|
||||
company_rep_mult: number;
|
||||
faction_rep_mult: number;
|
||||
work_money_mult: number;
|
||||
crime_success_mult: number;
|
||||
crime_money_mult: number;
|
||||
bladeburner_max_stamina_mult: number;
|
||||
bladeburner_stamina_gain_mult: number;
|
||||
bladeburner_analysis_mult: number;
|
||||
bladeburner_success_chance_mult: number;
|
||||
|
||||
// Methods
|
||||
applyForAgentJob(sing?: boolean): boolean | void;
|
||||
applyForBusinessConsultantJob(sing?: boolean): boolean | void;
|
||||
applyForBusinessJob(sing?: boolean): boolean | void;
|
||||
applyForEmployeeJob(sing?: boolean): boolean | void;
|
||||
applyForItJob(sing?: boolean): boolean | void;
|
||||
applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean | void;
|
||||
applyForNetworkEngineerJob(sing?: boolean): boolean | void;
|
||||
applyForPartTimeEmployeeJob(sing?: boolean): boolean | void;
|
||||
applyForPartTimeWaiterJob(sing?: boolean): boolean | void;
|
||||
applyForSecurityEngineerJob(sing?: boolean): boolean | void;
|
||||
applyForSecurityJob(sing?: boolean): boolean | void;
|
||||
applyForSoftwareConsultantJob(sing?: boolean): boolean | void;
|
||||
applyForSoftwareJob(sing?: boolean): boolean | void;
|
||||
applyForWaiterJob(sing?: boolean): boolean | void;
|
||||
canAccessBladeburner(): boolean;
|
||||
canAccessCorporation(): boolean;
|
||||
canAccessGang(): boolean;
|
||||
canAccessResleeving(): boolean;
|
||||
canAfford(cost: number): boolean;
|
||||
gainHackingExp(exp: number): void;
|
||||
gainStrengthExp(exp: number): void;
|
||||
gainDefenseExp(exp: number): void;
|
||||
gainDexterityExp(exp: number): void;
|
||||
gainAgilityExp(exp: number): void;
|
||||
gainCharismaExp(exp: number): void;
|
||||
gainIntelligenceExp(exp: number): void;
|
||||
gainMoney(money: number): void;
|
||||
getCurrentServer(): Server;
|
||||
getGangFaction(): Faction;
|
||||
getGangName(): string;
|
||||
getHomeComputer(): Server;
|
||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
|
||||
getUpgradeHomeRamCost(): number;
|
||||
gotoLocation(to: LocationName): boolean;
|
||||
hasCorporation(): boolean;
|
||||
hasGangWith(facName: string): boolean;
|
||||
hasTorRouter(): boolean;
|
||||
hasProgram(program: string): boolean;
|
||||
inBladeburner(): boolean;
|
||||
inGang(): boolean;
|
||||
isQualified(company: Company, position: CompanyPosition): boolean;
|
||||
loseMoney(money: number): void;
|
||||
reapplyAllAugmentations(resetMultipliers: boolean): void;
|
||||
reapplyAllSourceFiles(): void;
|
||||
regenerateHp(amt: number): void;
|
||||
recordMoneySource(amt: number, source: string): void;
|
||||
setMoney(amt: number): void;
|
||||
singularityStopWork(): void;
|
||||
startBladeburner(p: any): void;
|
||||
startClass(costMult: number, expMult: number, className: string): void;
|
||||
startCorporation(corpName: string, additionalShares?: number): void;
|
||||
startCrime(crimeType: string,
|
||||
hackExp: number,
|
||||
strExp: number,
|
||||
defExp: number,
|
||||
dexExp: number,
|
||||
agiExp: number,
|
||||
chaExp: number,
|
||||
money: number,
|
||||
time: number,
|
||||
singParams: any): void;
|
||||
startFactionFieldWork(faction: Faction): void;
|
||||
startFactionHackWork(faction: Faction): void;
|
||||
startFactionSecurityWork(faction: Faction): void;
|
||||
startGang(facName: string, isHacking: boolean): void;
|
||||
startWork(companyName: string): void;
|
||||
startWorkPartTime(companyName: string): void;
|
||||
takeDamage(amt: number): boolean;
|
||||
travel(to: CityName): boolean;
|
||||
giveExploit(exploit: Exploit): void;
|
||||
queryStatFromString(str: string): number;
|
||||
getIntelligenceBonus(weight: number): number;
|
||||
getCasinoWinnings(): number;
|
||||
quitJob(company: string): void;
|
||||
// Methods
|
||||
applyForAgentJob(sing?: boolean): boolean | void;
|
||||
applyForBusinessConsultantJob(sing?: boolean): boolean | void;
|
||||
applyForBusinessJob(sing?: boolean): boolean | void;
|
||||
applyForEmployeeJob(sing?: boolean): boolean | void;
|
||||
applyForItJob(sing?: boolean): boolean | void;
|
||||
applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean | void;
|
||||
applyForNetworkEngineerJob(sing?: boolean): boolean | void;
|
||||
applyForPartTimeEmployeeJob(sing?: boolean): boolean | void;
|
||||
applyForPartTimeWaiterJob(sing?: boolean): boolean | void;
|
||||
applyForSecurityEngineerJob(sing?: boolean): boolean | void;
|
||||
applyForSecurityJob(sing?: boolean): boolean | void;
|
||||
applyForSoftwareConsultantJob(sing?: boolean): boolean | void;
|
||||
applyForSoftwareJob(sing?: boolean): boolean | void;
|
||||
applyForWaiterJob(sing?: boolean): boolean | void;
|
||||
canAccessBladeburner(): boolean;
|
||||
canAccessCorporation(): boolean;
|
||||
canAccessGang(): boolean;
|
||||
canAccessResleeving(): boolean;
|
||||
canAfford(cost: number): boolean;
|
||||
gainHackingExp(exp: number): void;
|
||||
gainStrengthExp(exp: number): void;
|
||||
gainDefenseExp(exp: number): void;
|
||||
gainDexterityExp(exp: number): void;
|
||||
gainAgilityExp(exp: number): void;
|
||||
gainCharismaExp(exp: number): void;
|
||||
gainIntelligenceExp(exp: number): void;
|
||||
gainMoney(money: number): void;
|
||||
getCurrentServer(): Server;
|
||||
getGangFaction(): Faction;
|
||||
getGangName(): string;
|
||||
getHomeComputer(): Server;
|
||||
getNextCompanyPosition(
|
||||
company: Company,
|
||||
entryPosType: CompanyPosition,
|
||||
): CompanyPosition;
|
||||
getUpgradeHomeRamCost(): number;
|
||||
gotoLocation(to: LocationName): boolean;
|
||||
hasCorporation(): boolean;
|
||||
hasGangWith(facName: string): boolean;
|
||||
hasTorRouter(): boolean;
|
||||
hasProgram(program: string): boolean;
|
||||
inBladeburner(): boolean;
|
||||
inGang(): boolean;
|
||||
isQualified(company: Company, position: CompanyPosition): boolean;
|
||||
loseMoney(money: number): void;
|
||||
reapplyAllAugmentations(resetMultipliers: boolean): void;
|
||||
reapplyAllSourceFiles(): void;
|
||||
regenerateHp(amt: number): void;
|
||||
recordMoneySource(amt: number, source: string): void;
|
||||
setMoney(amt: number): void;
|
||||
singularityStopWork(): void;
|
||||
startBladeburner(p: any): void;
|
||||
startClass(costMult: number, expMult: number, className: string): void;
|
||||
startCorporation(corpName: string, additionalShares?: number): void;
|
||||
startCrime(
|
||||
crimeType: string,
|
||||
hackExp: number,
|
||||
strExp: number,
|
||||
defExp: number,
|
||||
dexExp: number,
|
||||
agiExp: number,
|
||||
chaExp: number,
|
||||
money: number,
|
||||
time: number,
|
||||
singParams: any,
|
||||
): void;
|
||||
startFactionFieldWork(faction: Faction): void;
|
||||
startFactionHackWork(faction: Faction): void;
|
||||
startFactionSecurityWork(faction: Faction): void;
|
||||
startGang(facName: string, isHacking: boolean): void;
|
||||
startWork(companyName: string): void;
|
||||
startWorkPartTime(companyName: string): void;
|
||||
takeDamage(amt: number): boolean;
|
||||
travel(to: CityName): boolean;
|
||||
giveExploit(exploit: Exploit): void;
|
||||
queryStatFromString(str: string): number;
|
||||
getIntelligenceBonus(weight: number): number;
|
||||
getCasinoWinnings(): number;
|
||||
quitJob(company: string): void;
|
||||
}
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
// a Sleeve. Used for functions that need to take in both.
|
||||
|
||||
export interface IPlayerOrSleeve {
|
||||
// Stats
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
intelligence: number;
|
||||
// Stats
|
||||
hacking_skill: number;
|
||||
strength: number;
|
||||
defense: number;
|
||||
dexterity: number;
|
||||
agility: number;
|
||||
charisma: number;
|
||||
intelligence: number;
|
||||
|
||||
// Experience
|
||||
hacking_exp: number;
|
||||
strength_exp: number;
|
||||
defense_exp: number;
|
||||
dexterity_exp: number;
|
||||
agility_exp: number;
|
||||
charisma_exp: number;
|
||||
// Experience
|
||||
hacking_exp: number;
|
||||
strength_exp: number;
|
||||
defense_exp: number;
|
||||
dexterity_exp: number;
|
||||
agility_exp: number;
|
||||
charisma_exp: number;
|
||||
|
||||
// Multipliers
|
||||
crime_success_mult: number;
|
||||
// Multipliers
|
||||
crime_success_mult: number;
|
||||
|
||||
getIntelligenceBonus(weight: number): number;
|
||||
getIntelligenceBonus(weight: number): number;
|
||||
}
|
||||
|
||||
+227
-172
@@ -10,207 +10,262 @@ import { calculateIntelligenceBonus } from "./formulas/intelligence";
|
||||
// Interface that defines a generic object used to track experience/money
|
||||
// earnings for tasks
|
||||
export interface ITaskTracker {
|
||||
hack: number;
|
||||
str: number;
|
||||
def: number;
|
||||
dex: number;
|
||||
agi: number;
|
||||
cha: number;
|
||||
money: number;
|
||||
hack: number;
|
||||
str: number;
|
||||
def: number;
|
||||
dex: number;
|
||||
agi: number;
|
||||
cha: number;
|
||||
money: number;
|
||||
}
|
||||
|
||||
export function createTaskTracker(): ITaskTracker {
|
||||
return {
|
||||
hack: 0,
|
||||
str: 0,
|
||||
def: 0,
|
||||
dex: 0,
|
||||
agi: 0,
|
||||
cha: 0,
|
||||
money: 0,
|
||||
}
|
||||
return {
|
||||
hack: 0,
|
||||
str: 0,
|
||||
def: 0,
|
||||
dex: 0,
|
||||
agi: 0,
|
||||
cha: 0,
|
||||
money: 0,
|
||||
};
|
||||
}
|
||||
|
||||
export abstract class Person {
|
||||
/**
|
||||
* Stats
|
||||
*/
|
||||
hacking_skill = 1;
|
||||
strength = 1;
|
||||
defense = 1;
|
||||
dexterity = 1;
|
||||
agility = 1;
|
||||
charisma = 1;
|
||||
intelligence = 1;
|
||||
hp = 10;
|
||||
max_hp = 10;
|
||||
/**
|
||||
* Stats
|
||||
*/
|
||||
hacking_skill = 1;
|
||||
strength = 1;
|
||||
defense = 1;
|
||||
dexterity = 1;
|
||||
agility = 1;
|
||||
charisma = 1;
|
||||
intelligence = 1;
|
||||
hp = 10;
|
||||
max_hp = 10;
|
||||
|
||||
/**
|
||||
* Experience
|
||||
*/
|
||||
hacking_exp = 0;
|
||||
strength_exp = 0;
|
||||
defense_exp = 0;
|
||||
dexterity_exp = 0;
|
||||
agility_exp = 0;
|
||||
charisma_exp = 0;
|
||||
intelligence_exp = 0;
|
||||
/**
|
||||
* Experience
|
||||
*/
|
||||
hacking_exp = 0;
|
||||
strength_exp = 0;
|
||||
defense_exp = 0;
|
||||
dexterity_exp = 0;
|
||||
agility_exp = 0;
|
||||
charisma_exp = 0;
|
||||
intelligence_exp = 0;
|
||||
|
||||
/**
|
||||
* Multipliers
|
||||
*/
|
||||
hacking_mult = 1;
|
||||
strength_mult = 1;
|
||||
defense_mult = 1;
|
||||
dexterity_mult = 1;
|
||||
agility_mult = 1;
|
||||
charisma_mult = 1;
|
||||
/**
|
||||
* Multipliers
|
||||
*/
|
||||
hacking_mult = 1;
|
||||
strength_mult = 1;
|
||||
defense_mult = 1;
|
||||
dexterity_mult = 1;
|
||||
agility_mult = 1;
|
||||
charisma_mult = 1;
|
||||
|
||||
hacking_exp_mult = 1;
|
||||
strength_exp_mult = 1;
|
||||
defense_exp_mult = 1;
|
||||
dexterity_exp_mult = 1;
|
||||
agility_exp_mult = 1;
|
||||
charisma_exp_mult = 1;
|
||||
hacking_exp_mult = 1;
|
||||
strength_exp_mult = 1;
|
||||
defense_exp_mult = 1;
|
||||
dexterity_exp_mult = 1;
|
||||
agility_exp_mult = 1;
|
||||
charisma_exp_mult = 1;
|
||||
|
||||
hacking_chance_mult = 1;
|
||||
hacking_speed_mult = 1;
|
||||
hacking_money_mult = 1;
|
||||
hacking_grow_mult = 1;
|
||||
hacking_chance_mult = 1;
|
||||
hacking_speed_mult = 1;
|
||||
hacking_money_mult = 1;
|
||||
hacking_grow_mult = 1;
|
||||
|
||||
company_rep_mult = 1;
|
||||
faction_rep_mult = 1;
|
||||
company_rep_mult = 1;
|
||||
faction_rep_mult = 1;
|
||||
|
||||
crime_money_mult = 1;
|
||||
crime_success_mult = 1;
|
||||
crime_money_mult = 1;
|
||||
crime_success_mult = 1;
|
||||
|
||||
work_money_mult = 1;
|
||||
work_money_mult = 1;
|
||||
|
||||
hacknet_node_money_mult = 1;
|
||||
hacknet_node_purchase_cost_mult = 1;
|
||||
hacknet_node_ram_cost_mult = 1;
|
||||
hacknet_node_core_cost_mult = 1;
|
||||
hacknet_node_level_cost_mult = 1;
|
||||
hacknet_node_money_mult = 1;
|
||||
hacknet_node_purchase_cost_mult = 1;
|
||||
hacknet_node_ram_cost_mult = 1;
|
||||
hacknet_node_core_cost_mult = 1;
|
||||
hacknet_node_level_cost_mult = 1;
|
||||
|
||||
bladeburner_max_stamina_mult = 1;
|
||||
bladeburner_stamina_gain_mult = 1;
|
||||
bladeburner_analysis_mult = 1;
|
||||
bladeburner_success_chance_mult = 1;
|
||||
bladeburner_max_stamina_mult = 1;
|
||||
bladeburner_stamina_gain_mult = 1;
|
||||
bladeburner_analysis_mult = 1;
|
||||
bladeburner_success_chance_mult = 1;
|
||||
|
||||
/**
|
||||
* Augmentations
|
||||
*/
|
||||
augmentations: IPlayerOwnedAugmentation[] = [];
|
||||
queuedAugmentations: IPlayerOwnedAugmentation[] = [];
|
||||
/**
|
||||
* Augmentations
|
||||
*/
|
||||
augmentations: IPlayerOwnedAugmentation[] = [];
|
||||
queuedAugmentations: IPlayerOwnedAugmentation[] = [];
|
||||
|
||||
/**
|
||||
* City that the person is in
|
||||
*/
|
||||
city: CityName = CityName.Sector12;
|
||||
/**
|
||||
* City that the person is in
|
||||
*/
|
||||
city: CityName = CityName.Sector12;
|
||||
|
||||
/**
|
||||
* Updates this object's multipliers for the given augmentation
|
||||
*/
|
||||
applyAugmentation(aug: Augmentation): void {
|
||||
for (const mult in aug.mults) {
|
||||
if ((<any>this)[mult] == null) {
|
||||
console.warn(`Augmentation has unrecognized multiplier property: ${mult}`);
|
||||
} else {
|
||||
(<any>this)[mult] *= aug.mults[mult];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Updates this object's multipliers for the given augmentation
|
||||
*/
|
||||
applyAugmentation(aug: Augmentation): void {
|
||||
for (const mult in aug.mults) {
|
||||
if ((<any>this)[mult] == null) {
|
||||
console.warn(
|
||||
`Augmentation has unrecognized multiplier property: ${mult}`,
|
||||
);
|
||||
} else {
|
||||
(<any>this)[mult] *= aug.mults[mult];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an experience amount and stat multiplier, calculates the
|
||||
* stat level. Stat-agnostic (same formula for every stat)
|
||||
*/
|
||||
calculateStat(exp: number, mult=1): number {
|
||||
return calculateSkill(exp, mult);
|
||||
}
|
||||
/**
|
||||
* Given an experience amount and stat multiplier, calculates the
|
||||
* stat level. Stat-agnostic (same formula for every stat)
|
||||
*/
|
||||
calculateStat(exp: number, mult = 1): number {
|
||||
return calculateSkill(exp, mult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and return the amount of faction reputation earned per cycle
|
||||
* when doing Field Work for a faction
|
||||
*/
|
||||
getFactionFieldWorkRepGain(): number {
|
||||
const t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
this.strength / CONSTANTS.MaxSkillLevel +
|
||||
this.defense / CONSTANTS.MaxSkillLevel +
|
||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
this.agility / CONSTANTS.MaxSkillLevel +
|
||||
this.charisma / CONSTANTS.MaxSkillLevel) / 5.5;
|
||||
return t * this.faction_rep_mult;
|
||||
}
|
||||
/**
|
||||
* Calculate and return the amount of faction reputation earned per cycle
|
||||
* when doing Field Work for a faction
|
||||
*/
|
||||
getFactionFieldWorkRepGain(): number {
|
||||
const t =
|
||||
(0.9 *
|
||||
(this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
this.strength / CONSTANTS.MaxSkillLevel +
|
||||
this.defense / CONSTANTS.MaxSkillLevel +
|
||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
this.agility / CONSTANTS.MaxSkillLevel +
|
||||
this.charisma / CONSTANTS.MaxSkillLevel)) /
|
||||
5.5;
|
||||
return t * this.faction_rep_mult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and return the amount of faction reputation earned per cycle
|
||||
* when doing Hacking Work for a faction
|
||||
*/
|
||||
getFactionHackingWorkRepGain(): number {
|
||||
return this.hacking_skill / CONSTANTS.MaxSkillLevel * this.faction_rep_mult;
|
||||
}
|
||||
/**
|
||||
* Calculate and return the amount of faction reputation earned per cycle
|
||||
* when doing Hacking Work for a faction
|
||||
*/
|
||||
getFactionHackingWorkRepGain(): number {
|
||||
return (
|
||||
(this.hacking_skill / CONSTANTS.MaxSkillLevel) * this.faction_rep_mult
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and return the amount of faction reputation earned per cycle
|
||||
* when doing Security Work for a faction
|
||||
*/
|
||||
getFactionSecurityWorkRepGain(): number {
|
||||
const t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
this.strength / CONSTANTS.MaxSkillLevel +
|
||||
this.defense / CONSTANTS.MaxSkillLevel +
|
||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
this.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
||||
return t * this.faction_rep_mult;
|
||||
}
|
||||
/**
|
||||
* Calculate and return the amount of faction reputation earned per cycle
|
||||
* when doing Security Work for a faction
|
||||
*/
|
||||
getFactionSecurityWorkRepGain(): number {
|
||||
const t =
|
||||
(0.9 *
|
||||
(this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
this.strength / CONSTANTS.MaxSkillLevel +
|
||||
this.defense / CONSTANTS.MaxSkillLevel +
|
||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
this.agility / CONSTANTS.MaxSkillLevel)) /
|
||||
4.5;
|
||||
return t * this.faction_rep_mult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all multipliers to 1
|
||||
*/
|
||||
resetMultipliers(): void {
|
||||
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;
|
||||
|
||||
/**
|
||||
* Reset all multipliers to 1
|
||||
*/
|
||||
resetMultipliers(): void {
|
||||
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.company_rep_mult = 1;
|
||||
this.faction_rep_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.crime_money_mult = 1;
|
||||
this.crime_success_mult = 1;
|
||||
|
||||
this.company_rep_mult = 1;
|
||||
this.faction_rep_mult = 1;
|
||||
this.work_money_mult = 1;
|
||||
}
|
||||
|
||||
this.crime_money_mult = 1;
|
||||
this.crime_success_mult = 1;
|
||||
/**
|
||||
* Update all stat levels
|
||||
*/
|
||||
updateStatLevels(): void {
|
||||
this.hacking_skill = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
this.calculateStat(
|
||||
this.hacking_exp,
|
||||
this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.strength = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
this.calculateStat(
|
||||
this.strength_exp,
|
||||
this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.defense = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
this.calculateStat(
|
||||
this.defense_exp,
|
||||
this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.dexterity = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
this.calculateStat(
|
||||
this.dexterity_exp,
|
||||
this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.agility = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
this.calculateStat(
|
||||
this.agility_exp,
|
||||
this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.charisma = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
this.calculateStat(
|
||||
this.charisma_exp,
|
||||
this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
this.work_money_mult = 1;
|
||||
}
|
||||
const ratio: number = this.hp / this.max_hp;
|
||||
this.max_hp = Math.floor(10 + this.defense / 10);
|
||||
this.hp = Math.round(this.max_hp * ratio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all stat levels
|
||||
*/
|
||||
updateStatLevels(): void {
|
||||
this.hacking_skill = Math.max(1, Math.floor(this.calculateStat(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
|
||||
this.strength = Math.max(1, Math.floor(this.calculateStat(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier)));
|
||||
this.defense = Math.max(1, Math.floor(this.calculateStat(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier)));
|
||||
this.dexterity = Math.max(1, Math.floor(this.calculateStat(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier)));
|
||||
this.agility = Math.max(1, Math.floor(this.calculateStat(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier)));
|
||||
this.charisma = Math.max(1, Math.floor(this.calculateStat(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier)));
|
||||
|
||||
const ratio: number = this.hp / this.max_hp;
|
||||
this.max_hp = Math.floor(10 + this.defense / 10);
|
||||
this.hp = Math.round(this.max_hp * ratio);
|
||||
}
|
||||
|
||||
|
||||
getIntelligenceBonus(weight: number): number {
|
||||
return calculateIntelligenceBonus(this.intelligence, weight);
|
||||
}
|
||||
getIntelligenceBonus(weight: number): number {
|
||||
return calculateIntelligenceBonus(this.intelligence, weight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,219 +10,219 @@ import { CityName } from "../../Locations/data/CityNames";
|
||||
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON,
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON,
|
||||
} from "../../../utils/JSONReviver";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
export function PlayerObject() {
|
||||
//Skills and stats
|
||||
this.hacking_skill = 1;
|
||||
//Skills and stats
|
||||
this.hacking_skill = 1;
|
||||
|
||||
//Combat stats
|
||||
this.hp = 10;
|
||||
this.max_hp = 10;
|
||||
this.strength = 1;
|
||||
this.defense = 1;
|
||||
this.dexterity = 1;
|
||||
this.agility = 1;
|
||||
//Combat stats
|
||||
this.hp = 10;
|
||||
this.max_hp = 10;
|
||||
this.strength = 1;
|
||||
this.defense = 1;
|
||||
this.dexterity = 1;
|
||||
this.agility = 1;
|
||||
|
||||
//Labor stats
|
||||
this.charisma = 1;
|
||||
//Labor stats
|
||||
this.charisma = 1;
|
||||
|
||||
//Special stats
|
||||
this.intelligence = 0;
|
||||
//Special stats
|
||||
this.intelligence = 0;
|
||||
|
||||
//Hacking multipliers
|
||||
this.hacking_chance_mult = 1;
|
||||
this.hacking_speed_mult = 1;
|
||||
this.hacking_money_mult = 1;
|
||||
this.hacking_grow_mult = 1;
|
||||
//Hacking multipliers
|
||||
this.hacking_chance_mult = 1;
|
||||
this.hacking_speed_mult = 1;
|
||||
this.hacking_money_mult = 1;
|
||||
this.hacking_grow_mult = 1;
|
||||
|
||||
//Experience and 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;
|
||||
//Experience and 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_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.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.company_rep_mult = 1;
|
||||
this.faction_rep_mult = 1;
|
||||
|
||||
//Money
|
||||
this.money = new Decimal(1000);
|
||||
//Money
|
||||
this.money = new Decimal(1000);
|
||||
|
||||
//IP Address of Starting (home) computer
|
||||
this.homeComputer = "";
|
||||
//IP Address of Starting (home) computer
|
||||
this.homeComputer = "";
|
||||
|
||||
//Location information
|
||||
this.city = CityName.Sector12;
|
||||
this.location = "";
|
||||
//Location information
|
||||
this.city = CityName.Sector12;
|
||||
this.location = "";
|
||||
|
||||
// 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 = {};
|
||||
// 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
|
||||
// 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
|
||||
|
||||
// Servers
|
||||
this.currentServer = ""; //IP address of Server currently being accessed through terminal
|
||||
this.purchasedServers = []; //IP Addresses of purchased servers
|
||||
// Servers
|
||||
this.currentServer = ""; //IP address of Server currently being accessed through terminal
|
||||
this.purchasedServers = []; //IP Addresses of purchased servers
|
||||
|
||||
// Hacknet Nodes/Servers
|
||||
this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers
|
||||
this.hashManager = new HashManager();
|
||||
// Hacknet Nodes/Servers
|
||||
this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers
|
||||
this.hashManager = new HashManager();
|
||||
|
||||
//Factions
|
||||
this.factions = []; //Names of all factions player has joined
|
||||
this.factionInvitations = []; //Outstanding faction invitations
|
||||
//Factions
|
||||
this.factions = []; //Names of all factions player has joined
|
||||
this.factionInvitations = []; //Outstanding faction invitations
|
||||
|
||||
//Augmentations
|
||||
this.queuedAugmentations = [];
|
||||
this.augmentations = [];
|
||||
//Augmentations
|
||||
this.queuedAugmentations = [];
|
||||
this.augmentations = [];
|
||||
|
||||
this.sourceFiles = [];
|
||||
this.sourceFiles = [];
|
||||
|
||||
//Crime statistics
|
||||
this.numPeopleKilled = 0;
|
||||
this.karma = 0;
|
||||
//Crime statistics
|
||||
this.numPeopleKilled = 0;
|
||||
this.karma = 0;
|
||||
|
||||
this.crime_money_mult = 1;
|
||||
this.crime_success_mult = 1;
|
||||
this.crime_money_mult = 1;
|
||||
this.crime_success_mult = 1;
|
||||
|
||||
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
|
||||
this.isWorking = false;
|
||||
this.focus = false;
|
||||
this.workType = "";
|
||||
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
|
||||
this.isWorking = false;
|
||||
this.focus = false;
|
||||
this.workType = "";
|
||||
|
||||
this.currentWorkFactionName = "";
|
||||
this.currentWorkFactionDescription = "";
|
||||
this.currentWorkFactionName = "";
|
||||
this.currentWorkFactionDescription = "";
|
||||
|
||||
this.workHackExpGainRate = 0;
|
||||
this.workStrExpGainRate = 0;
|
||||
this.workDefExpGainRate = 0;
|
||||
this.workDexExpGainRate = 0;
|
||||
this.workAgiExpGainRate = 0;
|
||||
this.workChaExpGainRate = 0;
|
||||
this.workRepGainRate = 0;
|
||||
this.workMoneyGainRate = 0;
|
||||
this.workMoneyLossRate = 0;
|
||||
this.workHackExpGainRate = 0;
|
||||
this.workStrExpGainRate = 0;
|
||||
this.workDefExpGainRate = 0;
|
||||
this.workDexExpGainRate = 0;
|
||||
this.workAgiExpGainRate = 0;
|
||||
this.workChaExpGainRate = 0;
|
||||
this.workRepGainRate = 0;
|
||||
this.workMoneyGainRate = 0;
|
||||
this.workMoneyLossRate = 0;
|
||||
|
||||
this.workHackExpGained = 0;
|
||||
this.workStrExpGained = 0;
|
||||
this.workDefExpGained = 0;
|
||||
this.workDexExpGained = 0;
|
||||
this.workAgiExpGained = 0;
|
||||
this.workChaExpGained = 0;
|
||||
this.workRepGained = 0;
|
||||
this.workMoneyGained = 0;
|
||||
this.workHackExpGained = 0;
|
||||
this.workStrExpGained = 0;
|
||||
this.workDefExpGained = 0;
|
||||
this.workDexExpGained = 0;
|
||||
this.workAgiExpGained = 0;
|
||||
this.workChaExpGained = 0;
|
||||
this.workRepGained = 0;
|
||||
this.workMoneyGained = 0;
|
||||
|
||||
this.createProgramName = "";
|
||||
this.createProgramReqLvl = 0;
|
||||
this.createProgramName = "";
|
||||
this.createProgramReqLvl = 0;
|
||||
|
||||
this.className = "";
|
||||
this.className = "";
|
||||
|
||||
this.crimeType = "";
|
||||
this.crimeType = "";
|
||||
|
||||
this.timeWorked = 0; //in ms
|
||||
this.timeWorkedCreateProgram = 0;
|
||||
this.timeNeededToCompleteWork = 0;
|
||||
this.timeWorked = 0; //in ms
|
||||
this.timeWorkedCreateProgram = 0;
|
||||
this.timeNeededToCompleteWork = 0;
|
||||
|
||||
this.work_money_mult = 1;
|
||||
this.work_money_mult = 1;
|
||||
|
||||
//Hacknet Node multipliers
|
||||
this.hacknet_node_money_mult = 1;
|
||||
this.hacknet_node_purchase_cost_mult = 1;
|
||||
this.hacknet_node_ram_cost_mult = 1;
|
||||
this.hacknet_node_core_cost_mult = 1;
|
||||
this.hacknet_node_level_cost_mult = 1;
|
||||
//Hacknet Node multipliers
|
||||
this.hacknet_node_money_mult = 1;
|
||||
this.hacknet_node_purchase_cost_mult = 1;
|
||||
this.hacknet_node_ram_cost_mult = 1;
|
||||
this.hacknet_node_core_cost_mult = 1;
|
||||
this.hacknet_node_level_cost_mult = 1;
|
||||
|
||||
//Stock Market
|
||||
this.hasWseAccount = false;
|
||||
this.hasTixApiAccess = false;
|
||||
this.has4SData = false;
|
||||
this.has4SDataTixApi = false;
|
||||
//Stock Market
|
||||
this.hasWseAccount = false;
|
||||
this.hasTixApiAccess = false;
|
||||
this.has4SData = false;
|
||||
this.has4SDataTixApi = false;
|
||||
|
||||
//Gang
|
||||
this.gang = 0;
|
||||
//Gang
|
||||
this.gang = 0;
|
||||
|
||||
//Corporation
|
||||
this.corporation = 0;
|
||||
//Corporation
|
||||
this.corporation = 0;
|
||||
|
||||
//Bladeburner
|
||||
this.bladeburner = 0;
|
||||
this.bladeburner_max_stamina_mult = 1;
|
||||
this.bladeburner_stamina_gain_mult = 1;
|
||||
this.bladeburner_analysis_mult = 1; //Field Analysis Only
|
||||
this.bladeburner_success_chance_mult = 1;
|
||||
//Bladeburner
|
||||
this.bladeburner = 0;
|
||||
this.bladeburner_max_stamina_mult = 1;
|
||||
this.bladeburner_stamina_gain_mult = 1;
|
||||
this.bladeburner_analysis_mult = 1; //Field Analysis Only
|
||||
this.bladeburner_success_chance_mult = 1;
|
||||
|
||||
// Sleeves & Re-sleeving
|
||||
this.sleeves = [];
|
||||
this.resleeves = [];
|
||||
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant
|
||||
// Sleeves & Re-sleeving
|
||||
this.sleeves = [];
|
||||
this.resleeves = [];
|
||||
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant
|
||||
|
||||
//bitnode
|
||||
this.bitNodeN = 1;
|
||||
//bitnode
|
||||
this.bitNodeN = 1;
|
||||
|
||||
//Flags for determining whether certain "thresholds" have been achieved
|
||||
this.firstFacInvRecvd = false;
|
||||
this.firstAugPurchased = false;
|
||||
this.firstTimeTraveled = false;
|
||||
this.firstProgramAvailable = false;
|
||||
//Flags for determining whether certain "thresholds" have been achieved
|
||||
this.firstFacInvRecvd = false;
|
||||
this.firstAugPurchased = false;
|
||||
this.firstTimeTraveled = false;
|
||||
this.firstProgramAvailable = false;
|
||||
|
||||
//Used to store the last update time.
|
||||
this.lastUpdate = 0;
|
||||
this.totalPlaytime = 0;
|
||||
this.playtimeSinceLastAug = 0;
|
||||
this.playtimeSinceLastBitnode = 0;
|
||||
//Used to store the last update time.
|
||||
this.lastUpdate = 0;
|
||||
this.totalPlaytime = 0;
|
||||
this.playtimeSinceLastAug = 0;
|
||||
this.playtimeSinceLastBitnode = 0;
|
||||
|
||||
// Keep track of where money comes from
|
||||
this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation
|
||||
this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run
|
||||
// Keep track of where money comes from
|
||||
this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation
|
||||
this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run
|
||||
|
||||
// Production since last Augmentation installation
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
// Production since last Augmentation installation
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
|
||||
this.exploits = [];
|
||||
this.exploits = [];
|
||||
}
|
||||
|
||||
// Apply player methods to the prototype using Object.assign()
|
||||
Object.assign(
|
||||
PlayerObject.prototype,
|
||||
generalMethods,
|
||||
serverMethods,
|
||||
bladeburnerMethods,
|
||||
corporationMethods,
|
||||
gangMethods,
|
||||
augmentationMethods,
|
||||
PlayerObject.prototype,
|
||||
generalMethods,
|
||||
serverMethods,
|
||||
bladeburnerMethods,
|
||||
corporationMethods,
|
||||
gangMethods,
|
||||
augmentationMethods,
|
||||
);
|
||||
|
||||
PlayerObject.prototype.toJSON = function() {
|
||||
return Generic_toJSON("PlayerObject", this);
|
||||
}
|
||||
PlayerObject.prototype.toJSON = function () {
|
||||
return Generic_toJSON("PlayerObject", this);
|
||||
};
|
||||
|
||||
PlayerObject.fromJSON = function(value) {
|
||||
return Generic_fromJSON(PlayerObject, value.data);
|
||||
}
|
||||
PlayerObject.fromJSON = function (value) {
|
||||
return Generic_fromJSON(PlayerObject, value.data);
|
||||
};
|
||||
|
||||
Reviver.constructors.PlayerObject = PlayerObject;
|
||||
|
||||
@@ -5,16 +5,23 @@ import { IPlayer } from "../IPlayer";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
|
||||
export function hasAugmentation(this: IPlayer, aug: string | Augmentation): boolean {
|
||||
const augName: string = (aug instanceof Augmentation) ? aug.name : aug;
|
||||
export function hasAugmentation(
|
||||
this: IPlayer,
|
||||
aug: string | Augmentation,
|
||||
): boolean {
|
||||
const augName: string = aug instanceof Augmentation ? aug.name : aug;
|
||||
|
||||
for (const owned of this.augmentations) {
|
||||
if (owned.name === augName) { return true; }
|
||||
for (const owned of this.augmentations) {
|
||||
if (owned.name === augName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const owned of this.queuedAugmentations) {
|
||||
if (owned.name === augName) { return true; }
|
||||
for (const owned of this.queuedAugmentations) {
|
||||
if (owned.name === augName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,16 +2,25 @@ import { Bladeburner } from "../../Bladeburner/Bladeburner";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
export function canAccessBladeburner() {
|
||||
if (this.bitNodeN === 8) { return false; }
|
||||
|
||||
return (this.bitNodeN === 6) || (this.bitNodeN === 7) || (SourceFileFlags[6] > 0) || (SourceFileFlags[7] > 0);
|
||||
if (this.bitNodeN === 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
this.bitNodeN === 6 ||
|
||||
this.bitNodeN === 7 ||
|
||||
SourceFileFlags[6] > 0 ||
|
||||
SourceFileFlags[7] > 0
|
||||
);
|
||||
}
|
||||
|
||||
export function inBladeburner() {
|
||||
if (this.bladeburner == null) { return false; }
|
||||
return (this.bladeburner instanceof Bladeburner);
|
||||
if (this.bladeburner == null) {
|
||||
return false;
|
||||
}
|
||||
return this.bladeburner instanceof Bladeburner;
|
||||
}
|
||||
|
||||
export function startBladeburner() {
|
||||
this.bladeburner = new Bladeburner(this);
|
||||
this.bladeburner = new Bladeburner(this);
|
||||
}
|
||||
|
||||
@@ -2,18 +2,20 @@ import { Corporation } from "../../Corporation/Corporation";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
export function canAccessCorporation() {
|
||||
return this.bitNodeN === 3 || (SourceFileFlags[3] > 0);
|
||||
return this.bitNodeN === 3 || SourceFileFlags[3] > 0;
|
||||
}
|
||||
|
||||
export function hasCorporation() {
|
||||
if (this.corporation == null) { return false; }
|
||||
return (this.corporation instanceof Corporation);
|
||||
if (this.corporation == null) {
|
||||
return false;
|
||||
}
|
||||
return this.corporation instanceof Corporation;
|
||||
}
|
||||
|
||||
export function startCorporation(corpName, additionalShares=0) {
|
||||
this.corporation = new Corporation({
|
||||
name: corpName,
|
||||
});
|
||||
export function startCorporation(corpName, additionalShares = 0) {
|
||||
this.corporation = new Corporation({
|
||||
name: corpName,
|
||||
});
|
||||
|
||||
this.corporation.totalShares += additionalShares;
|
||||
this.corporation.totalShares += additionalShares;
|
||||
}
|
||||
|
||||
@@ -7,41 +7,49 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
const GangKarmaRequirement = -54000;
|
||||
|
||||
export function canAccessGang() {
|
||||
if (this.bitNodeN === 2) { return true; }
|
||||
if (SourceFileFlags[2] <= 0) { return false; }
|
||||
if (this.bitNodeN === 2) {
|
||||
return true;
|
||||
}
|
||||
if (SourceFileFlags[2] <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (this.karma <= BitNodeMultipliers.GangKarmaRequirement*GangKarmaRequirement);
|
||||
return (
|
||||
this.karma <= BitNodeMultipliers.GangKarmaRequirement * GangKarmaRequirement
|
||||
);
|
||||
}
|
||||
|
||||
export function getGangFaction() {
|
||||
const fac = Factions[this.gang.facName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Gang has invalid faction name: ${this.gang.facName}`);
|
||||
}
|
||||
const fac = Factions[this.gang.facName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Gang has invalid faction name: ${this.gang.facName}`);
|
||||
}
|
||||
|
||||
return fac;
|
||||
return fac;
|
||||
}
|
||||
|
||||
export function getGangName() {
|
||||
return this.inGang() ? this.gang.facName : "";
|
||||
return this.inGang() ? this.gang.facName : "";
|
||||
}
|
||||
|
||||
export function hasGangWith(facName) {
|
||||
return this.inGang() && this.gang.facName === facName;
|
||||
return this.inGang() && this.gang.facName === facName;
|
||||
}
|
||||
|
||||
export function inGang() {
|
||||
if (this.gang == null || this.gang == undefined) { return false; }
|
||||
if (this.gang == null || this.gang == undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (this.gang instanceof Gang);
|
||||
return this.gang instanceof Gang;
|
||||
}
|
||||
|
||||
export function startGang(factionName, hacking) {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
|
||||
const fac = Factions[factionName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Invalid faction name when creating gang: ${factionName}`);
|
||||
}
|
||||
fac.playerReputation = 0;
|
||||
const fac = Factions[factionName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Invalid faction name when creating gang: ${factionName}`);
|
||||
}
|
||||
fac.playerReputation = 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,52 +9,56 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import {
|
||||
AddToAllServers,
|
||||
AllServers,
|
||||
createUniqueRandomIp,
|
||||
AddToAllServers,
|
||||
AllServers,
|
||||
createUniqueRandomIp,
|
||||
} from "../../Server/AllServers";
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
|
||||
export function hasTorRouter(this: IPlayer): boolean {
|
||||
return SpecialServerIps.hasOwnProperty("Darkweb Server");
|
||||
return SpecialServerIps.hasOwnProperty("Darkweb Server");
|
||||
}
|
||||
|
||||
export function getCurrentServer(this: IPlayer): Server | HacknetServer | null {
|
||||
return AllServers[this.currentServer];
|
||||
return AllServers[this.currentServer];
|
||||
}
|
||||
|
||||
export function getHomeComputer(this: IPlayer): Server | HacknetServer | null {
|
||||
return AllServers[this.homeComputer];
|
||||
return AllServers[this.homeComputer];
|
||||
}
|
||||
|
||||
export function getUpgradeHomeRamCost(this: IPlayer): number {
|
||||
//Calculate how many times ram has been upgraded (doubled)
|
||||
const currentRam = this.getHomeComputer().maxRam;
|
||||
const numUpgrades = Math.log2(currentRam);
|
||||
//Calculate how many times ram has been upgraded (doubled)
|
||||
const currentRam = this.getHomeComputer().maxRam;
|
||||
const numUpgrades = Math.log2(currentRam);
|
||||
|
||||
//Calculate cost
|
||||
//Have cost increase by some percentage each time RAM has been upgraded
|
||||
const mult = Math.pow(1.58, numUpgrades);
|
||||
const cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost;
|
||||
return cost;
|
||||
//Calculate cost
|
||||
//Have cost increase by some percentage each time RAM has been upgraded
|
||||
const mult = Math.pow(1.58, numUpgrades);
|
||||
const cost =
|
||||
currentRam *
|
||||
CONSTANTS.BaseCostFor1GBOfRamHome *
|
||||
mult *
|
||||
BitNodeMultipliers.HomeComputerRamCost;
|
||||
return cost;
|
||||
}
|
||||
|
||||
export function createHacknetServer(this: IPlayer): HacknetServer {
|
||||
const numOwned = this.hacknetNodes.length;
|
||||
const name = `hacknet-node-${numOwned}`;
|
||||
const server = new HacknetServer({
|
||||
adminRights: true,
|
||||
hostname: name,
|
||||
ip: createUniqueRandomIp(),
|
||||
// player: this,
|
||||
});
|
||||
this.hacknetNodes.push(server.ip);
|
||||
const numOwned = this.hacknetNodes.length;
|
||||
const name = `hacknet-node-${numOwned}`;
|
||||
const server = new HacknetServer({
|
||||
adminRights: true,
|
||||
hostname: name,
|
||||
ip: createUniqueRandomIp(),
|
||||
// player: this,
|
||||
});
|
||||
this.hacknetNodes.push(server.ip);
|
||||
|
||||
// Configure the HacknetServer to actually act as a Server
|
||||
AddToAllServers(server);
|
||||
const homeComputer = this.getHomeComputer();
|
||||
homeComputer.serversOnNetwork.push(server.ip);
|
||||
server.serversOnNetwork.push(homeComputer.ip);
|
||||
// Configure the HacknetServer to actually act as a Server
|
||||
AddToAllServers(server);
|
||||
const homeComputer = this.getHomeComputer();
|
||||
homeComputer.serversOnNetwork.push(server.ip);
|
||||
server.serversOnNetwork.push(homeComputer.ip);
|
||||
|
||||
return server;
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -7,57 +7,68 @@ import { Person } from "../Person";
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
|
||||
import {
|
||||
Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver,
|
||||
} from "../../../utils/JSONReviver";
|
||||
|
||||
export class Resleeve extends Person {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
getCost(): number {
|
||||
// Each experience point adds this to the cost
|
||||
const CostPerExp = 25e3;
|
||||
|
||||
// Final cost is multiplied by this constant ^ # Augs
|
||||
const NumAugsExponent = 1.2;
|
||||
|
||||
// Get total exp in this re-sleeve
|
||||
const totalExp: number =
|
||||
this.hacking_exp +
|
||||
this.strength_exp +
|
||||
this.defense_exp +
|
||||
this.dexterity_exp +
|
||||
this.agility_exp +
|
||||
this.charisma_exp;
|
||||
|
||||
// Get total base Augmentation cost for this re-sleeve
|
||||
let totalAugmentationCost = 0;
|
||||
for (let i = 0; i < this.augmentations.length; ++i) {
|
||||
const aug: Augmentation | null =
|
||||
Augmentations[this.augmentations[i].name];
|
||||
if (aug == null) {
|
||||
console.error(
|
||||
`Could not find Augmentation ${this.augmentations[i].name}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
totalAugmentationCost += aug.startingCost;
|
||||
}
|
||||
|
||||
getCost(): number {
|
||||
// Each experience point adds this to the cost
|
||||
const CostPerExp = 25e3;
|
||||
return (
|
||||
totalExp * CostPerExp +
|
||||
totalAugmentationCost *
|
||||
Math.pow(NumAugsExponent, this.augmentations.length)
|
||||
);
|
||||
}
|
||||
|
||||
// Final cost is multiplied by this constant ^ # Augs
|
||||
const NumAugsExponent = 1.2;
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Resleeve", this);
|
||||
}
|
||||
|
||||
// Get total exp in this re-sleeve
|
||||
const totalExp: number = this.hacking_exp +
|
||||
this.strength_exp +
|
||||
this.defense_exp +
|
||||
this.dexterity_exp +
|
||||
this.agility_exp +
|
||||
this.charisma_exp;
|
||||
|
||||
// Get total base Augmentation cost for this re-sleeve
|
||||
let totalAugmentationCost = 0;
|
||||
for (let i = 0; i < this.augmentations.length; ++i) {
|
||||
const aug: Augmentation | null = Augmentations[this.augmentations[i].name];
|
||||
if (aug == null) {
|
||||
console.error(`Could not find Augmentation ${this.augmentations[i].name}`);
|
||||
continue;
|
||||
}
|
||||
totalAugmentationCost += aug.startingCost;
|
||||
}
|
||||
|
||||
return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(NumAugsExponent, this.augmentations.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Resleeve", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiatizes a Resleeve object from a JSON save state.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): Resleeve {
|
||||
return Generic_fromJSON(Resleeve, value.data);
|
||||
}
|
||||
/**
|
||||
* Initiatizes a Resleeve object from a JSON save state.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): Resleeve {
|
||||
return Generic_fromJSON(Resleeve, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.Resleeve = Resleeve;
|
||||
|
||||
@@ -15,110 +15,120 @@ import { IPlayer } from "../IPlayer";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { IPlayerOwnedAugmentation,
|
||||
PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
|
||||
import {
|
||||
IPlayerOwnedAugmentation,
|
||||
PlayerOwnedAugmentation,
|
||||
} from "../../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
|
||||
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
|
||||
|
||||
|
||||
// Executes the actual re-sleeve when one is purchased
|
||||
export function purchaseResleeve(r: Resleeve, p: IPlayer): boolean {
|
||||
const cost: number = r.getCost();
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
const cost: number = r.getCost();
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
p.loseMoney(cost);
|
||||
|
||||
// Set the player's exp
|
||||
p.hacking_exp = r.hacking_exp;
|
||||
p.strength_exp = r.strength_exp;
|
||||
p.defense_exp = r.defense_exp;
|
||||
p.dexterity_exp = r.dexterity_exp;
|
||||
p.agility_exp = r.agility_exp;
|
||||
p.charisma_exp = r.charisma_exp;
|
||||
|
||||
// Reset Augmentation "owned" data
|
||||
for (const augKey in Augmentations) {
|
||||
Augmentations[augKey].owned = false;
|
||||
}
|
||||
|
||||
// Clear all of the player's augmentations, except the NeuroFlux Governor
|
||||
// which is kept
|
||||
for (let i = p.augmentations.length - 1; i >= 0; --i) {
|
||||
if (p.augmentations[i].name !== AugmentationNames.NeuroFluxGovernor) {
|
||||
p.augmentations.splice(i, 1);
|
||||
} else {
|
||||
// NeuroFlux Governor
|
||||
Augmentations[AugmentationNames.NeuroFluxGovernor].owned = true;
|
||||
}
|
||||
p.loseMoney(cost);
|
||||
}
|
||||
|
||||
// Set the player's exp
|
||||
p.hacking_exp = r.hacking_exp;
|
||||
p.strength_exp = r.strength_exp;
|
||||
p.defense_exp = r.defense_exp;
|
||||
p.dexterity_exp = r.dexterity_exp;
|
||||
p.agility_exp = r.agility_exp;
|
||||
p.charisma_exp = r.charisma_exp;
|
||||
for (let i = 0; i < r.augmentations.length; ++i) {
|
||||
p.augmentations.push(new PlayerOwnedAugmentation(r.augmentations[i].name));
|
||||
Augmentations[r.augmentations[i].name].owned = true;
|
||||
}
|
||||
|
||||
// Reset Augmentation "owned" data
|
||||
for (const augKey in Augmentations) {
|
||||
Augmentations[augKey].owned = false;
|
||||
// The player's purchased Augmentations should remain the same, but any purchased
|
||||
// Augmentations that are given by the resleeve should be removed so there are no duplicates
|
||||
for (let i = p.queuedAugmentations.length - 1; i >= 0; --i) {
|
||||
const name: string = p.queuedAugmentations[i].name;
|
||||
|
||||
if (
|
||||
p.augmentations.filter((e: IPlayerOwnedAugmentation) => {
|
||||
return (
|
||||
e.name !== AugmentationNames.NeuroFluxGovernor && e.name === name
|
||||
);
|
||||
}).length >= 1
|
||||
) {
|
||||
p.queuedAugmentations.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all of the player's augmentations, except the NeuroFlux Governor
|
||||
// which is kept
|
||||
for (let i = p.augmentations.length - 1; i >= 0; --i) {
|
||||
if (p.augmentations[i].name !== AugmentationNames.NeuroFluxGovernor) {
|
||||
p.augmentations.splice(i, 1);
|
||||
} else {
|
||||
// NeuroFlux Governor
|
||||
Augmentations[AugmentationNames.NeuroFluxGovernor].owned = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < r.augmentations.length; ++i) {
|
||||
p.augmentations.push(new PlayerOwnedAugmentation(r.augmentations[i].name));
|
||||
Augmentations[r.augmentations[i].name].owned = true;
|
||||
}
|
||||
|
||||
// The player's purchased Augmentations should remain the same, but any purchased
|
||||
// Augmentations that are given by the resleeve should be removed so there are no duplicates
|
||||
for (let i = p.queuedAugmentations.length - 1; i >= 0; --i) {
|
||||
const name: string = p.queuedAugmentations[i].name;
|
||||
|
||||
if (p.augmentations.filter((e: IPlayerOwnedAugmentation) => {return e.name !== AugmentationNames.NeuroFluxGovernor && e.name === name}).length >= 1) {
|
||||
p.queuedAugmentations.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
p.reapplyAllAugmentations(true);
|
||||
p.reapplyAllSourceFiles(); //Multipliers get reset, so have to re-process source files too
|
||||
return true;
|
||||
p.reapplyAllAugmentations(true);
|
||||
p.reapplyAllSourceFiles(); //Multipliers get reset, so have to re-process source files too
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates all of the Re-sleeves that will be available for purchase at VitaLife
|
||||
export function generateResleeves(): Resleeve[] {
|
||||
const NumResleeves = 40; // Total number of Resleeves to generate
|
||||
const NumResleeves = 40; // Total number of Resleeves to generate
|
||||
|
||||
const ret: Resleeve[] = [];
|
||||
for (let i = 0; i < NumResleeves; ++i) {
|
||||
// i will be a number indicating how "powerful" the Re-sleeve should be
|
||||
const r: Resleeve = new Resleeve();
|
||||
const ret: Resleeve[] = [];
|
||||
for (let i = 0; i < NumResleeves; ++i) {
|
||||
// i will be a number indicating how "powerful" the Re-sleeve should be
|
||||
const r: Resleeve = new Resleeve();
|
||||
|
||||
// Generate experience
|
||||
const expMult: number = (5 * i) + 1;
|
||||
r.hacking_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.strength_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.defense_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.dexterity_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.agility_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.charisma_exp = expMult * getRandomInt(1000, 5000);
|
||||
// Generate experience
|
||||
const expMult: number = 5 * i + 1;
|
||||
r.hacking_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.strength_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.defense_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.dexterity_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.agility_exp = expMult * getRandomInt(1000, 5000);
|
||||
r.charisma_exp = expMult * getRandomInt(1000, 5000);
|
||||
|
||||
// Generate Augs
|
||||
// Augmentation prequisites will be ignored for this
|
||||
const baseNumAugs: number = Math.max(2, Math.ceil((i + 3) / 2));
|
||||
const numAugs: number = getRandomInt(baseNumAugs, baseNumAugs + 2);
|
||||
const augKeys: string[] = Object.keys(Augmentations);
|
||||
for (let a = 0; a < numAugs; ++a) {
|
||||
// Get a random aug
|
||||
const randIndex: number = getRandomInt(0, augKeys.length - 1)
|
||||
const randKey: string = augKeys[randIndex];
|
||||
// Generate Augs
|
||||
// Augmentation prequisites will be ignored for this
|
||||
const baseNumAugs: number = Math.max(2, Math.ceil((i + 3) / 2));
|
||||
const numAugs: number = getRandomInt(baseNumAugs, baseNumAugs + 2);
|
||||
const augKeys: string[] = Object.keys(Augmentations);
|
||||
for (let a = 0; a < numAugs; ++a) {
|
||||
// Get a random aug
|
||||
const randIndex: number = getRandomInt(0, augKeys.length - 1);
|
||||
const randKey: string = augKeys[randIndex];
|
||||
|
||||
// Forbidden augmentations
|
||||
if (randKey === AugmentationNames.TheRedPill || randKey === AugmentationNames.NeuroFluxGovernor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const randAug: Augmentation | null = Augmentations[randKey];
|
||||
if(randAug === null) throw new Error(`null augmentation: ${randKey}`)
|
||||
r.augmentations.push({name: randAug.name, level: 1});
|
||||
r.applyAugmentation(Augmentations[randKey]);
|
||||
r.updateStatLevels();
|
||||
// Forbidden augmentations
|
||||
if (
|
||||
randKey === AugmentationNames.TheRedPill ||
|
||||
randKey === AugmentationNames.NeuroFluxGovernor
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove Augmentation so that there are no duplicates
|
||||
augKeys.splice(randIndex, 1);
|
||||
}
|
||||
const randAug: Augmentation | null = Augmentations[randKey];
|
||||
if (randAug === null) throw new Error(`null augmentation: ${randKey}`);
|
||||
r.augmentations.push({ name: randAug.name, level: 1 });
|
||||
r.applyAugmentation(Augmentations[randKey]);
|
||||
r.updateStatLevels();
|
||||
|
||||
ret.push(r);
|
||||
// Remove Augmentation so that there are no duplicates
|
||||
augKeys.splice(randIndex, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
ret.push(r);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
* Module for handling the Re-sleeving UI
|
||||
*/
|
||||
import { Resleeve } from "./Resleeve";
|
||||
import { generateResleeves,
|
||||
purchaseResleeve } from "./Resleeving";
|
||||
import { generateResleeves, purchaseResleeve } from "./Resleeving";
|
||||
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
@@ -12,8 +11,7 @@ import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Page,
|
||||
routing } from "../../ui/navigationTracking";
|
||||
import { Page, routing } from "../../ui/navigationTracking";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
@@ -26,353 +24,509 @@ import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildr
|
||||
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||
|
||||
import * as React from "react";
|
||||
import { renderToStaticMarkup } from "react-dom/server"
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
interface IResleeveUIElems {
|
||||
container: HTMLElement | null;
|
||||
statsPanel: HTMLElement | null;
|
||||
stats: HTMLElement | null;
|
||||
multipliersButton: HTMLElement | null;
|
||||
augPanel: HTMLElement | null;
|
||||
augSelector: HTMLSelectElement | null;
|
||||
augDescription: HTMLElement | null;
|
||||
costPanel: HTMLElement | null;
|
||||
costText: HTMLElement | null;
|
||||
buyButton: HTMLElement | null;
|
||||
container: HTMLElement | null;
|
||||
statsPanel: HTMLElement | null;
|
||||
stats: HTMLElement | null;
|
||||
multipliersButton: HTMLElement | null;
|
||||
augPanel: HTMLElement | null;
|
||||
augSelector: HTMLSelectElement | null;
|
||||
augDescription: HTMLElement | null;
|
||||
costPanel: HTMLElement | null;
|
||||
costText: HTMLElement | null;
|
||||
buyButton: HTMLElement | null;
|
||||
}
|
||||
|
||||
interface IPageUIElems {
|
||||
container: HTMLElement | null;
|
||||
info: HTMLElement | null;
|
||||
sortTag: HTMLElement | null;
|
||||
sortSelector: HTMLSelectElement | null;
|
||||
resleeveList: HTMLElement | null;
|
||||
resleeves: IResleeveUIElems[] | null;
|
||||
container: HTMLElement | null;
|
||||
info: HTMLElement | null;
|
||||
sortTag: HTMLElement | null;
|
||||
sortSelector: HTMLSelectElement | null;
|
||||
resleeveList: HTMLElement | null;
|
||||
resleeves: IResleeveUIElems[] | null;
|
||||
}
|
||||
|
||||
const UIElems: IPageUIElems = {
|
||||
container: null,
|
||||
info: null,
|
||||
sortTag: null,
|
||||
sortSelector: null,
|
||||
resleeveList: null,
|
||||
resleeves: null,
|
||||
}
|
||||
container: null,
|
||||
info: null,
|
||||
sortTag: null,
|
||||
sortSelector: null,
|
||||
resleeveList: null,
|
||||
resleeves: null,
|
||||
};
|
||||
|
||||
let playerRef: IPlayer | null;
|
||||
|
||||
export function createResleevesPage(p: IPlayer): void {
|
||||
if (!routing.isOn(Page.Resleeves)) { return; }
|
||||
if (!routing.isOn(Page.Resleeves)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
playerRef = p;
|
||||
try {
|
||||
playerRef = p;
|
||||
|
||||
UIElems.container = createElement("div", {
|
||||
class: "generic-menupage-container",
|
||||
id: "resleeves-container",
|
||||
position: "fixed",
|
||||
});
|
||||
UIElems.container = createElement("div", {
|
||||
class: "generic-menupage-container",
|
||||
id: "resleeves-container",
|
||||
position: "fixed",
|
||||
});
|
||||
|
||||
UIElems.info = createElement("p", {
|
||||
display: "block",
|
||||
innerHTML: "Re-sleeving is the process of digitizing and transferring your consciousness " +
|
||||
"into a new human body, or 'sleeve'. Here at VitaLife, you can purchase new " +
|
||||
"specially-engineered bodies for the re-sleeve process. Many of these bodies " +
|
||||
"even come with genetic and cybernetic Augmentations!<br /><br />" +
|
||||
"Re-sleeving will change your experience for every stat. It will also REMOVE " +
|
||||
"all of your currently-installed Augmentations, and replace " +
|
||||
"them with the ones provided by the purchased sleeve. However, Augmentations that you have " +
|
||||
"purchased but not installed will NOT be removed. If you have purchased an " +
|
||||
"Augmentation and then re-sleeve into a body which already has that Augmentation, " +
|
||||
"it will be removed (since you cannot have duplicate Augmentations).<br /><br />" +
|
||||
"NOTE: The stats and multipliers displayed on this page do NOT include your bonuses from " +
|
||||
"Source-File.",
|
||||
width: "75%",
|
||||
});
|
||||
UIElems.info = createElement("p", {
|
||||
display: "block",
|
||||
innerHTML:
|
||||
"Re-sleeving is the process of digitizing and transferring your consciousness " +
|
||||
"into a new human body, or 'sleeve'. Here at VitaLife, you can purchase new " +
|
||||
"specially-engineered bodies for the re-sleeve process. Many of these bodies " +
|
||||
"even come with genetic and cybernetic Augmentations!<br /><br />" +
|
||||
"Re-sleeving will change your experience for every stat. It will also REMOVE " +
|
||||
"all of your currently-installed Augmentations, and replace " +
|
||||
"them with the ones provided by the purchased sleeve. However, Augmentations that you have " +
|
||||
"purchased but not installed will NOT be removed. If you have purchased an " +
|
||||
"Augmentation and then re-sleeve into a body which already has that Augmentation, " +
|
||||
"it will be removed (since you cannot have duplicate Augmentations).<br /><br />" +
|
||||
"NOTE: The stats and multipliers displayed on this page do NOT include your bonuses from " +
|
||||
"Source-File.",
|
||||
width: "75%",
|
||||
});
|
||||
|
||||
// Randomly create all Resleeves if they dont already exist
|
||||
if (p.resleeves.length === 0) {
|
||||
p.resleeves = generateResleeves();
|
||||
}
|
||||
|
||||
// Create a selector for sorting the list of Resleeves
|
||||
UIElems.sortTag = createElement("p", {
|
||||
display: "inline-block",
|
||||
innerText: "Sort By: ",
|
||||
});
|
||||
UIElems.sortSelector = createElement("select", { class: "dropdown" }) as HTMLSelectElement;
|
||||
|
||||
enum SortOption {
|
||||
Cost = "Cost",
|
||||
Hacking = "Hacking",
|
||||
Strength = "Strength",
|
||||
Defense = "Defense",
|
||||
Dexterity = "Dexterity",
|
||||
Agility = "Agility",
|
||||
Charisma = "Charisma",
|
||||
AverageCombatStats = "AverageCombat",
|
||||
AverageAllStats = "AverageAllStats",
|
||||
TotalNumAugmentations = "TotalNumAugmentations",
|
||||
}
|
||||
|
||||
UIElems.sortSelector.add(createOptionElement("Cost", SortOption.Cost));
|
||||
UIElems.sortSelector.add(createOptionElement("Hacking Level", SortOption.Hacking));
|
||||
UIElems.sortSelector.add(createOptionElement("Strength Level", SortOption.Strength));
|
||||
UIElems.sortSelector.add(createOptionElement("Defense Level", SortOption.Defense));
|
||||
UIElems.sortSelector.add(createOptionElement("Dexterity Level", SortOption.Dexterity));
|
||||
UIElems.sortSelector.add(createOptionElement("Agility Level", SortOption.Agility));
|
||||
UIElems.sortSelector.add(createOptionElement("Charisma Level", SortOption.Charisma));
|
||||
UIElems.sortSelector.add(createOptionElement("Average Combat Stats", SortOption.AverageCombatStats));
|
||||
UIElems.sortSelector.add(createOptionElement("Average Stats", SortOption.AverageAllStats));
|
||||
UIElems.sortSelector.add(createOptionElement("Number of Augmentations", SortOption.TotalNumAugmentations));
|
||||
|
||||
UIElems.resleeveList = createElement("ul");
|
||||
UIElems.sortSelector.onchange = () => {
|
||||
removeChildrenFromElement(UIElems.resleeveList);
|
||||
UIElems.resleeves = [];
|
||||
|
||||
// Helper function for averaging
|
||||
function getAverage(...values: number[]): number {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
sum += values[i];
|
||||
}
|
||||
|
||||
return sum / values.length;
|
||||
}
|
||||
|
||||
const sortOpt = getSelectValue(UIElems.sortSelector);
|
||||
switch (sortOpt) {
|
||||
case SortOption.Hacking:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.hacking_skill - b.hacking_skill;
|
||||
});
|
||||
break;
|
||||
case SortOption.Strength:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.strength - b.strength;
|
||||
});
|
||||
break;
|
||||
case SortOption.Defense:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.defense - b.defense;
|
||||
});
|
||||
break;
|
||||
case SortOption.Dexterity:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.dexterity - b.dexterity;
|
||||
});
|
||||
break;
|
||||
case SortOption.Agility:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.agility - b.agility;
|
||||
});
|
||||
break;
|
||||
case SortOption.Charisma:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.charisma - b.charisma;
|
||||
});
|
||||
break;
|
||||
case SortOption.AverageCombatStats:
|
||||
p.resleeves.sort((a, b) => {
|
||||
const aAvg = getAverage(a.strength, a.defense, a.dexterity, a.agility);
|
||||
const bAvg = getAverage(b.strength, b.defense, b.dexterity, b.agility);
|
||||
|
||||
return aAvg - bAvg;
|
||||
});
|
||||
break;
|
||||
case SortOption.AverageAllStats:
|
||||
p.resleeves.sort((a, b) => {
|
||||
const aAvg = getAverage(a.hacking_skill, a.strength, a.defense, a.dexterity, a.agility, a.charisma);
|
||||
const bAvg = getAverage(b.hacking_skill, b.strength, b.defense, b.dexterity, b.agility, b.charisma);
|
||||
|
||||
return aAvg - bAvg;
|
||||
});
|
||||
break;
|
||||
case SortOption.TotalNumAugmentations:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.augmentations.length - b.augmentations.length;
|
||||
});
|
||||
break;
|
||||
case SortOption.Cost:
|
||||
default:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.getCost() - b.getCost();
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if(UIElems.resleeveList == null) throw new Error("UIElems.resleeveList is null in sortSelector.click()");
|
||||
if(UIElems.resleeves == null) throw new Error("UIElems.resleeves is null in sortSelector.click()");
|
||||
|
||||
// Create UI for all Resleeves
|
||||
for (const resleeve of p.resleeves) {
|
||||
const resleeveUi = createResleeveUi(resleeve);
|
||||
if(resleeveUi.container == null) throw new Error("resleeveUi.container is null in sortSelector.click()");
|
||||
UIElems.resleeveList.appendChild(resleeveUi.container);
|
||||
UIElems.resleeves.push(resleeveUi);
|
||||
}
|
||||
}
|
||||
UIElems.sortSelector.dispatchEvent(new Event('change')); // Force onchange event
|
||||
|
||||
UIElems.container.appendChild(UIElems.info);
|
||||
UIElems.container.appendChild(createElement("br"));
|
||||
UIElems.container.appendChild(UIElems.sortTag);
|
||||
UIElems.container.appendChild(UIElems.sortSelector);
|
||||
UIElems.container.appendChild(UIElems.resleeveList);
|
||||
|
||||
const container = document.getElementById("entire-game-container");
|
||||
if(container == null) throw new Error("Could not find entire-game-container in createResleevesPage()");
|
||||
container.appendChild(UIElems.container);
|
||||
} catch(e) {
|
||||
exceptionAlert(e);
|
||||
// Randomly create all Resleeves if they dont already exist
|
||||
if (p.resleeves.length === 0) {
|
||||
p.resleeves = generateResleeves();
|
||||
}
|
||||
|
||||
// Create a selector for sorting the list of Resleeves
|
||||
UIElems.sortTag = createElement("p", {
|
||||
display: "inline-block",
|
||||
innerText: "Sort By: ",
|
||||
});
|
||||
UIElems.sortSelector = createElement("select", {
|
||||
class: "dropdown",
|
||||
}) as HTMLSelectElement;
|
||||
|
||||
enum SortOption {
|
||||
Cost = "Cost",
|
||||
Hacking = "Hacking",
|
||||
Strength = "Strength",
|
||||
Defense = "Defense",
|
||||
Dexterity = "Dexterity",
|
||||
Agility = "Agility",
|
||||
Charisma = "Charisma",
|
||||
AverageCombatStats = "AverageCombat",
|
||||
AverageAllStats = "AverageAllStats",
|
||||
TotalNumAugmentations = "TotalNumAugmentations",
|
||||
}
|
||||
|
||||
UIElems.sortSelector.add(createOptionElement("Cost", SortOption.Cost));
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Hacking Level", SortOption.Hacking),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Strength Level", SortOption.Strength),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Defense Level", SortOption.Defense),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Dexterity Level", SortOption.Dexterity),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Agility Level", SortOption.Agility),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Charisma Level", SortOption.Charisma),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement(
|
||||
"Average Combat Stats",
|
||||
SortOption.AverageCombatStats,
|
||||
),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement("Average Stats", SortOption.AverageAllStats),
|
||||
);
|
||||
UIElems.sortSelector.add(
|
||||
createOptionElement(
|
||||
"Number of Augmentations",
|
||||
SortOption.TotalNumAugmentations,
|
||||
),
|
||||
);
|
||||
|
||||
UIElems.resleeveList = createElement("ul");
|
||||
UIElems.sortSelector.onchange = () => {
|
||||
removeChildrenFromElement(UIElems.resleeveList);
|
||||
UIElems.resleeves = [];
|
||||
|
||||
// Helper function for averaging
|
||||
function getAverage(...values: number[]): number {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
sum += values[i];
|
||||
}
|
||||
|
||||
return sum / values.length;
|
||||
}
|
||||
|
||||
const sortOpt = getSelectValue(UIElems.sortSelector);
|
||||
switch (sortOpt) {
|
||||
case SortOption.Hacking:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.hacking_skill - b.hacking_skill;
|
||||
});
|
||||
break;
|
||||
case SortOption.Strength:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.strength - b.strength;
|
||||
});
|
||||
break;
|
||||
case SortOption.Defense:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.defense - b.defense;
|
||||
});
|
||||
break;
|
||||
case SortOption.Dexterity:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.dexterity - b.dexterity;
|
||||
});
|
||||
break;
|
||||
case SortOption.Agility:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.agility - b.agility;
|
||||
});
|
||||
break;
|
||||
case SortOption.Charisma:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.charisma - b.charisma;
|
||||
});
|
||||
break;
|
||||
case SortOption.AverageCombatStats:
|
||||
p.resleeves.sort((a, b) => {
|
||||
const aAvg = getAverage(
|
||||
a.strength,
|
||||
a.defense,
|
||||
a.dexterity,
|
||||
a.agility,
|
||||
);
|
||||
const bAvg = getAverage(
|
||||
b.strength,
|
||||
b.defense,
|
||||
b.dexterity,
|
||||
b.agility,
|
||||
);
|
||||
|
||||
return aAvg - bAvg;
|
||||
});
|
||||
break;
|
||||
case SortOption.AverageAllStats:
|
||||
p.resleeves.sort((a, b) => {
|
||||
const aAvg = getAverage(
|
||||
a.hacking_skill,
|
||||
a.strength,
|
||||
a.defense,
|
||||
a.dexterity,
|
||||
a.agility,
|
||||
a.charisma,
|
||||
);
|
||||
const bAvg = getAverage(
|
||||
b.hacking_skill,
|
||||
b.strength,
|
||||
b.defense,
|
||||
b.dexterity,
|
||||
b.agility,
|
||||
b.charisma,
|
||||
);
|
||||
|
||||
return aAvg - bAvg;
|
||||
});
|
||||
break;
|
||||
case SortOption.TotalNumAugmentations:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.augmentations.length - b.augmentations.length;
|
||||
});
|
||||
break;
|
||||
case SortOption.Cost:
|
||||
default:
|
||||
p.resleeves.sort((a, b) => {
|
||||
return a.getCost() - b.getCost();
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (UIElems.resleeveList == null)
|
||||
throw new Error("UIElems.resleeveList is null in sortSelector.click()");
|
||||
if (UIElems.resleeves == null)
|
||||
throw new Error("UIElems.resleeves is null in sortSelector.click()");
|
||||
|
||||
// Create UI for all Resleeves
|
||||
for (const resleeve of p.resleeves) {
|
||||
const resleeveUi = createResleeveUi(resleeve);
|
||||
if (resleeveUi.container == null)
|
||||
throw new Error(
|
||||
"resleeveUi.container is null in sortSelector.click()",
|
||||
);
|
||||
UIElems.resleeveList.appendChild(resleeveUi.container);
|
||||
UIElems.resleeves.push(resleeveUi);
|
||||
}
|
||||
};
|
||||
UIElems.sortSelector.dispatchEvent(new Event("change")); // Force onchange event
|
||||
|
||||
UIElems.container.appendChild(UIElems.info);
|
||||
UIElems.container.appendChild(createElement("br"));
|
||||
UIElems.container.appendChild(UIElems.sortTag);
|
||||
UIElems.container.appendChild(UIElems.sortSelector);
|
||||
UIElems.container.appendChild(UIElems.resleeveList);
|
||||
|
||||
const container = document.getElementById("entire-game-container");
|
||||
if (container == null)
|
||||
throw new Error(
|
||||
"Could not find entire-game-container in createResleevesPage()",
|
||||
);
|
||||
container.appendChild(UIElems.container);
|
||||
} catch (e) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
}
|
||||
|
||||
export function clearResleevesPage(): void {
|
||||
if (UIElems.container instanceof HTMLElement) {
|
||||
removeElement(UIElems.container);
|
||||
}
|
||||
if (UIElems.container instanceof HTMLElement) {
|
||||
removeElement(UIElems.container);
|
||||
}
|
||||
|
||||
for (const prop in UIElems) {
|
||||
(UIElems as any)[prop] = null;
|
||||
}
|
||||
for (const prop in UIElems) {
|
||||
(UIElems as any)[prop] = null;
|
||||
}
|
||||
|
||||
playerRef = null;
|
||||
playerRef = null;
|
||||
}
|
||||
|
||||
function createResleeveUi(resleeve: Resleeve): IResleeveUIElems {
|
||||
const elems: IResleeveUIElems = {
|
||||
container: null,
|
||||
statsPanel: null,
|
||||
stats: null,
|
||||
multipliersButton: null,
|
||||
augPanel: null,
|
||||
augSelector: null,
|
||||
augDescription: null,
|
||||
costPanel: null,
|
||||
costText: null,
|
||||
buyButton: null,
|
||||
};
|
||||
if(playerRef === null) return elems;
|
||||
|
||||
if (!routing.isOn(Page.Resleeves)) { return elems; }
|
||||
|
||||
elems.container = createElement("div", {
|
||||
class: "resleeve-container",
|
||||
display: "block",
|
||||
});
|
||||
|
||||
elems.statsPanel = createElement("div", { class: "resleeve-panel", width: "30%" });
|
||||
elems.stats = createElement("p", {
|
||||
class: "resleeve-stats-text",
|
||||
innerHTML:
|
||||
`Hacking: ${numeralWrapper.formatSkill(resleeve.hacking_skill)} (${numeralWrapper.formatExp(resleeve.hacking_exp)} exp)<br />` +
|
||||
`Strength: ${numeralWrapper.formatSkill(resleeve.strength)} (${numeralWrapper.formatExp(resleeve.strength_exp)} exp)<br />` +
|
||||
`Defense: ${numeralWrapper.formatSkill(resleeve.defense)} (${numeralWrapper.formatExp(resleeve.defense_exp)} exp)<br />` +
|
||||
`Dexterity: ${numeralWrapper.formatSkill(resleeve.dexterity)} (${numeralWrapper.formatExp(resleeve.dexterity_exp)} exp)<br />` +
|
||||
`Agility: ${numeralWrapper.formatSkill(resleeve.agility)} (${numeralWrapper.formatExp(resleeve.agility_exp)} exp)<br />` +
|
||||
`Charisma: ${numeralWrapper.formatSkill(resleeve.charisma)} (${numeralWrapper.formatExp(resleeve.charisma_exp)} exp)<br />` +
|
||||
`# Augmentations: ${resleeve.augmentations.length}`,
|
||||
});
|
||||
elems.multipliersButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Multipliers",
|
||||
clickListener: () => {
|
||||
dialogBoxCreate(
|
||||
[
|
||||
"<h2><u>Total Multipliers:</u></h2>",
|
||||
`Hacking Level multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_mult)}`,
|
||||
`Hacking Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_exp_mult)}`,
|
||||
`Strength Level multiplier: ${numeralWrapper.formatPercentage(resleeve.strength_mult)}`,
|
||||
`Strength Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.strength_exp_mult)}`,
|
||||
`Defense Level multiplier: ${numeralWrapper.formatPercentage(resleeve.defense_mult)}`,
|
||||
`Defense Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.defense_exp_mult)}`,
|
||||
`Dexterity Level multiplier: ${numeralWrapper.formatPercentage(resleeve.dexterity_mult)}`,
|
||||
`Dexterity Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.dexterity_exp_mult)}`,
|
||||
`Agility Level multiplier: ${numeralWrapper.formatPercentage(resleeve.agility_mult)}`,
|
||||
`Agility Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.agility_exp_mult)}`,
|
||||
`Charisma Level multiplier: ${numeralWrapper.formatPercentage(resleeve.charisma_mult)}`,
|
||||
`Charisma Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.charisma_exp_mult)}`,
|
||||
`Hacking Chance multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_chance_mult)}`,
|
||||
`Hacking Speed multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_speed_mult)}`,
|
||||
`Hacking Money multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_money_mult)}`,
|
||||
`Hacking Growth multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_grow_mult)}`,
|
||||
`Salary multiplier: ${numeralWrapper.formatPercentage(resleeve.work_money_mult)}`,
|
||||
`Company Reputation Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.company_rep_mult)}`,
|
||||
`Faction Reputation Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.faction_rep_mult)}`,
|
||||
`Crime Money multiplier: ${numeralWrapper.formatPercentage(resleeve.crime_money_mult)}`,
|
||||
`Crime Success multiplier: ${numeralWrapper.formatPercentage(resleeve.crime_success_mult)}`,
|
||||
`Hacknet Income multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_money_mult)}`,
|
||||
`Hacknet Purchase Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_purchase_cost_mult)}`,
|
||||
`Hacknet Level Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_level_cost_mult)}`,
|
||||
`Hacknet Ram Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_ram_cost_mult)}`,
|
||||
`Hacknet Core Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_core_cost_mult)}`,
|
||||
`Bladeburner Max Stamina multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_max_stamina_mult)}`,
|
||||
`Bladeburner Stamina Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_stamina_gain_mult)}`,
|
||||
`Bladeburner Field Analysis multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_analysis_mult)}`,
|
||||
`Bladeburner Success Chance multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_success_chance_mult)}`,
|
||||
].join("<br />"), false,
|
||||
)
|
||||
},
|
||||
});
|
||||
elems.statsPanel.appendChild(elems.stats);
|
||||
elems.statsPanel.appendChild(elems.multipliersButton);
|
||||
|
||||
elems.augPanel = createElement("div", { class: "resleeve-panel", width: "50%" });
|
||||
elems.augSelector = createElement("select", { class: "resleeve-aug-selector dropdown" }) as HTMLSelectElement;
|
||||
elems.augDescription = createElement("p");
|
||||
for (let i = 0; i < resleeve.augmentations.length; ++i) {
|
||||
elems.augSelector.add(createOptionElement(resleeve.augmentations[i].name));
|
||||
}
|
||||
elems.augSelector.addEventListener("change", () => {
|
||||
updateAugDescription(elems);
|
||||
});
|
||||
elems.augSelector.dispatchEvent(new Event('change')); // Set inital description by manually triggering change event
|
||||
elems.augPanel.appendChild(elems.augSelector);
|
||||
elems.augPanel.appendChild(elems.augDescription);
|
||||
|
||||
const cost: number = resleeve.getCost();
|
||||
elems.costPanel = createElement("div", { class: "resleeve-panel", width: "20%" });
|
||||
elems.costText = createElement("p", {
|
||||
innerHTML: `It costs ${renderToStaticMarkup(<Money money={cost} player={playerRef} />)} ` +
|
||||
`to purchase this Sleeve.`,
|
||||
});
|
||||
elems.buyButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Purchase",
|
||||
clickListener: () => {
|
||||
if(playerRef == null) throw new Error("playerRef is null in buyButton.click()");
|
||||
if (purchaseResleeve(resleeve, playerRef)) {
|
||||
dialogBoxCreate((<>You re-sleeved for <Money money={cost} />!</>), false);
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford to re-sleeve into this body`, false);
|
||||
}
|
||||
},
|
||||
});
|
||||
elems.costPanel.appendChild(elems.costText);
|
||||
elems.costPanel.appendChild(elems.buyButton);
|
||||
|
||||
elems.container.appendChild(elems.statsPanel);
|
||||
elems.container.appendChild(elems.augPanel);
|
||||
elems.container.appendChild(elems.costPanel);
|
||||
const elems: IResleeveUIElems = {
|
||||
container: null,
|
||||
statsPanel: null,
|
||||
stats: null,
|
||||
multipliersButton: null,
|
||||
augPanel: null,
|
||||
augSelector: null,
|
||||
augDescription: null,
|
||||
costPanel: null,
|
||||
costText: null,
|
||||
buyButton: null,
|
||||
};
|
||||
if (playerRef === null) return elems;
|
||||
|
||||
if (!routing.isOn(Page.Resleeves)) {
|
||||
return elems;
|
||||
}
|
||||
|
||||
elems.container = createElement("div", {
|
||||
class: "resleeve-container",
|
||||
display: "block",
|
||||
});
|
||||
|
||||
elems.statsPanel = createElement("div", {
|
||||
class: "resleeve-panel",
|
||||
width: "30%",
|
||||
});
|
||||
elems.stats = createElement("p", {
|
||||
class: "resleeve-stats-text",
|
||||
innerHTML:
|
||||
`Hacking: ${numeralWrapper.formatSkill(
|
||||
resleeve.hacking_skill,
|
||||
)} (${numeralWrapper.formatExp(resleeve.hacking_exp)} exp)<br />` +
|
||||
`Strength: ${numeralWrapper.formatSkill(
|
||||
resleeve.strength,
|
||||
)} (${numeralWrapper.formatExp(resleeve.strength_exp)} exp)<br />` +
|
||||
`Defense: ${numeralWrapper.formatSkill(
|
||||
resleeve.defense,
|
||||
)} (${numeralWrapper.formatExp(resleeve.defense_exp)} exp)<br />` +
|
||||
`Dexterity: ${numeralWrapper.formatSkill(
|
||||
resleeve.dexterity,
|
||||
)} (${numeralWrapper.formatExp(resleeve.dexterity_exp)} exp)<br />` +
|
||||
`Agility: ${numeralWrapper.formatSkill(
|
||||
resleeve.agility,
|
||||
)} (${numeralWrapper.formatExp(resleeve.agility_exp)} exp)<br />` +
|
||||
`Charisma: ${numeralWrapper.formatSkill(
|
||||
resleeve.charisma,
|
||||
)} (${numeralWrapper.formatExp(resleeve.charisma_exp)} exp)<br />` +
|
||||
`# Augmentations: ${resleeve.augmentations.length}`,
|
||||
});
|
||||
elems.multipliersButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Multipliers",
|
||||
clickListener: () => {
|
||||
dialogBoxCreate(
|
||||
[
|
||||
"<h2><u>Total Multipliers:</u></h2>",
|
||||
`Hacking Level multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacking_mult,
|
||||
)}`,
|
||||
`Hacking Experience multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacking_exp_mult,
|
||||
)}`,
|
||||
`Strength Level multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.strength_mult,
|
||||
)}`,
|
||||
`Strength Experience multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.strength_exp_mult,
|
||||
)}`,
|
||||
`Defense Level multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.defense_mult,
|
||||
)}`,
|
||||
`Defense Experience multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.defense_exp_mult,
|
||||
)}`,
|
||||
`Dexterity Level multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.dexterity_mult,
|
||||
)}`,
|
||||
`Dexterity Experience multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.dexterity_exp_mult,
|
||||
)}`,
|
||||
`Agility Level multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.agility_mult,
|
||||
)}`,
|
||||
`Agility Experience multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.agility_exp_mult,
|
||||
)}`,
|
||||
`Charisma Level multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.charisma_mult,
|
||||
)}`,
|
||||
`Charisma Experience multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.charisma_exp_mult,
|
||||
)}`,
|
||||
`Hacking Chance multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacking_chance_mult,
|
||||
)}`,
|
||||
`Hacking Speed multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacking_speed_mult,
|
||||
)}`,
|
||||
`Hacking Money multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacking_money_mult,
|
||||
)}`,
|
||||
`Hacking Growth multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacking_grow_mult,
|
||||
)}`,
|
||||
`Salary multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.work_money_mult,
|
||||
)}`,
|
||||
`Company Reputation Gain multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.company_rep_mult,
|
||||
)}`,
|
||||
`Faction Reputation Gain multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.faction_rep_mult,
|
||||
)}`,
|
||||
`Crime Money multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.crime_money_mult,
|
||||
)}`,
|
||||
`Crime Success multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.crime_success_mult,
|
||||
)}`,
|
||||
`Hacknet Income multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacknet_node_money_mult,
|
||||
)}`,
|
||||
`Hacknet Purchase Cost multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacknet_node_purchase_cost_mult,
|
||||
)}`,
|
||||
`Hacknet Level Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacknet_node_level_cost_mult,
|
||||
)}`,
|
||||
`Hacknet Ram Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacknet_node_ram_cost_mult,
|
||||
)}`,
|
||||
`Hacknet Core Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.hacknet_node_core_cost_mult,
|
||||
)}`,
|
||||
`Bladeburner Max Stamina multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.bladeburner_max_stamina_mult,
|
||||
)}`,
|
||||
`Bladeburner Stamina Gain multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.bladeburner_stamina_gain_mult,
|
||||
)}`,
|
||||
`Bladeburner Field Analysis multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.bladeburner_analysis_mult,
|
||||
)}`,
|
||||
`Bladeburner Success Chance multiplier: ${numeralWrapper.formatPercentage(
|
||||
resleeve.bladeburner_success_chance_mult,
|
||||
)}`,
|
||||
].join("<br />"),
|
||||
false,
|
||||
);
|
||||
},
|
||||
});
|
||||
elems.statsPanel.appendChild(elems.stats);
|
||||
elems.statsPanel.appendChild(elems.multipliersButton);
|
||||
|
||||
elems.augPanel = createElement("div", {
|
||||
class: "resleeve-panel",
|
||||
width: "50%",
|
||||
});
|
||||
elems.augSelector = createElement("select", {
|
||||
class: "resleeve-aug-selector dropdown",
|
||||
}) as HTMLSelectElement;
|
||||
elems.augDescription = createElement("p");
|
||||
for (let i = 0; i < resleeve.augmentations.length; ++i) {
|
||||
elems.augSelector.add(createOptionElement(resleeve.augmentations[i].name));
|
||||
}
|
||||
elems.augSelector.addEventListener("change", () => {
|
||||
updateAugDescription(elems);
|
||||
});
|
||||
elems.augSelector.dispatchEvent(new Event("change")); // Set inital description by manually triggering change event
|
||||
elems.augPanel.appendChild(elems.augSelector);
|
||||
elems.augPanel.appendChild(elems.augDescription);
|
||||
|
||||
const cost: number = resleeve.getCost();
|
||||
elems.costPanel = createElement("div", {
|
||||
class: "resleeve-panel",
|
||||
width: "20%",
|
||||
});
|
||||
elems.costText = createElement("p", {
|
||||
innerHTML:
|
||||
`It costs ${renderToStaticMarkup(
|
||||
<Money money={cost} player={playerRef} />,
|
||||
)} ` + `to purchase this Sleeve.`,
|
||||
});
|
||||
elems.buyButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Purchase",
|
||||
clickListener: () => {
|
||||
if (playerRef == null)
|
||||
throw new Error("playerRef is null in buyButton.click()");
|
||||
if (purchaseResleeve(resleeve, playerRef)) {
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
You re-sleeved for <Money money={cost} />!
|
||||
</>,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford to re-sleeve into this body`, false);
|
||||
}
|
||||
},
|
||||
});
|
||||
elems.costPanel.appendChild(elems.costText);
|
||||
elems.costPanel.appendChild(elems.buyButton);
|
||||
|
||||
elems.container.appendChild(elems.statsPanel);
|
||||
elems.container.appendChild(elems.augPanel);
|
||||
elems.container.appendChild(elems.costPanel);
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
function updateAugDescription(elems: IResleeveUIElems): void {
|
||||
if(elems.augDescription == null) throw new Error("elems.augDescription is null in updateAugDescription()");
|
||||
const augName: string = getSelectValue(elems.augSelector);
|
||||
const aug: Augmentation | null = Augmentations[augName];
|
||||
if (aug == null) {
|
||||
console.warn(`Could not find Augmentation with name ${augName}`);
|
||||
return;
|
||||
}
|
||||
if (elems.augDescription == null)
|
||||
throw new Error("elems.augDescription is null in updateAugDescription()");
|
||||
const augName: string = getSelectValue(elems.augSelector);
|
||||
const aug: Augmentation | null = Augmentations[augName];
|
||||
if (aug == null) {
|
||||
console.warn(`Could not find Augmentation with name ${augName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let innerHTML = aug.info;
|
||||
if(typeof innerHTML !== 'string') {
|
||||
innerHTML = renderToStaticMarkup(innerHTML);
|
||||
}
|
||||
let innerHTML = aug.info;
|
||||
if (typeof innerHTML !== "string") {
|
||||
innerHTML = renderToStaticMarkup(innerHTML);
|
||||
}
|
||||
|
||||
elems.augDescription.innerHTML = innerHTML;
|
||||
elems.augDescription.innerHTML = innerHTML;
|
||||
}
|
||||
|
||||
+1023
-870
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* Module for handling the UI for purchasing Sleeve Augmentations
|
||||
* This UI is a popup, not a full page
|
||||
*/
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { Sleeve } from "./Sleeve";
|
||||
import { findSleevePurchasableAugs } from "./SleeveHelpers";
|
||||
|
||||
@@ -20,106 +20,118 @@ import { createPopup } from "../../../utils/uiHelpers/createPopup";
|
||||
import { createPopupCloseButton } from "../../../utils/uiHelpers/createPopupCloseButton";
|
||||
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
||||
|
||||
import { renderToStaticMarkup } from "react-dom/server"
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer): void {
|
||||
// Array of all owned Augmentations. Names only
|
||||
const ownedAugNames: string[] = sleeve.augmentations.map((e) => {return e.name});
|
||||
export function createSleevePurchaseAugsPopup(
|
||||
sleeve: Sleeve,
|
||||
p: IPlayer,
|
||||
): void {
|
||||
// Array of all owned Augmentations. Names only
|
||||
const ownedAugNames: string[] = sleeve.augmentations.map((e) => {
|
||||
return e.name;
|
||||
});
|
||||
|
||||
// You can only purchase Augmentations that are actually available from
|
||||
// your factions. I.e. you must be in a faction that has the Augmentation
|
||||
// and you must also have enough rep in that faction in order to purchase it.
|
||||
const availableAugs = findSleevePurchasableAugs(sleeve, p);
|
||||
// You can only purchase Augmentations that are actually available from
|
||||
// your factions. I.e. you must be in a faction that has the Augmentation
|
||||
// and you must also have enough rep in that faction in order to purchase it.
|
||||
const availableAugs = findSleevePurchasableAugs(sleeve, p);
|
||||
|
||||
// Create popup
|
||||
const popupId = "purchase-sleeve-augs-popup";
|
||||
// Create popup
|
||||
const popupId = "purchase-sleeve-augs-popup";
|
||||
|
||||
// Close popup button
|
||||
const closeBtn = createPopupCloseButton(popupId, { innerText: "Cancel" });
|
||||
// Close popup button
|
||||
const closeBtn = createPopupCloseButton(popupId, { innerText: "Cancel" });
|
||||
|
||||
// General info about owned Augmentations
|
||||
const ownedAugsInfo = createElement("p", {
|
||||
display: "block",
|
||||
innerHTML: "Owned Augmentations:",
|
||||
// General info about owned Augmentations
|
||||
const ownedAugsInfo = createElement("p", {
|
||||
display: "block",
|
||||
innerHTML: "Owned Augmentations:",
|
||||
});
|
||||
|
||||
const popupElems: HTMLElement[] = [closeBtn, ownedAugsInfo];
|
||||
|
||||
// Show owned augmentations
|
||||
// First we'll make a div with a reduced width, so the tooltips don't go off
|
||||
// the edge of the popup
|
||||
const ownedAugsDiv = createElement("div", { width: "70%" });
|
||||
for (const ownedAug of ownedAugNames) {
|
||||
const aug: Augmentation | null = Augmentations[ownedAug];
|
||||
if (aug == null) {
|
||||
console.warn(`Invalid Augmentation: ${ownedAug}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
let tooltip = aug.info;
|
||||
if (typeof tooltip !== "string") {
|
||||
tooltip = renderToStaticMarkup(tooltip);
|
||||
}
|
||||
tooltip += "<br /><br />";
|
||||
tooltip += renderToStaticMarkup(aug.stats);
|
||||
|
||||
ownedAugsDiv.appendChild(
|
||||
createElement("div", {
|
||||
class: "gang-owned-upgrade", // Reusing a class from the Gang UI
|
||||
innerText: ownedAug,
|
||||
tooltip: tooltip,
|
||||
}),
|
||||
);
|
||||
}
|
||||
popupElems.push(ownedAugsDiv);
|
||||
|
||||
// General info about buying Augmentations
|
||||
const info = createElement("p", {
|
||||
innerHTML: [
|
||||
`You can purchase Augmentations for your Duplicate Sleeves. These Augmentations`,
|
||||
`have the same effect as they would for you. You can only purchase Augmentations`,
|
||||
`that you have unlocked through Factions.<br><br>`,
|
||||
`When purchasing an Augmentation for a Duplicate Sleeve, they are immediately`,
|
||||
`installed. This means that the Duplicate Sleeve will immediately lose all of`,
|
||||
`its stat experience.`,
|
||||
].join(" "),
|
||||
});
|
||||
|
||||
popupElems.push(info);
|
||||
|
||||
for (const aug of availableAugs) {
|
||||
const div = createElement("div", {
|
||||
class: "cmpy-mgmt-upgrade-div", // We'll reuse this CSS class
|
||||
});
|
||||
|
||||
const popupElems: HTMLElement[] = [closeBtn, ownedAugsInfo];
|
||||
|
||||
// Show owned augmentations
|
||||
// First we'll make a div with a reduced width, so the tooltips don't go off
|
||||
// the edge of the popup
|
||||
const ownedAugsDiv = createElement("div", { width: "70%" });
|
||||
for (const ownedAug of ownedAugNames) {
|
||||
const aug: Augmentation | null = Augmentations[ownedAug];
|
||||
if (aug == null) {
|
||||
console.warn(`Invalid Augmentation: ${ownedAug}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
let tooltip = aug.info;
|
||||
if(typeof tooltip !== 'string') {
|
||||
tooltip = renderToStaticMarkup(tooltip);
|
||||
}
|
||||
tooltip += "<br /><br />";
|
||||
tooltip += renderToStaticMarkup(aug.stats);
|
||||
|
||||
ownedAugsDiv.appendChild(createElement("div", {
|
||||
class: "gang-owned-upgrade", // Reusing a class from the Gang UI
|
||||
innerText: ownedAug,
|
||||
tooltip: tooltip,
|
||||
}))
|
||||
let info = aug.info;
|
||||
if (typeof info !== "string") {
|
||||
info = renderToStaticMarkup(info);
|
||||
}
|
||||
popupElems.push(ownedAugsDiv);
|
||||
info += "<br /><br />";
|
||||
info += renderToStaticMarkup(aug.stats);
|
||||
|
||||
// General info about buying Augmentations
|
||||
const info = createElement("p", {
|
||||
innerHTML:
|
||||
[
|
||||
`You can purchase Augmentations for your Duplicate Sleeves. These Augmentations`,
|
||||
`have the same effect as they would for you. You can only purchase Augmentations`,
|
||||
`that you have unlocked through Factions.<br><br>`,
|
||||
`When purchasing an Augmentation for a Duplicate Sleeve, they are immediately`,
|
||||
`installed. This means that the Duplicate Sleeve will immediately lose all of`,
|
||||
`its stat experience.`,
|
||||
div.appendChild(
|
||||
createElement("p", {
|
||||
fontSize: "12px",
|
||||
innerHTML: [
|
||||
`<h2>${aug.name}</h2><br>`,
|
||||
`Cost: ${renderToStaticMarkup(
|
||||
<Money money={aug.startingCost} player={p} />,
|
||||
)}<br><br>`,
|
||||
`${info}`,
|
||||
].join(" "),
|
||||
});
|
||||
padding: "2px",
|
||||
clickListener: () => {
|
||||
if (sleeve.tryBuyAugmentation(p, aug)) {
|
||||
dialogBoxCreate(
|
||||
`Installed ${aug.name} on Duplicate Sleeve!`,
|
||||
false,
|
||||
);
|
||||
removeElementById(popupId);
|
||||
createSleevePurchaseAugsPopup(sleeve, p);
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford ${aug.name}`, false);
|
||||
}
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
popupElems.push(info);
|
||||
popupElems.push(div);
|
||||
}
|
||||
|
||||
for (const aug of availableAugs) {
|
||||
const div = createElement("div", {
|
||||
class: "cmpy-mgmt-upgrade-div", // We'll reuse this CSS class
|
||||
});
|
||||
|
||||
let info = aug.info;
|
||||
if(typeof info !== 'string') {
|
||||
info = renderToStaticMarkup(info);
|
||||
}
|
||||
info += "<br /><br />";
|
||||
info += renderToStaticMarkup(aug.stats);
|
||||
|
||||
div.appendChild(createElement("p", {
|
||||
fontSize: "12px",
|
||||
innerHTML:
|
||||
[
|
||||
`<h2>${aug.name}</h2><br>`,
|
||||
`Cost: ${renderToStaticMarkup(<Money money={aug.startingCost} player={p} />)}<br><br>`,
|
||||
`${info}`,
|
||||
].join(" "),
|
||||
padding: "2px",
|
||||
clickListener: () => {
|
||||
if (sleeve.tryBuyAugmentation(p, aug)) {
|
||||
dialogBoxCreate(`Installed ${aug.name} on Duplicate Sleeve!`, false);
|
||||
removeElementById(popupId);
|
||||
createSleevePurchaseAugsPopup(sleeve, p);
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford ${aug.name}`, false);
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
popupElems.push(div);
|
||||
}
|
||||
|
||||
createPopup(popupId, popupElems);
|
||||
createPopup(popupId, popupElems);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
import { CovenantPurchasesRoot } from "./ui/CovenantPurchasesRoot";
|
||||
import { createPopup,
|
||||
removePopup } from "../../ui/React/createPopup";
|
||||
import { createPopup, removePopup } from "../../ui/React/createPopup";
|
||||
|
||||
export const MaxSleevesFromCovenant = 5;
|
||||
export const BaseCostPerSleeve = 10e12;
|
||||
export const PopupId = "covenant-sleeve-purchases-popup";
|
||||
|
||||
export function createSleevePurchasesFromCovenantPopup(p: IPlayer): void {
|
||||
createPopup(PopupId, CovenantPurchasesRoot, { p: p, closeFn: () => removePopup(PopupId) });
|
||||
createPopup(PopupId, CovenantPurchasesRoot, {
|
||||
p: p,
|
||||
closeFn: () => removePopup(PopupId),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,57 +8,80 @@ import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
|
||||
export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentation[] {
|
||||
// You can only purchase Augmentations that are actually available from
|
||||
// your factions. I.e. you must be in a faction that has the Augmentation
|
||||
// and you must also have enough rep in that faction in order to purchase it.
|
||||
export function findSleevePurchasableAugs(
|
||||
sleeve: Sleeve,
|
||||
p: IPlayer,
|
||||
): Augmentation[] {
|
||||
// You can only purchase Augmentations that are actually available from
|
||||
// your factions. I.e. you must be in a faction that has the Augmentation
|
||||
// and you must also have enough rep in that faction in order to purchase it.
|
||||
|
||||
const ownedAugNames: string[] = sleeve.augmentations.map((e) => {return e.name});
|
||||
const availableAugs: Augmentation[] = [];
|
||||
const ownedAugNames: string[] = sleeve.augmentations.map((e) => {
|
||||
return e.name;
|
||||
});
|
||||
const availableAugs: Augmentation[] = [];
|
||||
|
||||
// Helper function that helps filter out augs that are already owned
|
||||
// and augs that aren't allowed for sleeves
|
||||
function isAvailableForSleeve(aug: Augmentation): boolean {
|
||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) { return false; }
|
||||
if (ownedAugNames.includes(aug.name)) { return false; }
|
||||
if (availableAugs.includes(aug)) { return false; }
|
||||
if (aug.isSpecial) { return false; }
|
||||
|
||||
return true;
|
||||
// Helper function that helps filter out augs that are already owned
|
||||
// and augs that aren't allowed for sleeves
|
||||
function isAvailableForSleeve(aug: Augmentation): boolean {
|
||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
return false;
|
||||
}
|
||||
if (ownedAugNames.includes(aug.name)) {
|
||||
return false;
|
||||
}
|
||||
if (availableAugs.includes(aug)) {
|
||||
return false;
|
||||
}
|
||||
if (aug.isSpecial) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If player is in a gang, then we return all augs that the player
|
||||
// has enough reputation for (since that gang offers all augs)
|
||||
if (p.inGang()) {
|
||||
const fac = p.getGangFaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
if (!isAvailableForSleeve(aug)) { continue; }
|
||||
// If player is in a gang, then we return all augs that the player
|
||||
// has enough reputation for (since that gang offers all augs)
|
||||
if (p.inGang()) {
|
||||
const fac = p.getGangFaction();
|
||||
|
||||
if (fac.playerReputation > aug.baseRepRequirement) {
|
||||
availableAugs.push(aug);
|
||||
}
|
||||
}
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
if (!isAvailableForSleeve(aug)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return availableAugs;
|
||||
}
|
||||
|
||||
for (const facName of p.factions) {
|
||||
if (facName === "Bladeburners") { continue; }
|
||||
if (facName === "Netburners") { continue; }
|
||||
const fac: Faction | null = Factions[facName];
|
||||
if (fac == null) { continue; }
|
||||
|
||||
for (const augName of fac.augmentations) {
|
||||
const aug: Augmentation = Augmentations[augName];
|
||||
if (!isAvailableForSleeve(aug)) { continue; }
|
||||
|
||||
if (fac.playerReputation > aug.baseRepRequirement) {
|
||||
availableAugs.push(aug);
|
||||
}
|
||||
}
|
||||
if (fac.playerReputation > aug.baseRepRequirement) {
|
||||
availableAugs.push(aug);
|
||||
}
|
||||
}
|
||||
|
||||
return availableAugs;
|
||||
}
|
||||
|
||||
for (const facName of p.factions) {
|
||||
if (facName === "Bladeburners") {
|
||||
continue;
|
||||
}
|
||||
if (facName === "Netburners") {
|
||||
continue;
|
||||
}
|
||||
const fac: Faction | null = Factions[facName];
|
||||
if (fac == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const augName of fac.augmentations) {
|
||||
const aug: Augmentation = Augmentations[augName];
|
||||
if (!isAvailableForSleeve(aug)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fac.playerReputation > aug.baseRepRequirement) {
|
||||
availableAugs.push(aug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return availableAugs;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
* Enum for different types of tasks that a Sleeve can perform
|
||||
*/
|
||||
export enum SleeveTaskType {
|
||||
// Same Order as selectable order in UI
|
||||
Idle,
|
||||
Company,
|
||||
Faction,
|
||||
Crime,
|
||||
Class,
|
||||
Gym,
|
||||
Recovery,
|
||||
Synchro,
|
||||
// Same Order as selectable order in UI
|
||||
Idle,
|
||||
Company,
|
||||
Faction,
|
||||
Crime,
|
||||
Class,
|
||||
Gym,
|
||||
Recovery,
|
||||
Synchro,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,80 +1,116 @@
|
||||
import * as React from "react";
|
||||
|
||||
export const SleeveFaq = (<>
|
||||
<strong><u>How do Duplicate Sleeves work?</u></strong>
|
||||
export const SleeveFaq = (
|
||||
<>
|
||||
<strong>
|
||||
<u>How do Duplicate Sleeves work?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Duplicate Sleeves are essentially clones. You can use them to perform any work type
|
||||
action, such as working for a company/faction or committing a crime.
|
||||
Having sleeves perform these tasks earns you money, experience, and reputation.
|
||||
<br /><br />
|
||||
Sleeves are their own individuals, which means they each have their own
|
||||
experience and stats.
|
||||
<br /><br />
|
||||
When a sleeve earns experience, it earns experience for itself, the player's
|
||||
original 'consciousness', as well as all of the player's other sleeves.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>What is Synchronization (Sync)?</u></strong>
|
||||
Duplicate Sleeves are essentially clones. You can use them to perform any
|
||||
work type action, such as working for a company/faction or committing a
|
||||
crime. Having sleeves perform these tasks earns you money, experience, and
|
||||
reputation.
|
||||
<br />
|
||||
Synchronization is a measure of how aligned your consciousness is with
|
||||
that of your Duplicate Sleeves. It is a numerical value between 1 and 100, and
|
||||
it affects how much experience is earned when the sleeve is performing a task.
|
||||
<br /><br />
|
||||
Let N be the sleeve's synchronization. When the sleeve earns experience by performing a
|
||||
task, both the sleeve and the player's original host consciousness earn N%
|
||||
of the amount of experience normally earned by the task. All of the player's
|
||||
other sleeves earn ((N/100)^2 * 100)% of the experience.
|
||||
<br /><br />
|
||||
Synchronization can be increased by assigning sleeves to the 'Synchronize' task.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>What is Shock?</u></strong>
|
||||
<br />
|
||||
Sleeve shock is a measure of how much trauma the sleeve has due to being placed in a new
|
||||
body. It is a numerical value between 0 and 99, where 99 indicates full shock and 0 indicates
|
||||
no shock. Shock affects the amount of experience earned by the sleeve.
|
||||
<br /><br />
|
||||
Sleeve shock slowly decreases over time. You can further increase the rate at which
|
||||
it decreases by assigning sleeves to the 'Shock Recovery' task.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>Why can't I work for this company or faction?</u></strong>
|
||||
Sleeves are their own individuals, which means they each have their own
|
||||
experience and stats.
|
||||
<br />
|
||||
Only one of your sleeves can work for a given company/faction a time.
|
||||
To clarify further, if you have two sleeves they can work for two different
|
||||
companies, but they cannot both work for the same company.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>Why did my Sleeve stop working?</u></strong>
|
||||
<br />
|
||||
Sleeves are subject to the same time restrictions as you. This means that
|
||||
they automatically stop working at a company after 8 hours, and stop working
|
||||
for a faction after 20 hours.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>How do I buy Augmentations for my Sleeves?</u></strong>
|
||||
When a sleeve earns experience, it earns experience for itself, the player's
|
||||
original 'consciousness', as well as all of the player's other sleeves.
|
||||
<br />
|
||||
Your Sleeve needs to have a Shock of 0 in order for you to buy Augmentations
|
||||
for it.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>Why can't I buy the X Augmentation for my sleeve?</u></strong>
|
||||
<br />
|
||||
Certain Augmentations, like Bladeburner-specific ones and NeuroFlux Governor,
|
||||
are not available for sleeves.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>Do sleeves get reset when installing Augmentations or switching BitNodes?</u></strong><br />
|
||||
Sleeves are reset when switching BitNodes, but not when installing Augmentations.
|
||||
<br /><br />
|
||||
|
||||
<strong><u>What is Memory?</u></strong>
|
||||
<strong>
|
||||
<u>What is Synchronization (Sync)?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeve memory dictates what a sleeve's synchronization will be
|
||||
when its reset by switching BitNodes. For example, if a sleeve has a memory of 25,
|
||||
then when you switch BitNodes its synchronization will initially be set to 25, rather than 1.
|
||||
<br /><br />
|
||||
Memory can only be increased by purchasing upgrades from The Covenant. It is a
|
||||
persistent stat, meaning it never gets resets back to 1. The maximum possible
|
||||
value for a sleeve's memory is 100.
|
||||
</>);
|
||||
Synchronization is a measure of how aligned your consciousness is with that
|
||||
of your Duplicate Sleeves. It is a numerical value between 1 and 100, and it
|
||||
affects how much experience is earned when the sleeve is performing a task.
|
||||
<br />
|
||||
<br />
|
||||
Let N be the sleeve's synchronization. When the sleeve earns experience by
|
||||
performing a task, both the sleeve and the player's original host
|
||||
consciousness earn N% of the amount of experience normally earned by the
|
||||
task. All of the player's other sleeves earn ((N/100)^2 * 100)% of the
|
||||
experience.
|
||||
<br />
|
||||
<br />
|
||||
Synchronization can be increased by assigning sleeves to the 'Synchronize'
|
||||
task.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>What is Shock?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeve shock is a measure of how much trauma the sleeve has due to being
|
||||
placed in a new body. It is a numerical value between 0 and 99, where 99
|
||||
indicates full shock and 0 indicates no shock. Shock affects the amount of
|
||||
experience earned by the sleeve.
|
||||
<br />
|
||||
<br />
|
||||
Sleeve shock slowly decreases over time. You can further increase the rate
|
||||
at which it decreases by assigning sleeves to the 'Shock Recovery' task.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Why can't I work for this company or faction?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Only one of your sleeves can work for a given company/faction a time. To
|
||||
clarify further, if you have two sleeves they can work for two different
|
||||
companies, but they cannot both work for the same company.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Why did my Sleeve stop working?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeves are subject to the same time restrictions as you. This means that
|
||||
they automatically stop working at a company after 8 hours, and stop working
|
||||
for a faction after 20 hours.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>How do I buy Augmentations for my Sleeves?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Your Sleeve needs to have a Shock of 0 in order for you to buy Augmentations
|
||||
for it.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Why can't I buy the X Augmentation for my sleeve?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Certain Augmentations, like Bladeburner-specific ones and NeuroFlux
|
||||
Governor, are not available for sleeves.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>
|
||||
Do sleeves get reset when installing Augmentations or switching
|
||||
BitNodes?
|
||||
</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeves are reset when switching BitNodes, but not when installing
|
||||
Augmentations.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>What is Memory?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeve memory dictates what a sleeve's synchronization will be when its
|
||||
reset by switching BitNodes. For example, if a sleeve has a memory of 25,
|
||||
then when you switch BitNodes its synchronization will initially be set to
|
||||
25, rather than 1.
|
||||
<br />
|
||||
<br />
|
||||
Memory can only be increased by purchasing upgrades from The Covenant. It is
|
||||
a persistent stat, meaning it never gets resets back to 1. The maximum
|
||||
possible value for a sleeve's memory is 100.
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -2,92 +2,110 @@
|
||||
* Root React component for the popup that lets player purchase Duplicate
|
||||
* Sleeves and Sleeve-related upgrades from The Covenant
|
||||
*/
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { CovenantSleeveUpgrades } from "./CovenantSleeveUpgrades";
|
||||
import { CovenantSleeveUpgrades } from "./CovenantSleeveUpgrades";
|
||||
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { BaseCostPerSleeve,
|
||||
MaxSleevesFromCovenant,
|
||||
PopupId } from "../SleeveCovenantPurchases";
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import {
|
||||
BaseCostPerSleeve,
|
||||
MaxSleevesFromCovenant,
|
||||
PopupId,
|
||||
} from "../SleeveCovenantPurchases";
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
|
||||
import { PopupCloseButton } from "../../../ui/React/PopupCloseButton";
|
||||
import { StdButton } from "../../../ui/React/StdButton";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { PopupCloseButton } from "../../../ui/React/PopupCloseButton";
|
||||
import { StdButton } from "../../../ui/React/StdButton";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
|
||||
import { dialogBoxCreate } from "../../../../utils/DialogBox";
|
||||
import { dialogBoxCreate } from "../../../../utils/DialogBox";
|
||||
|
||||
interface IProps {
|
||||
closeFn: () => void;
|
||||
p: IPlayer;
|
||||
closeFn: () => void;
|
||||
p: IPlayer;
|
||||
}
|
||||
|
||||
export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
|
||||
const [update, setUpdate] = useState(0);
|
||||
const [update, setUpdate] = useState(0);
|
||||
|
||||
/**
|
||||
* Get the cost to purchase a new Duplicate Sleeve
|
||||
*/
|
||||
function purchaseCost(): number {
|
||||
return (props.p.sleevesFromCovenant + 1) * BaseCostPerSleeve;
|
||||
}
|
||||
/**
|
||||
* Get the cost to purchase a new Duplicate Sleeve
|
||||
*/
|
||||
function purchaseCost(): number {
|
||||
return (props.p.sleevesFromCovenant + 1) * BaseCostPerSleeve;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a rerender by just changing an arbitrary state value
|
||||
*/
|
||||
function rerender(): void {
|
||||
setUpdate(update + 1);
|
||||
}
|
||||
/**
|
||||
* Force a rerender by just changing an arbitrary state value
|
||||
*/
|
||||
function rerender(): void {
|
||||
setUpdate(update + 1);
|
||||
}
|
||||
|
||||
// Purchasing a new Duplicate Sleeve
|
||||
let purchaseDisabled = false;
|
||||
if (!props.p.canAfford(purchaseCost())) {
|
||||
purchaseDisabled = true;
|
||||
}
|
||||
if (props.p.sleevesFromCovenant >= MaxSleevesFromCovenant) {
|
||||
purchaseDisabled = true;
|
||||
}
|
||||
// Purchasing a new Duplicate Sleeve
|
||||
let purchaseDisabled = false;
|
||||
if (!props.p.canAfford(purchaseCost())) {
|
||||
purchaseDisabled = true;
|
||||
}
|
||||
if (props.p.sleevesFromCovenant >= MaxSleevesFromCovenant) {
|
||||
purchaseDisabled = true;
|
||||
}
|
||||
|
||||
function purchaseOnClick(): void {
|
||||
if (props.p.sleevesFromCovenant >= MaxSleevesFromCovenant) return;
|
||||
|
||||
if (props.p.canAfford(purchaseCost())) {
|
||||
props.p.loseMoney(purchaseCost());
|
||||
props.p.sleevesFromCovenant += 1;
|
||||
props.p.sleeves.push(new Sleeve(props.p));
|
||||
rerender();
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`, false);
|
||||
}
|
||||
}
|
||||
function purchaseOnClick(): void {
|
||||
if (props.p.sleevesFromCovenant >= MaxSleevesFromCovenant) return;
|
||||
|
||||
// Purchasing Upgrades for Sleeves
|
||||
const upgradePanels = [];
|
||||
for (let i = 0; i < props.p.sleeves.length; ++i) {
|
||||
const sleeve = props.p.sleeves[i];
|
||||
upgradePanels.push(
|
||||
<CovenantSleeveUpgrades {...props} sleeve={sleeve} index={i} rerender={rerender} key={i} />,
|
||||
)
|
||||
if (props.p.canAfford(purchaseCost())) {
|
||||
props.p.loseMoney(purchaseCost());
|
||||
props.p.sleevesFromCovenant += 1;
|
||||
props.p.sleeves.push(new Sleeve(props.p));
|
||||
rerender();
|
||||
} else {
|
||||
dialogBoxCreate(
|
||||
`You cannot afford to purchase a Duplicate Sleeve`,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (<div>
|
||||
<PopupCloseButton popup={PopupId} text={"Close"} />
|
||||
<p>
|
||||
Would you like to purchase an additional Duplicate Sleeve from The Covenant
|
||||
for <Money money={purchaseCost()} player={props.p} />?
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
These Duplicate Sleeves are permanent (they persist through BitNodes). You can
|
||||
purchase a total of {MaxSleevesFromCovenant} from The Covenant.
|
||||
</p>
|
||||
<StdButton disabled={purchaseDisabled} onClick={purchaseOnClick} text={"Purchase"} />
|
||||
<br /><br />
|
||||
<p>
|
||||
Here, you can also purchase upgrades for your Duplicate Sleeves. These upgrades
|
||||
are also permanent, meaning they persist across BitNodes.
|
||||
</p>
|
||||
{upgradePanels}
|
||||
</div>);
|
||||
// Purchasing Upgrades for Sleeves
|
||||
const upgradePanels = [];
|
||||
for (let i = 0; i < props.p.sleeves.length; ++i) {
|
||||
const sleeve = props.p.sleeves[i];
|
||||
upgradePanels.push(
|
||||
<CovenantSleeveUpgrades
|
||||
{...props}
|
||||
sleeve={sleeve}
|
||||
index={i}
|
||||
rerender={rerender}
|
||||
key={i}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PopupCloseButton popup={PopupId} text={"Close"} />
|
||||
<p>
|
||||
Would you like to purchase an additional Duplicate Sleeve from The
|
||||
Covenant for <Money money={purchaseCost()} player={props.p} />?
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
These Duplicate Sleeves are permanent (they persist through BitNodes).
|
||||
You can purchase a total of {MaxSleevesFromCovenant} from The Covenant.
|
||||
</p>
|
||||
<StdButton
|
||||
disabled={purchaseDisabled}
|
||||
onClick={purchaseOnClick}
|
||||
text={"Purchase"}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<p>
|
||||
Here, you can also purchase upgrades for your Duplicate Sleeves. These
|
||||
upgrades are also permanent, meaning they persist across BitNodes.
|
||||
</p>
|
||||
{upgradePanels}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,91 +12,116 @@ import { StdButton } from "../../../ui/React/StdButton";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
|
||||
interface IProps {
|
||||
index: number;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
sleeve: Sleeve;
|
||||
index: number;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
sleeve: Sleeve;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
amt: number;
|
||||
amt: number;
|
||||
}
|
||||
|
||||
export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
export class CovenantSleeveMemoryUpgrade extends React.Component<
|
||||
IProps,
|
||||
IState
|
||||
> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
amt: 1,
|
||||
}
|
||||
this.state = {
|
||||
amt: 1,
|
||||
};
|
||||
|
||||
this.changePurchaseAmount = this.changePurchaseAmount.bind(this);
|
||||
this.purchaseMemory = this.purchaseMemory.bind(this);
|
||||
this.changePurchaseAmount = this.changePurchaseAmount.bind(this);
|
||||
this.purchaseMemory = this.purchaseMemory.bind(this);
|
||||
}
|
||||
|
||||
changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||
let n: number = parseInt(e.target.value);
|
||||
|
||||
if (isNaN(n)) n = 1;
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
if (n > maxMemory) n = maxMemory;
|
||||
|
||||
this.setState({
|
||||
amt: n,
|
||||
});
|
||||
}
|
||||
|
||||
getPurchaseCost(): number {
|
||||
if (isNaN(this.state.amt)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||
let n: number = parseInt(e.target.value);
|
||||
|
||||
if(isNaN(n)) n = 1;
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
if (n > maxMemory) n = maxMemory;
|
||||
|
||||
this.setState({
|
||||
amt: n,
|
||||
});
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
if (this.state.amt > maxMemory) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
getPurchaseCost(): number {
|
||||
if (isNaN(this.state.amt)) { return Infinity; }
|
||||
return this.props.sleeve.getMemoryUpgradeCost(this.state.amt);
|
||||
}
|
||||
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
if (this.state.amt > maxMemory) { return Infinity; }
|
||||
purchaseMemory(): void {
|
||||
const cost = this.getPurchaseCost();
|
||||
if (this.props.p.canAfford(cost)) {
|
||||
this.props.sleeve.upgradeMemory(this.state.amt);
|
||||
this.props.p.loseMoney(cost);
|
||||
this.props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
return this.props.sleeve.getMemoryUpgradeCost(this.state.amt);
|
||||
render(): React.ReactNode {
|
||||
const inputId = `sleeve-${this.props.index}-memory-upgrade-input`;
|
||||
|
||||
// Memory cannot go above 100
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
|
||||
// Purchase button props
|
||||
const cost = this.getPurchaseCost();
|
||||
const purchaseBtnDisabled = !this.props.p.canAfford(cost);
|
||||
let purchaseBtnContent;
|
||||
if (isNaN(this.state.amt)) {
|
||||
purchaseBtnContent = <>Invalid value</>;
|
||||
} else if (this.state.amt > maxMemory) {
|
||||
purchaseBtnContent = <>Memory cannot exceed 100?</>;
|
||||
} else {
|
||||
purchaseBtnContent = (
|
||||
<>
|
||||
Purchase {this.state.amt} memory -{" "}
|
||||
<Money money={cost} player={this.props.p} />?
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
purchaseMemory(): void {
|
||||
const cost = this.getPurchaseCost();
|
||||
if (this.props.p.canAfford(cost)) {
|
||||
this.props.sleeve.upgradeMemory(this.state.amt);
|
||||
this.props.p.loseMoney(cost);
|
||||
this.props.rerender();
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h2>
|
||||
<u>Upgrade Memory</u>
|
||||
</h2>
|
||||
<p>
|
||||
Purchase a memory upgrade for your sleeve. Note that a sleeve's max
|
||||
memory is 100 (current:{" "}
|
||||
{numeralWrapper.formatSleeveMemory(this.props.sleeve.memory)})
|
||||
</p>
|
||||
|
||||
render(): React.ReactNode {
|
||||
const inputId = `sleeve-${this.props.index}-memory-upgrade-input`;
|
||||
|
||||
// Memory cannot go above 100
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
|
||||
// Purchase button props
|
||||
const cost = this.getPurchaseCost();
|
||||
const purchaseBtnDisabled = !this.props.p.canAfford(cost);
|
||||
let purchaseBtnContent;
|
||||
if (isNaN(this.state.amt)) {
|
||||
purchaseBtnContent = <>Invalid value</>;
|
||||
} else if (this.state.amt > maxMemory) {
|
||||
purchaseBtnContent = <>Memory cannot exceed 100?</>;
|
||||
} else {
|
||||
purchaseBtnContent = <>Purchase {this.state.amt} memory - <Money money={cost} player={this.props.p} />?</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2><u>Upgrade Memory</u></h2>
|
||||
<p>
|
||||
Purchase a memory upgrade for your sleeve. Note that a sleeve's max memory
|
||||
is 100 (current: {numeralWrapper.formatSleeveMemory(this.props.sleeve.memory)})
|
||||
</p>
|
||||
|
||||
<label htmlFor={inputId}>
|
||||
Amount of memory to purchase (must be an integer):
|
||||
</label>
|
||||
<input className="text-input" id={inputId} onChange={this.changePurchaseAmount} type={"number"} value={this.state.amt} />
|
||||
<br />
|
||||
<StdButton disabled={purchaseBtnDisabled} onClick={this.purchaseMemory} text={purchaseBtnContent} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<label htmlFor={inputId}>
|
||||
Amount of memory to purchase (must be an integer):
|
||||
</label>
|
||||
<input
|
||||
className="text-input"
|
||||
id={inputId}
|
||||
onChange={this.changePurchaseAmount}
|
||||
type={"number"}
|
||||
value={this.state.amt}
|
||||
/>
|
||||
<br />
|
||||
<StdButton
|
||||
disabled={purchaseBtnDisabled}
|
||||
onClick={this.purchaseMemory}
|
||||
text={purchaseBtnContent}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,19 @@ import { Sleeve } from "../Sleeve";
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
|
||||
interface IProps {
|
||||
index: number;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
sleeve: Sleeve;
|
||||
index: number;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
sleeve: Sleeve;
|
||||
}
|
||||
|
||||
export class CovenantSleeveUpgrades extends React.Component<IProps, any> {
|
||||
render(): React.ReactNode {
|
||||
return (
|
||||
<div className={"bladeburner-action"}>
|
||||
<h1>Duplicate Sleeve {this.props.index}</h1>
|
||||
<CovenantSleeveMemoryUpgrade {...this.props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
render(): React.ReactNode {
|
||||
return (
|
||||
<div className={"bladeburner-action"}>
|
||||
<h1>Duplicate Sleeve {this.props.index}</h1>
|
||||
<CovenantSleeveMemoryUpgrade {...this.props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,31 @@
|
||||
import * as React from "react";
|
||||
|
||||
export function EarningsTableElement(title: string, stats: any[][]): React.ReactElement {
|
||||
return (<>
|
||||
<pre>{title}</pre>
|
||||
<table>
|
||||
<tbody>
|
||||
{stats.map((stat: any[], i: number) => <tr key={i}>
|
||||
{stat.map((s: any, i: number) => {
|
||||
let style = {};
|
||||
if(i !== 0) {
|
||||
style = {textAlign: "right"};
|
||||
}
|
||||
return <td style={style} key={i}>{s}</td>
|
||||
})}
|
||||
</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</>)
|
||||
export function EarningsTableElement(
|
||||
title: string,
|
||||
stats: any[][],
|
||||
): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<pre>{title}</pre>
|
||||
<table>
|
||||
<tbody>
|
||||
{stats.map((stat: any[], i: number) => (
|
||||
<tr key={i}>
|
||||
{stat.map((s: any, i: number) => {
|
||||
let style = {};
|
||||
if (i !== 0) {
|
||||
style = { textAlign: "right" };
|
||||
}
|
||||
return (
|
||||
<td style={style} key={i}>
|
||||
{s}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,36 +5,101 @@ import * as React from "react";
|
||||
import { StatsTable } from "../../../ui/React/StatsTable";
|
||||
|
||||
export function MoreEarningsContent(sleeve: Sleeve): React.ReactElement {
|
||||
return (<>
|
||||
{StatsTable([
|
||||
['Money ', <Money money={sleeve.earningsForTask.money} />],
|
||||
['Hacking Exp ', numeralWrapper.formatExp(sleeve.earningsForTask.hack)],
|
||||
['Strength Exp ', numeralWrapper.formatExp(sleeve.earningsForTask.str)],
|
||||
['Defense Exp ', numeralWrapper.formatExp(sleeve.earningsForTask.def)],
|
||||
['Dexterity Exp ', numeralWrapper.formatExp(sleeve.earningsForTask.dex)],
|
||||
['Agility Exp ', numeralWrapper.formatExp(sleeve.earningsForTask.agi)],
|
||||
['Charisma Exp ', numeralWrapper.formatExp(sleeve.earningsForTask.cha)],
|
||||
], 'Earnings for Current Task:')}
|
||||
<br />
|
||||
{StatsTable([
|
||||
['Money: ', <Money money={sleeve.earningsForPlayer.money} />],
|
||||
['Hacking Exp: ', numeralWrapper.formatExp(sleeve.earningsForPlayer.hack)],
|
||||
['Strength Exp: ', numeralWrapper.formatExp(sleeve.earningsForPlayer.str)],
|
||||
['Defense Exp: ', numeralWrapper.formatExp(sleeve.earningsForPlayer.def)],
|
||||
['Dexterity Exp: ', numeralWrapper.formatExp(sleeve.earningsForPlayer.dex)],
|
||||
['Agility Exp: ', numeralWrapper.formatExp(sleeve.earningsForPlayer.agi)],
|
||||
['Charisma Exp: ', numeralWrapper.formatExp(sleeve.earningsForPlayer.cha)],
|
||||
], 'Total Earnings for Host Consciousness:')}
|
||||
<br />
|
||||
{StatsTable([
|
||||
['Money: ', <Money money={sleeve.earningsForSleeves.money} />],
|
||||
['Hacking Exp: ', numeralWrapper.formatExp(sleeve.earningsForSleeves.hack)],
|
||||
['Strength Exp: ', numeralWrapper.formatExp(sleeve.earningsForSleeves.str)],
|
||||
['Defense Exp: ', numeralWrapper.formatExp(sleeve.earningsForSleeves.def)],
|
||||
['Dexterity Exp: ', numeralWrapper.formatExp(sleeve.earningsForSleeves.dex)],
|
||||
['Agility Exp: ', numeralWrapper.formatExp(sleeve.earningsForSleeves.agi)],
|
||||
['Charisma Exp: ', numeralWrapper.formatExp(sleeve.earningsForSleeves.cha)],
|
||||
], 'Total Earnings for Other Sleeves:')}
|
||||
<br />
|
||||
</>);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{StatsTable(
|
||||
[
|
||||
["Money ", <Money money={sleeve.earningsForTask.money} />],
|
||||
[
|
||||
"Hacking Exp ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForTask.hack),
|
||||
],
|
||||
[
|
||||
"Strength Exp ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForTask.str),
|
||||
],
|
||||
[
|
||||
"Defense Exp ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForTask.def),
|
||||
],
|
||||
[
|
||||
"Dexterity Exp ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForTask.dex),
|
||||
],
|
||||
[
|
||||
"Agility Exp ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForTask.agi),
|
||||
],
|
||||
[
|
||||
"Charisma Exp ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForTask.cha),
|
||||
],
|
||||
],
|
||||
"Earnings for Current Task:",
|
||||
)}
|
||||
<br />
|
||||
{StatsTable(
|
||||
[
|
||||
["Money: ", <Money money={sleeve.earningsForPlayer.money} />],
|
||||
[
|
||||
"Hacking Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForPlayer.hack),
|
||||
],
|
||||
[
|
||||
"Strength Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForPlayer.str),
|
||||
],
|
||||
[
|
||||
"Defense Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForPlayer.def),
|
||||
],
|
||||
[
|
||||
"Dexterity Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForPlayer.dex),
|
||||
],
|
||||
[
|
||||
"Agility Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForPlayer.agi),
|
||||
],
|
||||
[
|
||||
"Charisma Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForPlayer.cha),
|
||||
],
|
||||
],
|
||||
"Total Earnings for Host Consciousness:",
|
||||
)}
|
||||
<br />
|
||||
{StatsTable(
|
||||
[
|
||||
["Money: ", <Money money={sleeve.earningsForSleeves.money} />],
|
||||
[
|
||||
"Hacking Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForSleeves.hack),
|
||||
],
|
||||
[
|
||||
"Strength Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForSleeves.str),
|
||||
],
|
||||
[
|
||||
"Defense Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForSleeves.def),
|
||||
],
|
||||
[
|
||||
"Dexterity Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForSleeves.dex),
|
||||
],
|
||||
[
|
||||
"Agility Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForSleeves.agi),
|
||||
],
|
||||
[
|
||||
"Charisma Exp: ",
|
||||
numeralWrapper.formatExp(sleeve.earningsForSleeves.cha),
|
||||
],
|
||||
],
|
||||
"Total Earnings for Other Sleeves:",
|
||||
)}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,34 +4,117 @@ import { StatsTable } from "../../../ui/React/StatsTable";
|
||||
import * as React from "react";
|
||||
|
||||
export function MoreStatsContent(sleeve: Sleeve): React.ReactElement {
|
||||
return (<>
|
||||
{StatsTable([
|
||||
['Hacking: ', sleeve.hacking_skill, `(${numeralWrapper.formatExp(sleeve.hacking_exp)} exp)`],
|
||||
['Strength: ', sleeve.strength, `(${numeralWrapper.formatExp(sleeve.strength_exp)} exp)`],
|
||||
['Defense: ', sleeve.defense, `(${numeralWrapper.formatExp(sleeve.defense_exp)} exp)`],
|
||||
['Dexterity: ', sleeve.dexterity, `(${numeralWrapper.formatExp(sleeve.dexterity_exp)} exp)`],
|
||||
['Agility: ', sleeve.agility, `(${numeralWrapper.formatExp(sleeve.agility_exp)} exp)`],
|
||||
['Charisma: ', sleeve.charisma, `(${numeralWrapper.formatExp(sleeve.charisma_exp)} exp)`],
|
||||
], 'Stats:')}
|
||||
<br />
|
||||
{StatsTable([
|
||||
['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)],
|
||||
], 'Multipliers:')}
|
||||
</>);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{StatsTable(
|
||||
[
|
||||
[
|
||||
"Hacking: ",
|
||||
sleeve.hacking_skill,
|
||||
`(${numeralWrapper.formatExp(sleeve.hacking_exp)} exp)`,
|
||||
],
|
||||
[
|
||||
"Strength: ",
|
||||
sleeve.strength,
|
||||
`(${numeralWrapper.formatExp(sleeve.strength_exp)} exp)`,
|
||||
],
|
||||
[
|
||||
"Defense: ",
|
||||
sleeve.defense,
|
||||
`(${numeralWrapper.formatExp(sleeve.defense_exp)} exp)`,
|
||||
],
|
||||
[
|
||||
"Dexterity: ",
|
||||
sleeve.dexterity,
|
||||
`(${numeralWrapper.formatExp(sleeve.dexterity_exp)} exp)`,
|
||||
],
|
||||
[
|
||||
"Agility: ",
|
||||
sleeve.agility,
|
||||
`(${numeralWrapper.formatExp(sleeve.agility_exp)} exp)`,
|
||||
],
|
||||
[
|
||||
"Charisma: ",
|
||||
sleeve.charisma,
|
||||
`(${numeralWrapper.formatExp(sleeve.charisma_exp)} exp)`,
|
||||
],
|
||||
],
|
||||
"Stats:",
|
||||
)}
|
||||
<br />
|
||||
{StatsTable(
|
||||
[
|
||||
[
|
||||
"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),
|
||||
],
|
||||
],
|
||||
"Multipliers:",
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,56 +3,79 @@ import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import * as React from "react";
|
||||
|
||||
export function StatsElement(sleeve: Sleeve): React.ReactElement {
|
||||
let style = {};
|
||||
style = { textAlign: "right" };
|
||||
return (<>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="character-hp-cell">HP: </td>
|
||||
<td className="character-hp-cell" style={style}>{numeralWrapper.formatHp(sleeve.hp)} / {numeralWrapper.formatHp(sleeve.max_hp)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>City: </td>
|
||||
<td style={style}>{sleeve.city}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-hack-cell">Hacking: </td>
|
||||
<td className="character-hack-cell" style={style}>{numeralWrapper.formatSkill(sleeve.hacking_skill)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Strength: </td>
|
||||
<td className="character-combat-cell" style={style}>{numeralWrapper.formatSkill(sleeve.strength)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Defense: </td>
|
||||
<td className="character-combat-cell" style={style}>{numeralWrapper.formatSkill(sleeve.defense)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Dexterity: </td>
|
||||
<td className="character-combat-cell" style={style}>{numeralWrapper.formatSkill(sleeve.dexterity)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Agility: </td>
|
||||
<td className="character-combat-cell" style={style}>{numeralWrapper.formatSkill(sleeve.agility)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-cha-cell">Charisma: </td>
|
||||
<td className="character-cha-cell" style={style}>{numeralWrapper.formatSkill(sleeve.charisma)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-int-cell">Shock: </td>
|
||||
<td className="character-int-cell" style={style}>{numeralWrapper.formatSleeveShock(100 - sleeve.shock)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-int-cell">Sync: </td>
|
||||
<td className="character-int-cell" style={style}>{numeralWrapper.formatSleeveSynchro(sleeve.sync)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-int-cell">Memory: </td>
|
||||
<td className="character-int-cell" style={style}>{numeralWrapper.formatSleeveMemory(sleeve.memory)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</>)
|
||||
let style = {};
|
||||
style = { textAlign: "right" };
|
||||
return (
|
||||
<>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="character-hp-cell">HP: </td>
|
||||
<td className="character-hp-cell" style={style}>
|
||||
{numeralWrapper.formatHp(sleeve.hp)} /{" "}
|
||||
{numeralWrapper.formatHp(sleeve.max_hp)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>City: </td>
|
||||
<td style={style}>{sleeve.city}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-hack-cell">Hacking: </td>
|
||||
<td className="character-hack-cell" style={style}>
|
||||
{numeralWrapper.formatSkill(sleeve.hacking_skill)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Strength: </td>
|
||||
<td className="character-combat-cell" style={style}>
|
||||
{numeralWrapper.formatSkill(sleeve.strength)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Defense: </td>
|
||||
<td className="character-combat-cell" style={style}>
|
||||
{numeralWrapper.formatSkill(sleeve.defense)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Dexterity: </td>
|
||||
<td className="character-combat-cell" style={style}>
|
||||
{numeralWrapper.formatSkill(sleeve.dexterity)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-combat-cell">Agility: </td>
|
||||
<td className="character-combat-cell" style={style}>
|
||||
{numeralWrapper.formatSkill(sleeve.agility)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-cha-cell">Charisma: </td>
|
||||
<td className="character-cha-cell" style={style}>
|
||||
{numeralWrapper.formatSkill(sleeve.charisma)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-int-cell">Shock: </td>
|
||||
<td className="character-int-cell" style={style}>
|
||||
{numeralWrapper.formatSleeveShock(100 - sleeve.shock)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-int-cell">Sync: </td>
|
||||
<td className="character-int-cell" style={style}>
|
||||
{numeralWrapper.formatSleeveSynchro(sleeve.sync)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="character-int-cell">Memory: </td>
|
||||
<td className="character-int-cell" style={style}>
|
||||
{numeralWrapper.formatSleeveMemory(sleeve.memory)}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
export function calculateIntelligenceBonus(intelligence: number, weight = 1): number {
|
||||
return 1+(weight*Math.pow(intelligence, 0.8)/600);
|
||||
}
|
||||
export function calculateIntelligenceBonus(
|
||||
intelligence: number,
|
||||
weight = 1,
|
||||
): number {
|
||||
return 1 + (weight * Math.pow(intelligence, 0.8)) / 600;
|
||||
}
|
||||
|
||||
@@ -1,37 +1,48 @@
|
||||
import { IPlayer } from '../IPlayer';
|
||||
import { Faction } from '../../Faction/Faction';
|
||||
import { CONSTANTS } from '../../Constants';
|
||||
import { BitNodeMultipliers } from '../../BitNode/BitNodeMultipliers';
|
||||
import { IPlayer } from "../IPlayer";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
|
||||
function mult(f: Faction): number {
|
||||
let favorMult = 1 + (f.favor / 100);
|
||||
if (isNaN(favorMult)) {favorMult = 1;}
|
||||
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
|
||||
let favorMult = 1 + f.favor / 100;
|
||||
if (isNaN(favorMult)) {
|
||||
favorMult = 1;
|
||||
}
|
||||
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
|
||||
}
|
||||
|
||||
export function getHackingWorkRepGain(p: IPlayer, f: Faction): number {
|
||||
return (p.hacking_skill + p.intelligence/3) /
|
||||
CONSTANTS.MaxSkillLevel * p.faction_rep_mult *
|
||||
p.getIntelligenceBonus(1) * mult(f);
|
||||
return (
|
||||
((p.hacking_skill + p.intelligence / 3) / CONSTANTS.MaxSkillLevel) *
|
||||
p.faction_rep_mult *
|
||||
p.getIntelligenceBonus(1) *
|
||||
mult(f)
|
||||
);
|
||||
}
|
||||
|
||||
export function getFactionSecurityWorkRepGain(p: IPlayer, f: Faction): number {
|
||||
const t = 0.9 * (p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
p.strength / CONSTANTS.MaxSkillLevel +
|
||||
p.defense / CONSTANTS.MaxSkillLevel +
|
||||
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
p.agility / CONSTANTS.MaxSkillLevel +
|
||||
p.intelligence / CONSTANTS.MaxSkillLevel) / 4.5;
|
||||
return t * p.faction_rep_mult * mult(f) * p.getIntelligenceBonus(1);
|
||||
const t =
|
||||
(0.9 *
|
||||
(p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
p.strength / CONSTANTS.MaxSkillLevel +
|
||||
p.defense / CONSTANTS.MaxSkillLevel +
|
||||
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
p.agility / CONSTANTS.MaxSkillLevel +
|
||||
p.intelligence / CONSTANTS.MaxSkillLevel)) /
|
||||
4.5;
|
||||
return t * p.faction_rep_mult * mult(f) * p.getIntelligenceBonus(1);
|
||||
}
|
||||
|
||||
export function getFactionFieldWorkRepGain(p: IPlayer, f: Faction): number {
|
||||
const t = 0.9 * (p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
p.strength / CONSTANTS.MaxSkillLevel +
|
||||
p.defense / CONSTANTS.MaxSkillLevel +
|
||||
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
p.agility / CONSTANTS.MaxSkillLevel +
|
||||
p.charisma / CONSTANTS.MaxSkillLevel +
|
||||
p.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
||||
return t * p.faction_rep_mult * mult(f) * p.getIntelligenceBonus(1);
|
||||
const t =
|
||||
(0.9 *
|
||||
(p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||
p.strength / CONSTANTS.MaxSkillLevel +
|
||||
p.defense / CONSTANTS.MaxSkillLevel +
|
||||
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||
p.agility / CONSTANTS.MaxSkillLevel +
|
||||
p.charisma / CONSTANTS.MaxSkillLevel +
|
||||
p.intelligence / CONSTANTS.MaxSkillLevel)) /
|
||||
5.5;
|
||||
return t * p.faction_rep_mult * mult(f) * p.getIntelligenceBonus(1);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export function calculateSkill(exp: number, mult = 1): number {
|
||||
return Math.max(Math.floor(mult*(32 * Math.log(exp + 534.5) - 200)), 1);
|
||||
return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1);
|
||||
}
|
||||
|
||||
export function calculateExp(skill: number, mult = 1): number {
|
||||
return Math.exp((skill / mult + 200) / 32) - 534.6
|
||||
}
|
||||
return Math.exp((skill / mult + 200) / 32) - 534.6;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user