2018-12-07 11:54:26 +01:00
|
|
|
/**
|
2019-01-10 09:20:04 +01:00
|
|
|
* Sleeves are bodies that contain the player's cloned consciousness.
|
|
|
|
* The player can use these bodies to perform different tasks synchronously.
|
2018-12-07 11:54:26 +01:00
|
|
|
*
|
|
|
|
* Each sleeve is its own individual, meaning it has its own stats/exp
|
|
|
|
*
|
|
|
|
* Sleeves are unlocked in BitNode-10.
|
|
|
|
*/
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
import { Player } from "../../Player";
|
2022-04-14 17:40:59 +02:00
|
|
|
import { Person } from "../Person";
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2019-02-26 09:51:48 +01:00
|
|
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
|
|
|
|
2019-01-15 04:34:04 +01:00
|
|
|
import { Crime } from "../../Crime/Crime";
|
2019-01-30 07:02:27 +01:00
|
|
|
import { Crimes } from "../../Crime/Crimes";
|
2019-01-15 04:34:04 +01:00
|
|
|
|
2018-12-07 11:54:26 +01:00
|
|
|
import { Companies } from "../../Company/Companies";
|
|
|
|
import { Company } from "../../Company/Company";
|
2019-01-15 04:34:04 +01:00
|
|
|
import { CompanyPosition } from "../../Company/CompanyPosition";
|
|
|
|
import { CompanyPositions } from "../../Company/CompanyPositions";
|
|
|
|
|
2022-08-30 15:26:24 +02:00
|
|
|
import { Contracts } from "../../Bladeburner/data/Contracts";
|
|
|
|
|
2018-12-07 11:54:26 +01:00
|
|
|
import { CONSTANTS } from "../../Constants";
|
2019-01-15 04:34:04 +01:00
|
|
|
|
2018-12-07 11:54:26 +01:00
|
|
|
import { Faction } from "../../Faction/Faction";
|
|
|
|
import { Factions } from "../../Faction/Factions";
|
2019-01-15 04:34:04 +01:00
|
|
|
|
2019-04-01 11:23:25 +02:00
|
|
|
import { CityName } from "../../Locations/data/CityNames";
|
|
|
|
import { LocationName } from "../../Locations/data/LocationNames";
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2022-07-15 01:00:10 +02:00
|
|
|
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../utils/JSONReviver";
|
2022-04-30 21:25:36 +02:00
|
|
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
2022-07-12 07:54:19 +02:00
|
|
|
import { FactionWorkType } from "../../Work/data/FactionWorkType";
|
2022-07-28 02:37:32 +02:00
|
|
|
import { Work } from "./Work/Work";
|
|
|
|
import { SleeveClassWork } from "./Work/SleeveClassWork";
|
|
|
|
import { ClassType } from "../../Work/ClassWork";
|
|
|
|
import { SleeveSynchroWork } from "./Work/SleeveSynchroWork";
|
|
|
|
import { SleeveRecoveryWork } from "./Work/SleeveRecoveryWork";
|
|
|
|
import { SleeveFactionWork } from "./Work/SleeveFactionWork";
|
|
|
|
import { SleeveCompanyWork } from "./Work/SleeveCompanyWork";
|
|
|
|
import { SleeveInfiltrateWork } from "./Work/SleeveInfiltrateWork";
|
2022-07-28 08:46:34 +02:00
|
|
|
import { SleeveSupportWork } from "./Work/SleeveSupportWork";
|
|
|
|
import { SleeveBladeburnerWork } from "./Work/SleeveBladeburnerWork";
|
|
|
|
import { SleeveCrimeWork } from "./Work/SleeveCrimeWork";
|
2022-09-20 06:40:07 +02:00
|
|
|
import * as sleeveMethods from "./SleeveMethods";
|
2018-12-07 11:54:26 +01:00
|
|
|
|
|
|
|
export class Sleeve extends Person {
|
2022-07-28 02:37:32 +02:00
|
|
|
currentWork: Work | null = null;
|
2022-04-14 17:40:59 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
/**
|
|
|
|
* Clone retains 'memory' synchronization (and maybe exp?) upon prestige/installing Augs
|
|
|
|
*/
|
|
|
|
memory = 1;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sleeve shock. Number between 0 and 100
|
|
|
|
* Trauma/shock that comes with being in a sleeve. Experience earned
|
|
|
|
* is multipled by shock%. This gets applied before synchronization
|
|
|
|
*
|
|
|
|
* Reputation earned is also multiplied by shock%
|
|
|
|
*/
|
|
|
|
shock = 1;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stored number of game "loop" cycles
|
|
|
|
*/
|
|
|
|
storedCycles = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Synchronization. Number between 0 and 100
|
|
|
|
* When experience is earned by sleeve, both the player and the sleeve get
|
2022-07-28 20:35:55 +02:00
|
|
|
* sync% of the experience earned.
|
2021-09-05 01:09:30 +02:00
|
|
|
*/
|
|
|
|
sync = 1;
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
constructor() {
|
2021-09-05 01:09:30 +02:00
|
|
|
super();
|
2022-09-06 15:07:12 +02:00
|
|
|
this.shockRecovery();
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
|
2022-09-20 07:57:46 +02:00
|
|
|
applyAugmentation = sleeveMethods.applyAugmentation;
|
2022-09-20 06:40:07 +02:00
|
|
|
findPurchasableAugs = sleeveMethods.findPurchasableAugs;
|
|
|
|
|
2022-07-28 02:37:32 +02:00
|
|
|
shockBonus(): number {
|
|
|
|
return this.shock / 100;
|
|
|
|
}
|
2022-07-28 20:35:55 +02:00
|
|
|
|
2022-07-28 02:37:32 +02:00
|
|
|
syncBonus(): number {
|
|
|
|
return this.sync / 100;
|
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
startWork(w: Work): void {
|
|
|
|
if (this.currentWork) this.currentWork.finish();
|
2022-07-28 08:46:34 +02:00
|
|
|
this.currentWork = w;
|
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
stopWork(): void {
|
|
|
|
if (this.currentWork) this.currentWork.finish();
|
2022-07-28 08:46:34 +02:00
|
|
|
this.currentWork = null;
|
|
|
|
}
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
/**
|
|
|
|
* Commit crimes
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
commitCrime(crimeKey: string): boolean {
|
2021-10-18 20:59:18 +02:00
|
|
|
const crime: Crime | null = Crimes[crimeKey] || Object.values(Crimes).find((crime) => crime.name === crimeKey);
|
|
|
|
if (!crime) {
|
2021-09-05 01:09:30 +02:00
|
|
|
return false;
|
2018-12-07 11:54:26 +01:00
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveCrimeWork(crime.type));
|
2021-09-05 01:09:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the cost of upgrading this sleeve's memory by a certain amount
|
|
|
|
*/
|
|
|
|
getMemoryUpgradeCost(n: number): number {
|
|
|
|
const amt = Math.round(n);
|
|
|
|
if (amt < 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (this.memory + amt > 100) {
|
|
|
|
return this.getMemoryUpgradeCost(100 - this.memory);
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
const mult = 1.02;
|
|
|
|
const baseCost = 1e12;
|
|
|
|
let currCost = 0;
|
|
|
|
let currMemory = this.memory - 1;
|
|
|
|
for (let i = 0; i < n; ++i) {
|
|
|
|
currCost += Math.pow(mult, currMemory);
|
|
|
|
++currMemory;
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
return currCost * baseCost;
|
|
|
|
}
|
|
|
|
|
|
|
|
installAugmentation(aug: Augmentation): void {
|
2022-07-27 05:54:17 +02:00
|
|
|
this.exp.hacking = 0;
|
|
|
|
this.exp.strength = 0;
|
|
|
|
this.exp.defense = 0;
|
|
|
|
this.exp.dexterity = 0;
|
|
|
|
this.exp.agility = 0;
|
|
|
|
this.exp.charisma = 0;
|
2021-09-05 01:09:30 +02:00
|
|
|
this.applyAugmentation(aug);
|
|
|
|
this.augmentations.push({ name: aug.name, level: 1 });
|
2022-09-20 07:57:46 +02:00
|
|
|
this.updateSkillLevels();
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-02-03 14:50:08 +01:00
|
|
|
* Called on every sleeve for a Source File Prestige
|
2021-09-05 01:09:30 +02:00
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
prestige(): void {
|
2021-09-05 01:09:30 +02:00
|
|
|
// Reset exp
|
2022-07-27 05:54:17 +02:00
|
|
|
this.exp.hacking = 0;
|
|
|
|
this.exp.strength = 0;
|
|
|
|
this.exp.defense = 0;
|
|
|
|
this.exp.dexterity = 0;
|
|
|
|
this.exp.agility = 0;
|
|
|
|
this.exp.charisma = 0;
|
2022-09-20 07:57:46 +02:00
|
|
|
this.updateSkillLevels();
|
2022-09-11 02:44:50 +02:00
|
|
|
this.hp.current = this.hp.max;
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
// Reset task-related stuff
|
2022-09-06 15:07:12 +02:00
|
|
|
this.stopWork();
|
|
|
|
this.shockRecovery();
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
// Reset augs and multipliers
|
|
|
|
this.augmentations = [];
|
|
|
|
this.resetMultipliers();
|
2022-03-05 06:56:11 +01:00
|
|
|
|
2022-02-03 14:50:08 +01:00
|
|
|
// Reset Location
|
2022-03-05 06:56:11 +01:00
|
|
|
|
|
|
|
this.city = CityName.Sector12;
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Reset sleeve-related stats
|
|
|
|
this.shock = 1;
|
|
|
|
this.storedCycles = 0;
|
|
|
|
this.sync = Math.max(this.memory, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process loop
|
|
|
|
* Returns an object containing the amount of experience that should be
|
|
|
|
* transferred to all other sleeves
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
process(numCycles = 1): void {
|
2021-09-05 01:09:30 +02:00
|
|
|
// Only process once every second (5 cycles)
|
|
|
|
const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle;
|
|
|
|
this.storedCycles += numCycles;
|
2022-07-28 02:37:32 +02:00
|
|
|
if (this.storedCycles < CyclesPerSecond) return;
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
let cyclesUsed = this.storedCycles;
|
2021-09-25 05:02:27 +02:00
|
|
|
cyclesUsed = Math.min(cyclesUsed, 15);
|
2021-09-10 03:38:05 +02:00
|
|
|
this.shock = Math.min(100, this.shock + 0.0001 * cyclesUsed);
|
2022-07-28 20:35:55 +02:00
|
|
|
if (!this.currentWork) return;
|
2022-09-06 15:07:12 +02:00
|
|
|
this.currentWork.process(this, cyclesUsed);
|
2021-09-05 01:09:30 +02:00
|
|
|
this.storedCycles -= cyclesUsed;
|
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
shockRecovery(): boolean {
|
|
|
|
this.startWork(new SleeveRecoveryWork());
|
2021-09-05 01:09:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
2019-03-27 09:36:14 +01:00
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
synchronize(): boolean {
|
|
|
|
this.startWork(new SleeveSynchroWork());
|
2021-09-05 01:09:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Take a course at a university
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
takeUniversityCourse(universityName: string, className: string): boolean {
|
2021-09-05 01:09:30 +02:00
|
|
|
// Set exp/money multipliers based on which university.
|
|
|
|
// Also check that the sleeve is in the right city
|
2022-07-28 02:37:32 +02:00
|
|
|
let loc: LocationName | undefined;
|
2021-09-05 01:09:30 +02:00
|
|
|
switch (universityName.toLowerCase()) {
|
2022-07-28 02:37:32 +02:00
|
|
|
case LocationName.AevumSummitUniversity.toLowerCase(): {
|
|
|
|
if (this.city !== CityName.Aevum) return false;
|
|
|
|
loc = LocationName.AevumSummitUniversity;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
|
|
|
case LocationName.Sector12RothmanUniversity.toLowerCase(): {
|
|
|
|
if (this.city !== CityName.Sector12) return false;
|
|
|
|
loc = LocationName.Sector12RothmanUniversity;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
|
|
|
case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): {
|
|
|
|
if (this.city !== CityName.Volhaven) return false;
|
|
|
|
loc = LocationName.VolhavenZBInstituteOfTechnology;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!loc) return false;
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Set experience/money gains based on class
|
2022-07-28 02:37:32 +02:00
|
|
|
let classType: ClassType | undefined;
|
2021-09-05 01:09:30 +02:00
|
|
|
switch (className.toLowerCase()) {
|
|
|
|
case "study computer science":
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.StudyComputerScience;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
|
|
|
case "data structures":
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.DataStructures;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
|
|
|
case "networks":
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.Networks;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
|
|
|
case "algorithms":
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.Algorithms;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
|
|
|
case "management":
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.Management;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
|
|
|
case "leadership":
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.Leadership;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!classType) return false;
|
2019-01-20 23:57:38 +01:00
|
|
|
|
2022-07-28 08:46:34 +02:00
|
|
|
this.startWork(
|
|
|
|
new SleeveClassWork({
|
|
|
|
classType: classType,
|
|
|
|
location: loc,
|
|
|
|
}),
|
|
|
|
);
|
2021-09-05 01:09:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
/**
|
|
|
|
* Travel to another City. Costs money from player
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
travel(newCity: CityName): boolean {
|
|
|
|
Player.loseMoney(CONSTANTS.TravelCost, "sleeves");
|
2021-09-05 01:09:30 +02:00
|
|
|
this.city = newCity;
|
2019-01-15 04:34:04 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2022-09-23 18:04:21 +02:00
|
|
|
hasAugmentation(aug: string): boolean {
|
|
|
|
return this.augmentations.some((a) => a.name === aug);
|
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
tryBuyAugmentation(aug: Augmentation): boolean {
|
|
|
|
if (!Player.canAfford(aug.baseCost)) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Verify that this sleeve does not already have that augmentation.
|
2022-09-23 18:04:21 +02:00
|
|
|
if (this.hasAugmentation(aug.name)) return false;
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
Player.loseMoney(aug.baseCost, "sleeves");
|
2021-09-05 01:09:30 +02:00
|
|
|
this.installAugmentation(aug);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
upgradeMemory(n: number): void {
|
|
|
|
this.memory = Math.min(100, Math.round(this.memory + n));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start work for one of the player's companies
|
|
|
|
* Returns boolean indicating success
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
workForCompany(companyName: string): boolean {
|
|
|
|
if (!(Companies[companyName] instanceof Company) || Player.jobs[companyName] == null) {
|
2021-09-05 01:09:30 +02:00
|
|
|
return false;
|
2018-12-07 11:54:26 +01:00
|
|
|
}
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
const company: Company | null = Companies[companyName];
|
2022-09-06 15:07:12 +02:00
|
|
|
const companyPosition: CompanyPosition | null = CompanyPositions[Player.jobs[companyName]];
|
2022-07-28 02:37:32 +02:00
|
|
|
if (company == null) return false;
|
|
|
|
if (companyPosition == null) return false;
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveCompanyWork({ companyName: companyName }));
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start work for one of the player's factions
|
|
|
|
* Returns boolean indicating success
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
workForFaction(factionName: string, workType: string): boolean {
|
2022-04-07 01:30:08 +02:00
|
|
|
const faction = Factions[factionName];
|
2022-09-06 15:07:12 +02:00
|
|
|
if (factionName === "" || !faction || !(faction instanceof Faction) || !Player.factions.includes(factionName)) {
|
2021-09-05 01:09:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-07-16 06:40:13 +02:00
|
|
|
|
2022-03-05 06:56:11 +01:00
|
|
|
const factionInfo = faction.getInfo();
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
// Set type of work (hacking/field/security), and the experience gains
|
2022-07-28 02:37:32 +02:00
|
|
|
const sanitizedWorkType = workType.toLowerCase();
|
|
|
|
let factionWorkType: FactionWorkType;
|
2021-09-05 01:09:30 +02:00
|
|
|
if (sanitizedWorkType.includes("hack")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!factionInfo.offerHackingWork) return false;
|
|
|
|
factionWorkType = FactionWorkType.HACKING;
|
2021-09-05 01:09:30 +02:00
|
|
|
} else if (sanitizedWorkType.includes("field")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!factionInfo.offerFieldWork) return false;
|
|
|
|
factionWorkType = FactionWorkType.FIELD;
|
2021-09-05 01:09:30 +02:00
|
|
|
} else if (sanitizedWorkType.includes("security")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!factionInfo.offerSecurityWork) return false;
|
|
|
|
factionWorkType = FactionWorkType.SECURITY;
|
2021-09-05 01:09:30 +02:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-16 06:40:13 +02:00
|
|
|
|
2022-07-28 08:46:34 +02:00
|
|
|
this.startWork(
|
|
|
|
new SleeveFactionWork({
|
|
|
|
factionWorkType: factionWorkType,
|
|
|
|
factionName: faction.name,
|
|
|
|
}),
|
|
|
|
);
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Begin a gym workout task
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
workoutAtGym(gymName: string, stat: string): boolean {
|
2021-09-05 01:09:30 +02:00
|
|
|
// Set exp/money multipliers based on which university.
|
|
|
|
// Also check that the sleeve is in the right city
|
2022-07-28 02:37:32 +02:00
|
|
|
let loc: LocationName | undefined;
|
2021-09-05 01:09:30 +02:00
|
|
|
switch (gymName.toLowerCase()) {
|
2022-07-28 02:37:32 +02:00
|
|
|
case LocationName.AevumCrushFitnessGym.toLowerCase(): {
|
|
|
|
if (this.city != CityName.Aevum) return false;
|
|
|
|
loc = LocationName.AevumCrushFitnessGym;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
|
|
|
case LocationName.AevumSnapFitnessGym.toLowerCase(): {
|
|
|
|
if (this.city != CityName.Aevum) return false;
|
|
|
|
loc = LocationName.AevumSnapFitnessGym;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
|
|
|
case LocationName.Sector12IronGym.toLowerCase(): {
|
|
|
|
if (this.city != CityName.Sector12) return false;
|
|
|
|
loc = LocationName.Sector12IronGym;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
|
|
|
case LocationName.Sector12PowerhouseGym.toLowerCase(): {
|
|
|
|
if (this.city != CityName.Sector12) return false;
|
|
|
|
loc = LocationName.Sector12PowerhouseGym;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
|
|
|
case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): {
|
|
|
|
if (this.city != CityName.Volhaven) return false;
|
|
|
|
loc = LocationName.VolhavenMilleniumFitnessGym;
|
2021-09-05 01:09:30 +02:00
|
|
|
break;
|
2022-07-28 02:37:32 +02:00
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
}
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!loc) return false;
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Set experience/money gains based on class
|
|
|
|
const sanitizedStat: string = stat.toLowerCase();
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2022-05-23 20:03:13 +02:00
|
|
|
// set stat to a default value.
|
2022-07-28 02:37:32 +02:00
|
|
|
let classType: ClassType | undefined;
|
2022-05-23 20:03:13 +02:00
|
|
|
if (sanitizedStat.includes("str")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.GymStrength;
|
2022-05-23 20:03:13 +02:00
|
|
|
}
|
|
|
|
if (sanitizedStat.includes("def")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.GymDefense;
|
2022-05-23 20:03:13 +02:00
|
|
|
}
|
|
|
|
if (sanitizedStat.includes("dex")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.GymDexterity;
|
2022-05-23 20:03:13 +02:00
|
|
|
}
|
|
|
|
if (sanitizedStat.includes("agi")) {
|
2022-07-28 02:37:32 +02:00
|
|
|
classType = ClassType.GymAgility;
|
2022-05-23 20:03:13 +02:00
|
|
|
}
|
|
|
|
// if stat is still equals its default value, then validation has failed.
|
2022-07-28 02:37:32 +02:00
|
|
|
if (!classType) return false;
|
2018-12-07 11:54:26 +01:00
|
|
|
|
2022-07-28 08:46:34 +02:00
|
|
|
this.startWork(
|
|
|
|
new SleeveClassWork({
|
|
|
|
classType: classType,
|
|
|
|
location: loc,
|
|
|
|
}),
|
|
|
|
);
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-04-14 17:40:59 +02:00
|
|
|
/**
|
|
|
|
* Begin a bladeburner task
|
|
|
|
*/
|
2022-09-06 15:07:12 +02:00
|
|
|
bladeburner(action: string, contract: string): boolean {
|
2022-04-14 17:40:59 +02:00
|
|
|
switch (action) {
|
2022-04-30 21:25:36 +02:00
|
|
|
case "Field analysis":
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Field Analysis" }));
|
2022-07-28 02:37:32 +02:00
|
|
|
return true;
|
2022-04-14 17:40:59 +02:00
|
|
|
case "Recruitment":
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Recruitment" }));
|
2022-07-28 08:46:34 +02:00
|
|
|
return true;
|
2022-04-14 17:40:59 +02:00
|
|
|
case "Diplomacy":
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Diplomacy" }));
|
2022-07-28 08:46:34 +02:00
|
|
|
return true;
|
2022-09-11 02:39:40 +02:00
|
|
|
case "Hyperbolic Regeneration Chamber":
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Hyperbolic Regeneration Chamber" }));
|
2022-09-11 02:39:40 +02:00
|
|
|
return true;
|
2022-04-14 17:40:59 +02:00
|
|
|
case "Infiltrate synthoids":
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveInfiltrateWork());
|
2022-07-28 08:46:34 +02:00
|
|
|
return true;
|
2022-04-14 17:40:59 +02:00
|
|
|
case "Support main sleeve":
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveSupportWork());
|
2022-07-28 08:46:34 +02:00
|
|
|
return true;
|
2022-04-30 21:25:36 +02:00
|
|
|
case "Take on contracts":
|
2022-08-30 15:26:24 +02:00
|
|
|
if (!Contracts[contract]) return false;
|
2022-09-06 15:07:12 +02:00
|
|
|
this.startWork(new SleeveBladeburnerWork({ type: "Contracts", name: contract }));
|
2022-07-28 08:46:34 +02:00
|
|
|
return true;
|
2022-04-14 17:40:59 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 15:26:24 +02:00
|
|
|
return false;
|
2022-04-14 17:40:59 +02:00
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
recruitmentSuccessChance(): number {
|
|
|
|
return Math.max(0, Math.min(1, Player.bladeburner?.getRecruitmentSuccessChance(this) ?? 0));
|
2022-04-30 21:25:36 +02:00
|
|
|
}
|
|
|
|
|
2022-09-06 15:07:12 +02:00
|
|
|
contractSuccessChance(type: string, name: string): string {
|
|
|
|
const bb = Player.bladeburner;
|
2022-04-14 18:00:17 +02:00
|
|
|
if (bb === null) {
|
2022-04-14 17:40:59 +02:00
|
|
|
const errorLogText = `bladeburner is null`;
|
2022-04-14 18:00:17 +02:00
|
|
|
console.error(`Function: sleeves.contractSuccessChance; Message: '${errorLogText}'`);
|
|
|
|
return "0%";
|
2022-04-14 17:40:59 +02:00
|
|
|
}
|
|
|
|
const chances = bb.getActionEstimatedSuccessChanceNetscriptFn(this, type, name);
|
2022-04-14 18:00:17 +02:00
|
|
|
if (typeof chances === "string") {
|
|
|
|
console.error(`Function: sleeves.contractSuccessChance; Message: '${chances}'`);
|
|
|
|
return "0%";
|
2022-04-14 17:40:59 +02:00
|
|
|
}
|
2022-04-14 18:00:17 +02:00
|
|
|
if (chances[0] >= 1) {
|
|
|
|
return "100%";
|
2022-04-14 17:40:59 +02:00
|
|
|
} else {
|
2022-04-30 21:25:36 +02:00
|
|
|
return `${numeralWrapper.formatPercentage(chances[0])} - ${numeralWrapper.formatPercentage(chances[1])}`;
|
2022-04-14 17:40:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 18:00:17 +02:00
|
|
|
takeDamage(amt: number): boolean {
|
2022-04-14 17:40:59 +02:00
|
|
|
if (typeof amt !== "number") {
|
|
|
|
console.warn(`Player.takeDamage() called without a numeric argument: ${amt}`);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-07-27 05:54:17 +02:00
|
|
|
this.hp.current -= amt;
|
|
|
|
if (this.hp.current <= 0) {
|
2022-08-25 17:49:01 +02:00
|
|
|
this.shock = Math.max(0, this.shock - 0.5);
|
2022-07-27 05:54:17 +02:00
|
|
|
this.hp.current = this.hp.max;
|
2022-04-14 17:40:59 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
whoAmI(): string {
|
2022-04-14 18:00:17 +02:00
|
|
|
return "Sleeve";
|
2022-04-14 17:40:59 +02:00
|
|
|
}
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
/**
|
|
|
|
* Serialize the current object to a JSON save state.
|
|
|
|
*/
|
2022-07-15 01:00:10 +02:00
|
|
|
toJSON(): IReviverValue {
|
2021-09-05 01:09:30 +02:00
|
|
|
return Generic_toJSON("Sleeve", this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initiatizes a Sleeve object from a JSON save state.
|
|
|
|
*/
|
2022-07-15 01:00:10 +02:00
|
|
|
static fromJSON(value: IReviverValue): Sleeve {
|
2021-09-05 01:09:30 +02:00
|
|
|
return Generic_fromJSON(Sleeve, value.data);
|
|
|
|
}
|
2018-12-07 11:54:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Reviver.constructors.Sleeve = Sleeve;
|