mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-01-11 15:57:33 +01:00
Convert Locations and Faction implementations to TypeScript. Also restructed directory. Implemented Sleeve, but untested
This commit is contained in:
parent
8fcb1706cc
commit
48c694c9c1
58892
dist/engine.bundle.js
vendored
58892
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
111048
dist/vendor.bundle.js
vendored
111048
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Bitburner</title>
|
<title>Bitburner - development</title>
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
|
||||||
@ -474,7 +474,8 @@
|
|||||||
|
|
||||||
<!-- Tutorial content -->
|
<!-- Tutorial content -->
|
||||||
<div id="tutorial-container" class="generic-menupage-container">
|
<div id="tutorial-container" class="generic-menupage-container">
|
||||||
<a id="tutorial-getting-started-link" class="a-link-button" href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
|
<a id="tutorial-getting-started-link" class="a-link-button"
|
||||||
|
href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
|
||||||
<a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a>
|
<a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a>
|
||||||
<a id="tutorial-hacking-link" class="a-link-button"> Hacking </a>
|
<a id="tutorial-hacking-link" class="a-link-button"> Hacking </a>
|
||||||
<a id="tutorial-scripts-link" class="a-link-button"> Scripts </a>
|
<a id="tutorial-scripts-link" class="a-link-button"> Scripts </a>
|
||||||
@ -483,7 +484,8 @@
|
|||||||
<a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a>
|
<a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a>
|
||||||
<a id="tutorial-factions-link" class="a-link-button"> Factions </a>
|
<a id="tutorial-factions-link" class="a-link-button"> Factions </a>
|
||||||
<a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a>
|
<a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a>
|
||||||
<a id="tutorial-shortcuts-link" class="a-link-button" href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
|
<a id="tutorial-shortcuts-link" class="a-link-button"
|
||||||
|
href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
|
||||||
|
|
||||||
<a id="tutorial-back-button" class="a-link-button"> Back </a>
|
<a id="tutorial-back-button" class="a-link-button"> Back </a>
|
||||||
<p id="tutorial-text"> </p>
|
<p id="tutorial-text"> </p>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import { Engine } from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {Factions, factionExists} from "./Faction";
|
import { Factions,
|
||||||
|
factionExists } from "./Faction/Factions";
|
||||||
import { hasBladeburnerSF } from "./NetscriptFunctions";
|
import { hasBladeburnerSF } from "./NetscriptFunctions";
|
||||||
import { addWorkerScript } from "./NetscriptWorker";
|
import { addWorkerScript } from "./NetscriptWorker";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
@ -1569,13 +1570,13 @@ function initAugmentations() {
|
|||||||
//Do this before adding special Augmentations that become available in later BitNodes
|
//Do this before adding special Augmentations that become available in later BitNodes
|
||||||
if (Player.bitNodeN === 2) {
|
if (Player.bitNodeN === 2) {
|
||||||
console.log("Adding all augmentations to crime factions for Bit node 2");
|
console.log("Adding all augmentations to crime factions for Bit node 2");
|
||||||
Factions["Slum Snakes"].addAllAugmentations();
|
Factions["Slum Snakes"].addAllAugmentations(Augmentations);
|
||||||
Factions["Tetrads"].addAllAugmentations();
|
Factions["Tetrads"].addAllAugmentations(Augmentations);
|
||||||
Factions["The Syndicate"].addAllAugmentations();
|
Factions["The Syndicate"].addAllAugmentations(Augmentations);
|
||||||
Factions["The Dark Army"].addAllAugmentations();
|
Factions["The Dark Army"].addAllAugmentations(Augmentations);
|
||||||
Factions["Speakers for the Dead"].addAllAugmentations();
|
Factions["Speakers for the Dead"].addAllAugmentations(Augmentations);
|
||||||
Factions["NiteSec"].addAllAugmentations();
|
Factions["NiteSec"].addAllAugmentations(Augmentations);
|
||||||
Factions["The Black Hand"].addAllAugmentations();
|
Factions["The Black Hand"].addAllAugmentations(Augmentations);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Special Bladeburner Augmentations
|
//Special Bladeburner Augmentations
|
||||||
|
@ -2,8 +2,9 @@ import {Augmentations, AugmentationNames} from "./Augmentations";
|
|||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import { Engine } from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {Faction, Factions, factionExists,
|
import { Faction } from "./Faction/Faction";
|
||||||
joinFaction, displayFactionContent} from "./Faction";
|
import { Factions, factionExists } from "./Faction/Factions";
|
||||||
|
import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers";
|
||||||
import { Locations } from "./Locations";
|
import { Locations } from "./Locations";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { hackWorldDaemon, redPillFlag } from "./RedPill";
|
import { hackWorldDaemon, redPillFlag } from "./RedPill";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { CodingContract,
|
import { CodingContract,
|
||||||
CodingContractRewardType,
|
CodingContractRewardType,
|
||||||
CodingContractTypes } from "./CodingContracts";
|
CodingContractTypes } from "./CodingContracts";
|
||||||
import {Factions} from "./Faction";
|
import { Factions } from "./Faction/Factions";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { GetServerByHostname,
|
import { GetServerByHostname,
|
||||||
AllServers } from "./Server";
|
AllServers } from "./Server";
|
||||||
|
@ -125,7 +125,7 @@ export class Company {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize the current file to a JSON save state.
|
* Serialize the current object to a JSON save state.
|
||||||
*/
|
*/
|
||||||
toJSON(): any {
|
toJSON(): any {
|
||||||
return Generic_toJSON("Company", this);
|
return Generic_toJSON("Company", this);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
||||||
import {Factions} from "./Faction";
|
import { Factions } from "./Faction/Factions";
|
||||||
import { showLiterature } from "./Literature";
|
import { showLiterature } from "./Literature";
|
||||||
import { Locations } from "./Locations";
|
import { Locations } from "./Locations";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
@ -19,11 +19,16 @@ import {getRandomInt} from "../utils/helpers/g
|
|||||||
import { isString } from "../utils/helpers/isString";
|
import { isString } from "../utils/helpers/isString";
|
||||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
|
import { yesNoBoxCreate,
|
||||||
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
|
yesNoTxtInpBoxCreate,
|
||||||
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
|
yesNoBoxGetYesButton,
|
||||||
yesNoTxtInpBoxGetInput, yesNoBoxClose,
|
yesNoBoxGetNoButton,
|
||||||
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
|
yesNoTxtInpBoxGetYesButton,
|
||||||
|
yesNoTxtInpBoxGetNoButton,
|
||||||
|
yesNoTxtInpBoxGetInput,
|
||||||
|
yesNoBoxClose,
|
||||||
|
yesNoTxtInpBoxClose,
|
||||||
|
yesNoBoxOpen } from "../utils/YesNoBox";
|
||||||
|
|
||||||
/* State */
|
/* State */
|
||||||
var companyStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
var companyStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { AugmentationNames } from "./Augmentations";
|
import { AugmentationNames } from "./Augmentations";
|
||||||
import { generateRandomContract } from "./CodingContractGenerator";
|
import { generateRandomContract } from "./CodingContractGenerator";
|
||||||
import { Programs } from "./CreateProgram";
|
import { Programs } from "./CreateProgram";
|
||||||
import {Factions} from "./Faction";
|
import { Factions } from "./Faction/Factions";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { AllServers } from "./Server";
|
import { AllServers } from "./Server";
|
||||||
import { hackWorldDaemon } from "./RedPill";
|
import { hackWorldDaemon } from "./RedPill";
|
||||||
|
118
src/Faction/Faction.ts
Normal file
118
src/Faction/Faction.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { FactionInfo,
|
||||||
|
FactionInfos } from "./FactionInfo";
|
||||||
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
|
export class Faction {
|
||||||
|
/**
|
||||||
|
* Initiatizes a Faction object from a JSON save state.
|
||||||
|
*/
|
||||||
|
static fromJSON(value: any): Faction {
|
||||||
|
return Generic_fromJSON(Faction, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag signalling whether the player has already received an invitation
|
||||||
|
* to this faction
|
||||||
|
*/
|
||||||
|
alreadyInvited: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds names of all augmentations that this Faction offers
|
||||||
|
*/
|
||||||
|
augmentations: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of favor the player has with this faction.
|
||||||
|
*/
|
||||||
|
favor: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag signalling whether player has been banned from this faction
|
||||||
|
*/
|
||||||
|
isBanned: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag signalling whether player is a member of this faction
|
||||||
|
*/
|
||||||
|
isMember: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of faction
|
||||||
|
*/
|
||||||
|
name: string = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of reputation player has with this faction
|
||||||
|
*/
|
||||||
|
playerReputation: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reputation from the last "prestige" that was not converted to favor.
|
||||||
|
* This reputation rolls over and is used for the next favor calculation
|
||||||
|
*/
|
||||||
|
rolloverRep: number = 0;
|
||||||
|
|
||||||
|
constructor(name: string="") {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInfo(): FactionInfo {
|
||||||
|
const info = FactionInfos[this.name];
|
||||||
|
if (info == null) {
|
||||||
|
throw new Error(`Missing faction from FactionInfos: ${this.name} this probably means the faction got corrupted somehow`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
gainFavor(): void {
|
||||||
|
if (this.favor == null) { this.favor = 0; }
|
||||||
|
if (this.rolloverRep == null) { this.rolloverRep = 0; }
|
||||||
|
const res = this.getFavorGain();
|
||||||
|
if (res.length !== 2) {
|
||||||
|
console.error("Invalid result from getFavorGain() function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.favor += res[0];
|
||||||
|
this.rolloverRep = res[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns an array with [How much favor would be gained, how much rep would be left over]
|
||||||
|
getFavorGain(): number[] {
|
||||||
|
if (this.favor == null) { this.favor = 0; }
|
||||||
|
if (this.rolloverRep == null) { this.rolloverRep = 0; }
|
||||||
|
var favorGain = 0, rep = this.playerReputation + this.rolloverRep;
|
||||||
|
let reqdRep = CONSTANTS.FactionReputationToFavorBase *
|
||||||
|
Math.pow(CONSTANTS.FactionReputationToFavorMult, this.favor);
|
||||||
|
while(rep > 0) {
|
||||||
|
if (rep >= reqdRep) {
|
||||||
|
++favorGain;
|
||||||
|
rep -= reqdRep;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reqdRep *= CONSTANTS.FactionReputationToFavorMult;
|
||||||
|
}
|
||||||
|
return [favorGain, rep];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds all Augmentations to this faction.
|
||||||
|
addAllAugmentations(augs: object): void {
|
||||||
|
this.augmentations.length = 0;
|
||||||
|
for (const name in augs) {
|
||||||
|
if (augs.hasOwnProperty(name)) {
|
||||||
|
this.augmentations.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the current object to a JSON save state.
|
||||||
|
*/
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("Faction", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Faction = Faction;
|
@ -1,139 +1,26 @@
|
|||||||
import {Augmentations, AugmentationNames,
|
import {Augmentations, AugmentationNames,
|
||||||
PlayerOwnedAugmentation} from "./Augmentations";
|
PlayerOwnedAugmentation} from "../Augmentations";
|
||||||
import {BitNodeMultipliers} from "./BitNodeMultipliers";
|
import {BitNodeMultipliers} from "../BitNodeMultipliers";
|
||||||
import {CONSTANTS} from "./Constants";
|
import {CONSTANTS} from "../Constants";
|
||||||
import {Engine} from "./engine";
|
import {Engine} from "../engine";
|
||||||
import {FactionInfos} from "./FactionInfo";
|
import {FactionInfos} from "./FactionInfo";
|
||||||
import {Locations} from "./Location";
|
import {Locations} from "../Location";
|
||||||
import {HackingMission, setInMission} from "./Missions";
|
import {HackingMission, setInMission} from "../Missions";
|
||||||
import {Player} from "./Player";
|
import {Player} from "../Player";
|
||||||
import {PurchaseAugmentationsOrderSetting} from "./SettingEnums";
|
import {PurchaseAugmentationsOrderSetting} from "../SettingEnums";
|
||||||
import {Settings} from "./Settings";
|
import {Settings} from "../Settings";
|
||||||
|
|
||||||
import {Page, routing} from "./ui/navigationTracking";
|
import {Page, routing} from "../ui/navigationTracking";
|
||||||
import {numeralWrapper} from "./ui/numeralFormat";
|
import {numeralWrapper} from "../ui/numeralFormat";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../../utils/DialogBox";
|
||||||
import {factionInvitationBoxCreate} from "../utils/FactionInvitationBox";
|
import {factionInvitationBoxCreate} from "../../utils/FactionInvitationBox";
|
||||||
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
import {removeChildrenFromElement} from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
import {createElement} from "../utils/uiHelpers/createElement";
|
import {createElement} from "../../utils/uiHelpers/createElement";
|
||||||
import {Reviver, Generic_toJSON,
|
import {Reviver, Generic_toJSON,
|
||||||
Generic_fromJSON} from "../utils/JSONReviver";
|
Generic_fromJSON} from "../../utils/JSONReviver";
|
||||||
import {formatNumber} from "../utils/StringHelperFunctions";
|
import {formatNumber} from "../../utils/StringHelperFunctions";
|
||||||
import {yesNoBoxCreate, yesNoBoxGetYesButton,
|
import {yesNoBoxCreate, yesNoBoxGetYesButton,
|
||||||
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox";
|
yesNoBoxGetNoButton, yesNoBoxClose} from "../../utils/YesNoBox";
|
||||||
|
|
||||||
function Faction(name="") {
|
|
||||||
this.name = name;
|
|
||||||
this.augmentations = []; //Name of augmentation only
|
|
||||||
|
|
||||||
//Player-related properties for faction
|
|
||||||
this.isMember = false; //Whether player is member
|
|
||||||
this.isBanned = false; //Whether or not player is banned from joining this faction
|
|
||||||
this.playerReputation = 0; //"Reputation" within faction
|
|
||||||
this.alreadyInvited = false;
|
|
||||||
|
|
||||||
//Faction favor
|
|
||||||
this.favor = 0;
|
|
||||||
this.rolloverRep = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Faction.prototype.getInfo = function() {
|
|
||||||
const info = FactionInfos[this.name];
|
|
||||||
if(info == null) {
|
|
||||||
throw new Error("Missing faction from FactionInfos: " + this.name+" this probably means the faction got corrupted somehow");
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction.prototype.gainFavor = function() {
|
|
||||||
if (this.favor == null || this.favor == undefined) {this.favor = 0;}
|
|
||||||
if (this.rolloverRep == null || this.rolloverRep == undefined) {this.rolloverRep = 0;}
|
|
||||||
var res = this.getFavorGain();
|
|
||||||
if (res.length != 2) {
|
|
||||||
console.log("Error: invalid result from getFavorGain() function");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.favor += res[0];
|
|
||||||
this.rolloverRep = res[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Returns an array with [How much favor would be gained, how much rep would be left over]
|
|
||||||
Faction.prototype.getFavorGain = function() {
|
|
||||||
if (this.favor == null || this.favor == undefined) {this.favor = 0;}
|
|
||||||
if (this.rolloverRep == null || this.rolloverRep == undefined) {this.rolloverRep = 0;}
|
|
||||||
var favorGain = 0, rep = this.playerReputation + this.rolloverRep;
|
|
||||||
var reqdRep = CONSTANTS.FactionReputationToFavorBase *
|
|
||||||
Math.pow(CONSTANTS.FactionReputationToFavorMult, this.favor);
|
|
||||||
while(rep > 0) {
|
|
||||||
if (rep >= reqdRep) {
|
|
||||||
++favorGain;
|
|
||||||
rep -= reqdRep;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reqdRep *= CONSTANTS.FactionReputationToFavorMult;
|
|
||||||
}
|
|
||||||
return [favorGain, rep];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Adds all Augmentations to this faction.
|
|
||||||
Faction.prototype.addAllAugmentations = function() {
|
|
||||||
this.augmentations.length = 0;
|
|
||||||
for (var name in Augmentations) {
|
|
||||||
if (Augmentations.hasOwnProperty(name)) {
|
|
||||||
this.augmentations.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("Faction", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(Faction, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.Faction = Faction;
|
|
||||||
|
|
||||||
//Map of factions indexed by faction name
|
|
||||||
let Factions = {}
|
|
||||||
|
|
||||||
function loadFactions(saveString) {
|
|
||||||
Factions = JSON.parse(saveString, Reviver);
|
|
||||||
}
|
|
||||||
|
|
||||||
function AddToFactions(faction) {
|
|
||||||
var name = faction.name;
|
|
||||||
Factions[name] = faction;
|
|
||||||
}
|
|
||||||
|
|
||||||
function factionExists(name) {
|
|
||||||
return Factions.hasOwnProperty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Augmentation price and rep requirement mult are 1 for everything right now,
|
|
||||||
// This might change in the future for balance
|
|
||||||
function initFactions() {
|
|
||||||
for(const name in FactionInfos) {
|
|
||||||
resetFaction(new Faction(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Resets a faction during (re-)initialization. Saves the favor in the new
|
|
||||||
//Faction object and deletes the old Faction Object from "Factions". Then
|
|
||||||
//reinserts the new Faction object
|
|
||||||
function resetFaction(newFactionObject) {
|
|
||||||
if (!(newFactionObject instanceof Faction)) {
|
|
||||||
throw new Error("Invalid argument 'newFactionObject' passed into resetFaction()");
|
|
||||||
}
|
|
||||||
var factionName = newFactionObject.name;
|
|
||||||
if (factionExists(factionName)) {
|
|
||||||
newFactionObject.favor = Factions[factionName].favor;
|
|
||||||
delete Factions[factionName];
|
|
||||||
}
|
|
||||||
AddToFactions(newFactionObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
function inviteToFaction(faction) {
|
function inviteToFaction(faction) {
|
||||||
if (Settings.SuppressFactionInvites) {
|
if (Settings.SuppressFactionInvites) {
|
||||||
@ -783,6 +670,6 @@ function processPassiveFactionRepGain(numCycles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {getNextNeurofluxLevel, Factions, initFactions, inviteToFaction,
|
export {getNextNeurofluxLevel, inviteToFaction,
|
||||||
joinFaction, displayFactionContent, processPassiveFactionRepGain,
|
joinFaction, displayFactionContent, processPassiveFactionRepGain,
|
||||||
loadFactions, Faction, purchaseAugmentation, factionExists};
|
purchaseAugmentation};
|
@ -1,9 +1,9 @@
|
|||||||
import { IMap } from "./types";
|
import { IMap } from "../types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the "information" property for all the Factions, which is just a description of each faction
|
* Contains the "information" property for all the Factions, which is just a description of each faction
|
||||||
*/
|
*/
|
||||||
class FactionInfo {
|
export class FactionInfo {
|
||||||
/**
|
/**
|
||||||
* The multiplier to apply to augmentation base purchase price.
|
* The multiplier to apply to augmentation base purchase price.
|
||||||
*/
|
*/
|
6
src/Faction/FactionWorkTypeEnum.ts
Normal file
6
src/Faction/FactionWorkTypeEnum.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum FactionWorkType {
|
||||||
|
Field,
|
||||||
|
Hacking,
|
||||||
|
None,
|
||||||
|
Security,
|
||||||
|
}
|
47
src/Faction/Factions.ts
Normal file
47
src/Faction/Factions.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Initialization and manipulation of the Factions object, which stores data
|
||||||
|
* about all Factions in the game
|
||||||
|
*/
|
||||||
|
import { Faction } from "./Faction";
|
||||||
|
import { FactionInfos } from "./FactionInfo";
|
||||||
|
|
||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
import { Reviver } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
|
|
||||||
|
export let Factions: IMap<Faction> = {};
|
||||||
|
|
||||||
|
export function loadFactions(saveString: string): void {
|
||||||
|
Factions = JSON.parse(saveString, Reviver);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddToFactions(faction: Faction) {
|
||||||
|
const name: string = faction.name;
|
||||||
|
Factions[name] = faction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function factionExists(name: string): boolean {
|
||||||
|
return Factions.hasOwnProperty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initFactions(bitNode: number=1) {
|
||||||
|
for (const name in FactionInfos) {
|
||||||
|
resetFaction(new Faction(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resets a faction during (re-)initialization. Saves the favor in the new
|
||||||
|
//Faction object and deletes the old Faction Object from "Factions". Then
|
||||||
|
//reinserts the new Faction object
|
||||||
|
export function resetFaction(newFactionObject: Faction) {
|
||||||
|
if (!(newFactionObject instanceof Faction)) {
|
||||||
|
throw new Error("Invalid argument 'newFactionObject' passed into resetFaction()");
|
||||||
|
}
|
||||||
|
const factionName: string = newFactionObject.name;
|
||||||
|
if (factionExists(factionName)) {
|
||||||
|
newFactionObject.favor = Factions[factionName].favor;
|
||||||
|
delete Factions[factionName];
|
||||||
|
}
|
||||||
|
AddToFactions(newFactionObject);
|
||||||
|
}
|
1
src/Faction/README.md
Normal file
1
src/Faction/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Implementation of Faction-related mechanics
|
23
src/Gang.js
23
src/Gang.js
@ -7,8 +7,9 @@ import {gangMemberTasksMetadata} from "./data/gangmembertasks";
|
|||||||
import { gangMemberUpgradesMetadata } from "./data/gangmemberupgrades";
|
import { gangMemberUpgradesMetadata } from "./data/gangmemberupgrades";
|
||||||
|
|
||||||
import { Engine } from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {Faction, Factions,
|
import { Faction } from "./Faction/Faction";
|
||||||
displayFactionContent} from "./Faction";
|
import { Factions } from "./Faction/Factions";
|
||||||
|
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||||
import { numeralWrapper } from "./ui/numeralFormat";
|
import { numeralWrapper } from "./ui/numeralFormat";
|
||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import { Reviver, Generic_toJSON,
|
import { Reviver, Generic_toJSON,
|
||||||
@ -17,18 +18,24 @@ import {KEY} from "../utils/helpers/keyCodes"
|
|||||||
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
|
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
|
||||||
import { createElement } from "../utils/uiHelpers/createElement";
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||||
import {Page, routing} from "./ui/navigationTracking";
|
import { Page,
|
||||||
|
routing } from "./ui/navigationTracking";
|
||||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||||
import { removeElement } from "../utils/uiHelpers/removeElement";
|
import { removeElement } from "../utils/uiHelpers/removeElement";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
|
import { yesNoBoxCreate,
|
||||||
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
|
yesNoTxtInpBoxCreate,
|
||||||
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
|
yesNoBoxGetYesButton,
|
||||||
yesNoTxtInpBoxGetInput, yesNoBoxClose,
|
yesNoBoxGetNoButton,
|
||||||
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
|
yesNoTxtInpBoxGetYesButton,
|
||||||
|
yesNoTxtInpBoxGetNoButton,
|
||||||
|
yesNoTxtInpBoxGetInput,
|
||||||
|
yesNoBoxClose,
|
||||||
|
yesNoTxtInpBoxClose,
|
||||||
|
yesNoBoxOpen } from "../utils/YesNoBox";
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const GangRespectToReputationRatio = 5; // Respect is divided by this to get rep gain
|
const GangRespectToReputationRatio = 5; // Respect is divided by this to get rep gain
|
||||||
|
14
src/Locations/Cities.ts
Normal file
14
src/Locations/Cities.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display Location Content when visiting somewhere in the World
|
||||||
|
*/
|
||||||
|
// tslint:disable-next-line:variable-name
|
||||||
|
export const Cities: IMap<string> = {
|
||||||
|
Aevum: "Aevum",
|
||||||
|
Chongqing: "Chongqing",
|
||||||
|
Ishima: "Ishima",
|
||||||
|
NewTokyo: "New Tokyo",
|
||||||
|
Sector12: "Sector-12",
|
||||||
|
Volhaven: "Volhaven",
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import { CONSTANTS } from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import { Engine } from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {displayFactionContent} from "./Faction";
|
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||||
|
@ -22,9 +22,13 @@ import {calculateHackingChance,
|
|||||||
calculateGrowTime,
|
calculateGrowTime,
|
||||||
calculateWeakenTime} from "./Hacking";
|
calculateWeakenTime} from "./Hacking";
|
||||||
import {AllGangs} from "./Gang";
|
import {AllGangs} from "./Gang";
|
||||||
import {Factions, Faction, joinFaction,
|
import { Faction } from "./Faction/Faction";
|
||||||
factionExists, purchaseAugmentation} from "./Faction";
|
import { Factions,
|
||||||
import {getCostOfNextHacknetNode, purchaseHacknet} from "./HacknetNode";
|
factionExists } from "./Faction/Factions";
|
||||||
|
import { joinFaction,
|
||||||
|
purchaseAugmentation } from "./Faction/FactionHelpers";
|
||||||
|
import { getCostOfNextHacknetNode,
|
||||||
|
purchaseHacknet } from "./HacknetNode";
|
||||||
import {Locations} from "./Locations";
|
import {Locations} from "./Locations";
|
||||||
import {Message, Messages} from "./Message";
|
import {Message, Messages} from "./Message";
|
||||||
import {inMission} from "./Missions";
|
import {inMission} from "./Missions";
|
||||||
|
268
src/PersonObjects/Person.ts
Normal file
268
src/PersonObjects/Person.ts
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
// Base class representing a person-like object
|
||||||
|
import { BitNodeMultipliers } from "../BitNodeMultipliers";
|
||||||
|
import { Cities } from "../Locations/Cities";
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
|
||||||
|
// Interface for an object that represents the player (PlayerObject)
|
||||||
|
// Used because at the time of implementation, the PlayerObject
|
||||||
|
// cant be converted to TypeScript.
|
||||||
|
//
|
||||||
|
// Only contains the needed properties for Sleeve implementation
|
||||||
|
export interface IPlayer {
|
||||||
|
companyName: string;
|
||||||
|
factions: string[];
|
||||||
|
money: any;
|
||||||
|
gainHackingExp(exp: number): void;
|
||||||
|
gainStrengthExp(exp: number): void;
|
||||||
|
gainDefenseExp(exp: number): void;
|
||||||
|
gainDexterityExp(exp: number): void;
|
||||||
|
gainAgilityExp(exp: number): void;
|
||||||
|
gainCharismaExp(exp: number): void;
|
||||||
|
gainMoney(money: number): void;
|
||||||
|
loseMoney(money: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface for a Crime object
|
||||||
|
// Used because at the time of implementation, the Crime object has not been converted
|
||||||
|
// to Typescript
|
||||||
|
export interface ICrime {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
time: number;
|
||||||
|
money: number;
|
||||||
|
difficulty: number;
|
||||||
|
karma: number;
|
||||||
|
|
||||||
|
hacking_success_weight: number;
|
||||||
|
strength_success_weight: number;
|
||||||
|
defense_success_weight: number;
|
||||||
|
dexterity_success_weight: number;
|
||||||
|
agility_success_weight: number;
|
||||||
|
charisma_success_weight: number;
|
||||||
|
|
||||||
|
hacking_exp: number;
|
||||||
|
strength_exp: number;
|
||||||
|
defense_exp: number;
|
||||||
|
dexterity_exp: number;
|
||||||
|
agility_exp: number;
|
||||||
|
charisma_exp: number;
|
||||||
|
intelligence_exp: number;
|
||||||
|
|
||||||
|
kills: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface for Faction object
|
||||||
|
// Used because at the time of implementation, the Faction object has not been
|
||||||
|
// converted to TypeScript
|
||||||
|
export interface IFaction {
|
||||||
|
name: string;
|
||||||
|
playerReputation: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTaskTracker(): ITaskTracker {
|
||||||
|
return {
|
||||||
|
hack: 0,
|
||||||
|
str: 0,
|
||||||
|
def: 0,
|
||||||
|
dex: 0,
|
||||||
|
agi: 0,
|
||||||
|
cha: 0,
|
||||||
|
money: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class Person {
|
||||||
|
/**
|
||||||
|
* Stats
|
||||||
|
*/
|
||||||
|
hacking_skill: number;
|
||||||
|
strength: number;
|
||||||
|
defense: number;
|
||||||
|
dexterity: number;
|
||||||
|
agility: number;
|
||||||
|
charisma: number;
|
||||||
|
hp: number;
|
||||||
|
max_hp: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multipliers
|
||||||
|
*/
|
||||||
|
hacking_exp: number;
|
||||||
|
strength_exp: number;
|
||||||
|
defense_exp: number;
|
||||||
|
dexterity_exp: number;
|
||||||
|
agility_exp: number;
|
||||||
|
charisma_exp: number;
|
||||||
|
intelligence_exp: number;
|
||||||
|
|
||||||
|
hacking_mult: number;
|
||||||
|
strength_mult: number;
|
||||||
|
defense_mult: number;
|
||||||
|
dexterity_mult: number;
|
||||||
|
agility_mult: number;
|
||||||
|
charisma_mult: number;
|
||||||
|
|
||||||
|
hacking_exp_mult: number;
|
||||||
|
strength_exp_mult: number;
|
||||||
|
defense_exp_mult: number;
|
||||||
|
dexterity_exp_mult: number;
|
||||||
|
agility_exp_mult: number;
|
||||||
|
charisma_exp_mult: number;
|
||||||
|
|
||||||
|
company_rep_mult: number;
|
||||||
|
faction_rep_mult: number;
|
||||||
|
|
||||||
|
crime_money_mult: number;
|
||||||
|
crime_success_mult: number;
|
||||||
|
|
||||||
|
work_money_mult: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* City that the person is in
|
||||||
|
*/
|
||||||
|
city: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.hacking_skill = 1;
|
||||||
|
this.strength = 1;
|
||||||
|
this.defense = 1;
|
||||||
|
this.dexterity = 1;
|
||||||
|
this.agility = 1;
|
||||||
|
this.charisma = 1;
|
||||||
|
this.hp = 10;
|
||||||
|
this.max_hp = 10;
|
||||||
|
|
||||||
|
// Multipliers
|
||||||
|
this.hacking_exp = 0;
|
||||||
|
this.strength_exp = 0;
|
||||||
|
this.defense_exp = 0;
|
||||||
|
this.dexterity_exp = 0;
|
||||||
|
this.agility_exp = 0;
|
||||||
|
this.charisma_exp = 0;
|
||||||
|
this.intelligence_exp = 0;
|
||||||
|
|
||||||
|
this.hacking_mult = 1;
|
||||||
|
this.strength_mult = 1;
|
||||||
|
this.defense_mult = 1;
|
||||||
|
this.dexterity_mult = 1;
|
||||||
|
this.agility_mult = 1;
|
||||||
|
this.charisma_mult = 1;
|
||||||
|
|
||||||
|
this.hacking_exp_mult = 1;
|
||||||
|
this.strength_exp_mult = 1;
|
||||||
|
this.defense_exp_mult = 1;
|
||||||
|
this.dexterity_exp_mult = 1;
|
||||||
|
this.agility_exp_mult = 1;
|
||||||
|
this.charisma_exp_mult = 1;
|
||||||
|
|
||||||
|
this.company_rep_mult = 1;
|
||||||
|
this.faction_rep_mult = 1;
|
||||||
|
|
||||||
|
this.crime_money_mult = 1;
|
||||||
|
this.crime_success_mult = 1;
|
||||||
|
|
||||||
|
this.work_money_mult = 1;
|
||||||
|
|
||||||
|
this.city = Cities.Sector12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an experience amount and stat multiplier, calculates the
|
||||||
|
* stat level. Stat-agnostic (same formula for every stat)
|
||||||
|
*/
|
||||||
|
calculateStat(exp: number, mult: number=1): number {
|
||||||
|
return Math.max(Math.floor(mult*(32 * Math.log(exp + 534.5) - 200)), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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;
|
||||||
|
|
||||||
|
this.company_rep_mult = 1;
|
||||||
|
this.faction_rep_mult = 1;
|
||||||
|
|
||||||
|
this.crime_money_mult = 1;
|
||||||
|
this.crime_success_mult = 1;
|
||||||
|
|
||||||
|
this.work_money_mult = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)));
|
||||||
|
this.defense = Math.max(1, Math.floor(this.calculateStat(this.defense_exp, this.defense_mult)));
|
||||||
|
this.dexterity = Math.max(1, Math.floor(this.calculateStat(this.dexterity_exp, this.dexterity_mult)));
|
||||||
|
this.agility = Math.max(1, Math.floor(this.calculateStat(this.agility_exp, this.agility_mult)));
|
||||||
|
this.charisma = Math.max(1, Math.floor(this.calculateStat(this.charisma_exp, this.charisma_mult)));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
2
src/PersonObjects/README.md
Normal file
2
src/PersonObjects/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Implementation of all Person-type objects, including but not limited to
|
||||||
|
the "PlayerObject" and Sleeves.
|
598
src/PersonObjects/Sleeve/Sleeve.ts
Normal file
598
src/PersonObjects/Sleeve/Sleeve.ts
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
/**
|
||||||
|
* Sleeves are clones of the player that can be used to perform
|
||||||
|
* different tasks synchronously.
|
||||||
|
*
|
||||||
|
* Each sleeve is its own individual, meaning it has its own stats/exp
|
||||||
|
*
|
||||||
|
* Sleeves are unlocked in BitNode-10.
|
||||||
|
*/
|
||||||
|
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
||||||
|
|
||||||
|
import { Person,
|
||||||
|
IPlayer,
|
||||||
|
ICrime,
|
||||||
|
IFaction,
|
||||||
|
ITaskTracker,
|
||||||
|
createTaskTracker } from "../Person";
|
||||||
|
|
||||||
|
import { BitNodeMultipliers } from "../../BitNodeMultipliers";
|
||||||
|
import { Cities } from "../../Locations/Cities";
|
||||||
|
import { Companies } from "../../Company/Companies";
|
||||||
|
import { Company } from "../../Company/Company";
|
||||||
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
import { Faction } from "../../Faction/Faction";
|
||||||
|
import { Factions } from "../../Faction/Factions";
|
||||||
|
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
|
||||||
|
import { Locations } from "../../Locations";
|
||||||
|
|
||||||
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
|
||||||
|
|
||||||
|
export class Sleeve extends Person {
|
||||||
|
/**
|
||||||
|
* Initiatizes a Sleeve object from a JSON save state.
|
||||||
|
*/
|
||||||
|
static fromJSON(value: any): Sleeve {
|
||||||
|
return Generic_fromJSON(Sleeve, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum value for current task
|
||||||
|
*/
|
||||||
|
currentTask: SleeveTaskType = SleeveTaskType.Idle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of current task. Used only for logging purposes
|
||||||
|
*/
|
||||||
|
currentTaskDescription: string = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For what company/faction the current task is assigned to.
|
||||||
|
* Only applicable when working for faction or company, obviously
|
||||||
|
*/
|
||||||
|
currentTaskLocation: string = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum amount of time (in milliseconds) that can be spent on current task.
|
||||||
|
*/
|
||||||
|
currentTaskMaxTime: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Milliseconds spent on current task
|
||||||
|
*/
|
||||||
|
currentTaskTime: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of experience earned for other sleeves
|
||||||
|
*/
|
||||||
|
earningsForSleeves: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of experience + money earned for player
|
||||||
|
*/
|
||||||
|
earningsForPlayer: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of experienced earned in the current task/action
|
||||||
|
*/
|
||||||
|
earningsForTask: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of what type of work sleeve is doing for faction, if applicable
|
||||||
|
*/
|
||||||
|
factionWorkType: FactionWorkType = FactionWorkType.None;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records experience gain rate for the current task
|
||||||
|
*/
|
||||||
|
gainRatesForTask: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of events/notifications for this sleeve
|
||||||
|
*/
|
||||||
|
logs: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone retains memory% of exp upon prestige. If exp would be lower than previously
|
||||||
|
* kept exp, nothing happens
|
||||||
|
*/
|
||||||
|
memory: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sleeve shock. Number between 1 and 100
|
||||||
|
* Trauma/shock that comes with being in a sleeve. Experience earned
|
||||||
|
* is multipled by shock%. This gets applied before synchronization
|
||||||
|
*/
|
||||||
|
shock: number = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stored number of game "loop" cycles
|
||||||
|
*/
|
||||||
|
storedCycles: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronization. Number between 0 and 100
|
||||||
|
* When experience is earned by sleeve, both the player and the sleeve get
|
||||||
|
* sync% of the experience earned. Other sleeves get sync^2% of exp
|
||||||
|
*/
|
||||||
|
sync: number = 1;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
/*
|
||||||
|
this.currentTask = SleeveTaskType.Idle;
|
||||||
|
this.currentTaskDescription = "";
|
||||||
|
this.currentTaskTime = 0;
|
||||||
|
this.currentTaskMaxTime = 0;
|
||||||
|
this.earningsForSleeves = createTaskTracker();
|
||||||
|
this.earningsForPlayer = createTaskTracker();
|
||||||
|
this.earningsForTask = createTaskTracker();
|
||||||
|
this.gainRatesForTask = createTaskTracker();
|
||||||
|
this.logs = [];
|
||||||
|
this.memory = 0;
|
||||||
|
this.shock = 1;
|
||||||
|
this.storedCycles = 0;
|
||||||
|
this.sync = 1;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit crimes
|
||||||
|
*/
|
||||||
|
commitCrime(p: IPlayer, crime: ICrime): void {
|
||||||
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
|
this.finishTask();
|
||||||
|
} else {
|
||||||
|
this.resetTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gainRatesForTask.hack = crime.hacking_exp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.str = crime.strength_exp * this.strength_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.def = crime.defense_exp * this.defense_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
|
||||||
|
this.currentTaskMaxTime = crime.time;
|
||||||
|
|
||||||
|
this.currentTask = SleeveTaskType.Crime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to stop the current task
|
||||||
|
*/
|
||||||
|
finishTask(): void {
|
||||||
|
if (this.currentTask === SleeveTaskType.Crime) {
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Earn experience for any stats (supports multiple)
|
||||||
|
* This function also handles experience propogating to Player and other sleeves
|
||||||
|
*/
|
||||||
|
gainExperience(p: IPlayer, exp: ITaskTracker, numCycles: number=1): ITaskTracker {
|
||||||
|
// Experience is first multiplied by shock. Then 'synchronization'
|
||||||
|
// is accounted for
|
||||||
|
const multFac = (this.shock / 100) * (this.sync / 100) * numCycles;
|
||||||
|
const pHackExp = exp.hack * multFac;
|
||||||
|
const pStrExp = exp.str * multFac;
|
||||||
|
const pDefExp = exp.def * multFac;
|
||||||
|
const pDexExp = exp.dex * multFac;
|
||||||
|
const pAgiExp = exp.agi * multFac;
|
||||||
|
const pChaExp = exp.cha * multFac;
|
||||||
|
|
||||||
|
// Experience is gained by both this sleeve and player
|
||||||
|
if (pHackExp > 0) {
|
||||||
|
this.hacking_exp += pHackExp;
|
||||||
|
p.gainHackingExp(pHackExp);
|
||||||
|
this.earningsForPlayer.hack += pHackExp;
|
||||||
|
this.earningsForTask.hack += pHackExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pStrExp > 0) {
|
||||||
|
this.strength_exp += pStrExp;
|
||||||
|
p.gainStrengthExp(pStrExp);
|
||||||
|
this.earningsForPlayer.str += pStrExp;
|
||||||
|
this.earningsForTask.str += pStrExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDefExp > 0) {
|
||||||
|
this.defense_exp += pDefExp;
|
||||||
|
p.gainDefenseExp(pDefExp);
|
||||||
|
this.earningsForPlayer.def += pDefExp;
|
||||||
|
this.earningsForTask.dex += pDefExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDexExp > 0) {
|
||||||
|
this.dexterity_exp += pDexExp;
|
||||||
|
p.gainDexterityExp(pDexExp);
|
||||||
|
this.earningsForPlayer.dex += pDexExp;
|
||||||
|
this.earningsForTask.dex += pDexExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pAgiExp > 0) {
|
||||||
|
this.agility_exp += pAgiExp;
|
||||||
|
p.gainAgilityExp(pAgiExp);
|
||||||
|
this.earningsForPlayer.agi += pAgiExp;
|
||||||
|
this.earningsForTask.agi += pAgiExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pChaExp > 0) {
|
||||||
|
this.charisma_exp += pChaExp;
|
||||||
|
p.gainCharismaExp(pChaExp);
|
||||||
|
this.earningsForPlayer.cha += pChaExp;
|
||||||
|
this.earningsForTask.cha += pChaExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record earnings for other sleeves
|
||||||
|
this.earningsForSleeves.hack += (pHackExp * (this.sync / 100));
|
||||||
|
this.earningsForSleeves.str += (pStrExp * (this.sync / 100));
|
||||||
|
this.earningsForSleeves.def += (pDefExp * (this.sync / 100));
|
||||||
|
this.earningsForSleeves.dex += (pDexExp * (this.sync / 100));
|
||||||
|
this.earningsForSleeves.agi += (pAgiExp * (this.sync / 100));
|
||||||
|
this.earningsForSleeves.cha += (pChaExp * (this.sync / 100));
|
||||||
|
|
||||||
|
// Return the experience to be gained by other sleeves
|
||||||
|
return {
|
||||||
|
hack: pHackExp * (this.sync / 100),
|
||||||
|
str: pStrExp * (this.sync / 100),
|
||||||
|
def: pDefExp * (this.sync / 100),
|
||||||
|
dex: pDexExp * (this.sync / 100),
|
||||||
|
agi: pAgiExp * (this.sync / 100),
|
||||||
|
cha: pChaExp * (this.sync / 100),
|
||||||
|
money: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Earn money for player
|
||||||
|
*/
|
||||||
|
gainMoney(p: IPlayer, task: ITaskTracker, numCycles: number=1): void {
|
||||||
|
p.gainMoney(task.money * numCycles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets reputation gain for the current task
|
||||||
|
* Only applicable when working for company or faction
|
||||||
|
*/
|
||||||
|
getRepGain(): number {
|
||||||
|
if (this.currentTask === SleeveTaskType.Faction) {
|
||||||
|
switch (this.factionWorkType) {
|
||||||
|
case FactionWorkType.Hacking:
|
||||||
|
return this.getFactionHackingWorkRepGain();
|
||||||
|
case FactionWorkType.Field:
|
||||||
|
return this.getFactionFieldWorkRepGain();
|
||||||
|
case FactionWorkType.Security:
|
||||||
|
return this.getFactionSecurityWorkRepGain();
|
||||||
|
default:
|
||||||
|
console.warn(`Invalid Sleeve.factionWorkType property in Sleeve.getRepGain(): ${this.factionWorkType}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (this.currentTask === SleeveTaskType.Company) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
console.warn(`Sleeve.getRepGain() called for invalid task type: ${this.currentTask}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log(entry: string): void {
|
||||||
|
const MaxLogSize: number = 50;
|
||||||
|
this.logs.push(entry);
|
||||||
|
if (this.logs.length > MaxLogSize) {
|
||||||
|
this.logs.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process loop
|
||||||
|
* Returns an object containing the amount of experience that should be
|
||||||
|
* transferred to all other sleeves
|
||||||
|
*/
|
||||||
|
process(p: IPlayer, numCycles: number=1): ITaskTracker | null {
|
||||||
|
// Only process once every second (5 cycles)
|
||||||
|
const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle;
|
||||||
|
this.storedCycles += numCycles;
|
||||||
|
if (this.storedCycles < CyclesPerSecond) { return null; }
|
||||||
|
|
||||||
|
// Shock gradually goes towards 100
|
||||||
|
this.shock = Math.max(100, this.shock + (0.0001 * this.storedCycles));
|
||||||
|
|
||||||
|
if (this.currentTask === SleeveTaskType.Idle) { return null; }
|
||||||
|
|
||||||
|
let time = this.storedCycles * CONSTANTS.MilliPerCycle;
|
||||||
|
let cyclesUsed = this.storedCycles;
|
||||||
|
if (this.currentTaskTime + time > this.currentTaskMaxTime) {
|
||||||
|
time = this.currentTaskMaxTime - this.currentTaskTime;
|
||||||
|
cyclesUsed = Math.floor(time / CONSTANTS.MilliPerCycle);
|
||||||
|
|
||||||
|
if (time < 0 || cyclesUsed < 0) {
|
||||||
|
console.warn(`Sleeve.process() calculated negative cycle usage`);
|
||||||
|
time = 0;
|
||||||
|
cyclesUsed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.currentTaskTime += time;
|
||||||
|
|
||||||
|
let retValue: ITaskTracker = createTaskTracker();
|
||||||
|
switch (this.currentTask) {
|
||||||
|
case SleeveTaskType.Class:
|
||||||
|
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
break;
|
||||||
|
case SleeveTaskType.Faction:
|
||||||
|
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
|
||||||
|
// TODO REP for both this and company
|
||||||
|
const fac = Factions[this.currentTaskLocation];
|
||||||
|
if (!(fac instanceof Faction)) {
|
||||||
|
console.error(`Invalid faction for Sleeve task: ${this.currentTaskLocation}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SleeveTaskType.Company:
|
||||||
|
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
break;
|
||||||
|
case SleeveTaskType.Recovery:
|
||||||
|
this.shock = Math.max(100, this.shock + (0.001 * this.storedCycles));
|
||||||
|
break;
|
||||||
|
case SleeveTaskType.Sync:
|
||||||
|
this.sync = Math.max(100, this.sync + (0.001 * this.storedCycles));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||||
|
this.finishTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.storedCycles -= cyclesUsed;
|
||||||
|
|
||||||
|
// TODO Finish this
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all parameters used to keep information about the current task
|
||||||
|
*/
|
||||||
|
resetTaskStatus(): void {
|
||||||
|
this.earningsForTask = createTaskTracker();
|
||||||
|
this.gainRatesForTask = createTaskTracker();
|
||||||
|
this.currentTask = SleeveTaskType.Idle;
|
||||||
|
this.currentTaskTime = 0;
|
||||||
|
this.currentTaskMaxTime = 0;
|
||||||
|
this.factionWorkType = FactionWorkType.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a course at a university
|
||||||
|
*/
|
||||||
|
takeUniversityCourse(p: IPlayer, universityName: string, className: string): boolean {
|
||||||
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
|
this.finishTask();
|
||||||
|
} else {
|
||||||
|
this.resetTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set exp/money multipliers based on which university.
|
||||||
|
// Also check that the sleeve is in the right city
|
||||||
|
let costMult: number = 1;
|
||||||
|
let expMult: number = 1;
|
||||||
|
switch (universityName.toLowerCase()) {
|
||||||
|
case Locations.AevumSummitUniversity.toLowerCase():
|
||||||
|
if (this.city !== Cities.Aevum) { return false; }
|
||||||
|
costMult = 4;
|
||||||
|
expMult = 3;
|
||||||
|
break;
|
||||||
|
case Locations.Sector12RothmanUniversity.toLowerCase():
|
||||||
|
if (this.city !== Cities.Sector12) { return false; }
|
||||||
|
costMult = 3;
|
||||||
|
expMult = 2;
|
||||||
|
break;
|
||||||
|
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
|
||||||
|
if (this.city !== Cities.Volhaven) { return false; }
|
||||||
|
costMult = 5;
|
||||||
|
expMult = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of game cycles in a second
|
||||||
|
const cps: number = 1000 / CONSTANTS.MilliPerCycle;
|
||||||
|
|
||||||
|
// Set experience/money gains based on class
|
||||||
|
// TODO Refactor University Courses into its own class or something
|
||||||
|
const baseStudyComputerScienceExp: number = 0.5;
|
||||||
|
const baseDataStructuresExp: number = 1;
|
||||||
|
const baseNetworksExp: number = 2;
|
||||||
|
const baseAlgorithmsExp: number = 4;
|
||||||
|
const baseManagementExp: number = 2;
|
||||||
|
const baseLeadershipExp: number = 4;
|
||||||
|
|
||||||
|
switch (className.toLowerCase()) {
|
||||||
|
case "study computer science":
|
||||||
|
this.gainRatesForTask.hack = (baseStudyComputerScienceExp * expMult * this.hacking_exp_mult);
|
||||||
|
break;
|
||||||
|
case "data structures":
|
||||||
|
this.gainRatesForTask.hack = (baseDataStructuresExp * expMult * this.hacking_exp_mult);
|
||||||
|
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassDataStructuresBaseCost * costMult);
|
||||||
|
break;
|
||||||
|
case "networks":
|
||||||
|
this.gainRatesForTask.hack = (baseNetworksExp * expMult * this.hacking_exp_mult);
|
||||||
|
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassNetworksBaseCost * costMult);
|
||||||
|
break;
|
||||||
|
case "algorithms":
|
||||||
|
this.gainRatesForTask.hack = (baseAlgorithmsExp * expMult * this.hacking_exp_mult);
|
||||||
|
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassAlgorithmsBaseCost * costMult);
|
||||||
|
break;
|
||||||
|
case "management":
|
||||||
|
this.gainRatesForTask.cha = (baseManagementExp * expMult * this.charisma_exp_mult);
|
||||||
|
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassManagementBaseCost * costMult);
|
||||||
|
break;
|
||||||
|
case "leadership":
|
||||||
|
this.gainRatesForTask.cha = (baseLeadershipExp * expMult * this.charisma_exp_mult);
|
||||||
|
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassLeadershipBaseCost * costMult);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentTask = SleeveTaskType.Class;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Travel to another City. Costs money from player
|
||||||
|
*/
|
||||||
|
travel(p: IPlayer, newCity: string): boolean {
|
||||||
|
if (Cities[newCity] == null) {
|
||||||
|
console.error(`Invalid city ${newCity} passed into Sleeve.travel()`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.loseMoney(CONSTANTS.TravelCost);
|
||||||
|
this.city = newCity;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work for a company
|
||||||
|
*/
|
||||||
|
workForCompany(p: IPlayer): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work for one of the player's factions
|
||||||
|
*/
|
||||||
|
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
|
||||||
|
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
|
this.finishTask();
|
||||||
|
} else {
|
||||||
|
this.resetTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set type of work (hacking/field/security), and the experience gains
|
||||||
|
const sanitizedWorkType: string = workType.toLowerCase();
|
||||||
|
if (sanitizedWorkType.includes("hack")) {
|
||||||
|
this.factionWorkType = FactionWorkType.Hacking;
|
||||||
|
this.gainRatesForTask.hack = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
} else if (sanitizedWorkType.includes("field")) {
|
||||||
|
this.factionWorkType = FactionWorkType.Field;
|
||||||
|
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.str = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.def = .1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.dex = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.agi = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.cha = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
} else if (sanitizedWorkType.includes("security")) {
|
||||||
|
this.factionWorkType = FactionWorkType.Security;
|
||||||
|
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.str = .15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.def = .15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.dex = .15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.agi = .15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentTaskLocation = factionName;
|
||||||
|
this.currentTask = SleeveTaskType.Faction;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a gym workout task
|
||||||
|
*/
|
||||||
|
workoutAtGym(p: IPlayer, gymName: string, stat: string): boolean {
|
||||||
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
|
this.finishTask();
|
||||||
|
} else {
|
||||||
|
this.resetTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set exp/money multipliers based on which university.
|
||||||
|
// Also check that the sleeve is in the right city
|
||||||
|
let costMult: number = 1;
|
||||||
|
let expMult: number = 1;
|
||||||
|
switch (gymName.toLowerCase()) {
|
||||||
|
case Locations.AevumCrushFitnessGym.toLowerCase():
|
||||||
|
if (this.city != Cities.Aevum) { return false; }
|
||||||
|
costMult = 3;
|
||||||
|
expMult = 2;
|
||||||
|
break;
|
||||||
|
case Locations.AevumSnapFitnessGym.toLowerCase():
|
||||||
|
if (this.city != Cities.Aevum) { return false; }
|
||||||
|
costMult = 10;
|
||||||
|
expMult = 5;
|
||||||
|
break;
|
||||||
|
case Locations.Sector12IronGym.toLowerCase():
|
||||||
|
if (this.city != Cities.Sector12) { return false; }
|
||||||
|
costMult = 1;
|
||||||
|
expMult = 1;
|
||||||
|
break;
|
||||||
|
case Locations.Sector12PowerhouseGym.toLowerCase():
|
||||||
|
if (this.city != Cities.Sector12) { return false; }
|
||||||
|
costMult = 20;
|
||||||
|
expMult = 10;
|
||||||
|
break;
|
||||||
|
case Locations.VolhavenMilleniumFitnessGym:
|
||||||
|
if (this.city != Cities.Volhaven) { return false; }
|
||||||
|
costMult = 7;
|
||||||
|
expMult = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of game cycles in a second
|
||||||
|
const cps = 1000 / CONSTANTS.MilliPerCycle;
|
||||||
|
|
||||||
|
// Set experience/money gains based on class
|
||||||
|
// TODO Refactor University Courses into its own class or something
|
||||||
|
const baseGymExp: number = 1;
|
||||||
|
const sanitizedStat: string = stat.toLowerCase();
|
||||||
|
|
||||||
|
// Set cost
|
||||||
|
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassGymBaseCost * costMult);
|
||||||
|
|
||||||
|
// Set stat gain rate
|
||||||
|
if (sanitizedStat.includes("str")) {
|
||||||
|
this.gainRatesForTask.str = (baseGymExp * expMult);
|
||||||
|
} else if (sanitizedStat.includes("def")) {
|
||||||
|
this.gainRatesForTask.def = (baseGymExp * expMult);
|
||||||
|
} else if (sanitizedStat.includes("dex")) {
|
||||||
|
this.gainRatesForTask.dex = (baseGymExp * expMult);
|
||||||
|
} else if (sanitizedStat.includes("agi")) {
|
||||||
|
this.gainRatesForTask.agi = (baseGymExp * expMult);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentTask = SleeveTaskType.Class;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the current object to a JSON save state.
|
||||||
|
*/
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("Sleeve", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Sleeve = Sleeve;
|
12
src/PersonObjects/Sleeve/SleeveTaskTypesEnum.ts
Normal file
12
src/PersonObjects/Sleeve/SleeveTaskTypesEnum.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Enum for different types of tasks that a Sleeve can perform
|
||||||
|
*/
|
||||||
|
export enum SleeveTaskType {
|
||||||
|
Class,
|
||||||
|
Company,
|
||||||
|
Crime,
|
||||||
|
Faction,
|
||||||
|
Idle,
|
||||||
|
Recovery,
|
||||||
|
Sync,
|
||||||
|
}
|
@ -14,8 +14,9 @@ import {Corporation} from "./CompanyManagement";
|
|||||||
import {Programs} from "./CreateProgram";
|
import {Programs} from "./CreateProgram";
|
||||||
import {determineCrimeSuccess, Crimes} from "./Crimes";
|
import {determineCrimeSuccess, Crimes} from "./Crimes";
|
||||||
import {Engine} from "./engine";
|
import {Engine} from "./engine";
|
||||||
import {Factions, Faction,
|
import { Faction } from "./Faction/Faction";
|
||||||
displayFactionContent} from "./Faction";
|
import { Factions } from "./Faction/Factions";
|
||||||
|
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||||
import {Gang, resetGangs} from "./Gang";
|
import {Gang, resetGangs} from "./Gang";
|
||||||
import {Locations} from "./Locations";
|
import {Locations} from "./Locations";
|
||||||
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
|
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
|
||||||
@ -41,10 +42,10 @@ function PlayerObject() {
|
|||||||
//Combat stats
|
//Combat stats
|
||||||
this.hp = 10;
|
this.hp = 10;
|
||||||
this.max_hp = 10;
|
this.max_hp = 10;
|
||||||
this.strength = 1; //Damage dealt
|
this.strength = 1;
|
||||||
this.defense = 1; //Damage received
|
this.defense = 1;
|
||||||
this.dexterity = 1; //Accuracy
|
this.dexterity = 1;
|
||||||
this.agility = 1; //Dodge %
|
this.agility = 1;
|
||||||
|
|
||||||
//Labor stats
|
//Labor stats
|
||||||
this.charisma = 1;
|
this.charisma = 1;
|
||||||
@ -594,7 +595,7 @@ PlayerObject.prototype.gainIntelligenceExp = function(exp) {
|
|||||||
|
|
||||||
//Given a string expression like "str" or "strength", returns the given stat
|
//Given a string expression like "str" or "strength", returns the given stat
|
||||||
PlayerObject.prototype.queryStatFromString = function(str) {
|
PlayerObject.prototype.queryStatFromString = function(str) {
|
||||||
var tempStr = str.toLowerCase();
|
const tempStr = str.toLowerCase();
|
||||||
if (tempStr.includes("hack")) {return Player.hacking_skill;}
|
if (tempStr.includes("hack")) {return Player.hacking_skill;}
|
||||||
if (tempStr.includes("str")) {return Player.strength;}
|
if (tempStr.includes("str")) {return Player.strength;}
|
||||||
if (tempStr.includes("def")) {return Player.defense;}
|
if (tempStr.includes("def")) {return Player.defense;}
|
||||||
|
@ -7,8 +7,10 @@ import {writeCinematicText} from "./CinematicText";
|
|||||||
import {Companies, initCompanies} from "./Company/Companies";
|
import {Companies, initCompanies} from "./Company/Companies";
|
||||||
import {Programs} from "./CreateProgram";
|
import {Programs} from "./CreateProgram";
|
||||||
import {Engine} from "./engine";
|
import {Engine} from "./engine";
|
||||||
import {Factions, Faction, initFactions,
|
import { Faction } from "./Faction/Faction";
|
||||||
joinFaction} from "./Faction";
|
import { Factions,
|
||||||
|
initFactions } from "./Faction/Factions";
|
||||||
|
import { joinFaction } from "./Faction/FactionHelpers";
|
||||||
import {deleteGangDisplayContent} from "./Gang";
|
import {deleteGangDisplayContent} from "./Gang";
|
||||||
import {Locations} from "./Location";
|
import {Locations} from "./Location";
|
||||||
import {initMessages, Messages, Message} from "./Message";
|
import {initMessages, Messages, Message} from "./Message";
|
||||||
|
@ -4,8 +4,9 @@ import {Companies, loadCompanies} from "./Company/Companies";
|
|||||||
import {CompanyPosition} from "./Company/CompanyPosition";
|
import {CompanyPosition} from "./Company/CompanyPosition";
|
||||||
import {CONSTANTS} from "./Constants";
|
import {CONSTANTS} from "./Constants";
|
||||||
import {Engine} from "./engine";
|
import {Engine} from "./engine";
|
||||||
import {loadFactions, Factions,
|
import { Factions,
|
||||||
processPassiveFactionRepGain} from "./Faction";
|
loadFactions } from "./Faction/Factions";
|
||||||
|
import { processPassiveFactionRepGain } from "./Faction/FactionHelpers";
|
||||||
import {FconfSettings, loadFconf} from "./Fconf";
|
import {FconfSettings, loadFconf} from "./Fconf";
|
||||||
import {loadAllGangs, AllGangs} from "./Gang";
|
import {loadAllGangs, AllGangs} from "./Gang";
|
||||||
import {processAllHacknetNodeEarnings} from "./HacknetNode";
|
import {processAllHacknetNodeEarnings} from "./HacknetNode";
|
||||||
|
@ -34,9 +34,10 @@ import {displayCreateProgramContent,
|
|||||||
initCreateProgramButtons,
|
initCreateProgramButtons,
|
||||||
Programs} from "./CreateProgram";
|
Programs} from "./CreateProgram";
|
||||||
import {createDevMenu, closeDevMenu} from "./DevMenu";
|
import {createDevMenu, closeDevMenu} from "./DevMenu";
|
||||||
|
import { Factions, initFactions } from "./Faction/Factions";
|
||||||
import { displayFactionContent, joinFaction,
|
import { displayFactionContent, joinFaction,
|
||||||
processPassiveFactionRepGain, Factions,
|
processPassiveFactionRepGain,
|
||||||
inviteToFaction, initFactions} from "./Faction";
|
inviteToFaction } from "./Faction/FactionHelpers";
|
||||||
import {FconfSettings} from "./Fconf";
|
import {FconfSettings} from "./Fconf";
|
||||||
import {displayLocationContent,
|
import {displayLocationContent,
|
||||||
initLocationButtons} from "./Location";
|
initLocationButtons} from "./Location";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {joinFaction} from "../src/Faction";
|
import {joinFaction} from "../src/Faction/FactionHelpers";
|
||||||
import {Engine} from "../src/engine";
|
import {Engine} from "../src/engine";
|
||||||
import {Player} from "../src/Player";
|
import {Player} from "../src/Player";
|
||||||
import {clearEventListeners} from "./uiHelpers/clearEventListeners";
|
import {clearEventListeners} from "./uiHelpers/clearEventListeners";
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { BitNodeMultipliers } from "../src/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../src/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../src/Constants";
|
import { CONSTANTS } from "../src/Constants";
|
||||||
import {Factions, Faction} from "../src/Faction";
|
import { Faction } from "../src/Faction/Faction";
|
||||||
|
import { Factions } from "../src/Faction/Factions";
|
||||||
import { Player } from "../src/Player";
|
import { Player } from "../src/Player";
|
||||||
import { dialogBoxCreate } from "./DialogBox";
|
import { dialogBoxCreate } from "./DialogBox";
|
||||||
import { clearEventListeners } from "./uiHelpers/clearEventListeners";
|
import { clearEventListeners } from "./uiHelpers/clearEventListeners";
|
||||||
|
Loading…
Reference in New Issue
Block a user