prettify, sorry for the big ass commit

This commit is contained in:
Olivier Gagnon
2021-09-04 19:09:30 -04:00
parent 3d7cdb4ef9
commit a18bdd6afc
554 changed files with 91615 additions and 66138 deletions
+180 -175
View File
@@ -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;
}
+18 -18
View File
@@ -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
View File
@@ -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);
}
}
+161 -161
View File
@@ -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;
}
+55 -44
View File
@@ -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;
+93 -83
View File
@@ -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;
}
+475 -321
View File
@@ -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;
}
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),
});
}
+66 -43
View File
@@ -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
+106 -70
View File
@@ -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 />
</>
);
}
+114 -31
View File
@@ -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:",
)}
</>
);
}
+75 -52
View File
@@ -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>
</>
);
}
+6 -3
View File
@@ -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;
}
+36 -25
View File
@@ -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);
}
+3 -3
View File
@@ -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;
}