mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 05:33:54 +01:00
v0.46.2
This commit is contained in:
parent
98a04e4932
commit
7417fb6ef8
@ -75,7 +75,7 @@
|
||||
margin: 4px;
|
||||
padding: 2px;
|
||||
resize: none;
|
||||
width: 50%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#script-editor-status {
|
||||
|
2
dist/engine.bundle.js
vendored
2
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/engine.css
vendored
2
dist/engine.css
vendored
@ -893,7 +893,7 @@ button {
|
||||
margin: 4px;
|
||||
padding: 2px;
|
||||
resize: none;
|
||||
width: 50%; }
|
||||
width: 60%; }
|
||||
|
||||
#script-editor-status {
|
||||
float: left;
|
||||
|
114
dist/vendor.bundle.js
vendored
114
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -3,6 +3,18 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.46.2 - 4/14/2019
|
||||
-------------------
|
||||
* Source-File 2 now allows you to form gangs in other BitNodes when your karma reaches a very large negative value
|
||||
** (Karma is a hidden stat and is lowered by committing crimes)
|
||||
* Gang changes:
|
||||
** Bug Fix: Gangs can no longer clash with themselve
|
||||
** Bug Fix: Winning against another gang should properly reduce their power
|
||||
|
||||
* Bug Fix: Terminal 'wget' command now works properly
|
||||
* Bug Fix: Hacknet Server Hash upgrades now properly reset upon installing Augs/switching BitNodes
|
||||
* Bug Fix: Fixed button for creating Corporations
|
||||
|
||||
v0.46.1 - 4/12/2019
|
||||
-------------------
|
||||
* Added a very rudimentary directory system to the Terminal
|
||||
|
@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# The short X.Y version.
|
||||
version = '0.46'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.46.0'
|
||||
release = '0.46.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -8,6 +8,7 @@ recruitMember() Netscript Function
|
||||
Attempt to recruit a new gang member.
|
||||
|
||||
Possible reasons for failure:
|
||||
|
||||
* Cannot currently recruit a new member
|
||||
* There already exists a member with the specified name
|
||||
|
||||
|
@ -3,7 +3,7 @@ hashCost() Netscript Function
|
||||
|
||||
.. warning:: This page contains spoilers for the game
|
||||
|
||||
.. js:function:: hashCost(upgName, upgTarget)
|
||||
.. js:function:: hashCost(upgName)
|
||||
|
||||
:param string upgName: Name of upgrade to get the cost of. Must be an exact match
|
||||
|
||||
|
@ -115,7 +115,7 @@
|
||||
|
||||
<div id="script-editor-filename-wrapper">
|
||||
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
|
||||
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/>
|
||||
<input id="script-editor-filename" type="text" maxlength="100" tabindex="1"/>
|
||||
</div>
|
||||
|
||||
<div id="ace-editor"></div>
|
||||
@ -221,8 +221,6 @@
|
||||
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
||||
<div id="faction-container" class="generic-menupage-container"></div>
|
||||
|
||||
<div id="faction-augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
<!-- Augmentations -->
|
||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
|
@ -114,5 +114,5 @@
|
||||
"watch": "webpack --watch --mode production",
|
||||
"watch:dev": "webpack --watch --mode development"
|
||||
},
|
||||
"version": "0.45.0"
|
||||
"version": "0.46.2"
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviv
|
||||
|
||||
interface IConstructorParams {
|
||||
info: string;
|
||||
isSpecial?: boolean;
|
||||
moneyCost: number;
|
||||
name: string;
|
||||
prereqs?: string[];
|
||||
@ -62,6 +63,9 @@ export class Augmentation {
|
||||
// Description of what this Aug is and what it does
|
||||
info: string = "";
|
||||
|
||||
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
|
||||
isSpecial: boolean = false;
|
||||
|
||||
// Augmentation level - for repeatable Augs like NeuroFlux Governor
|
||||
level: number = 0;
|
||||
|
||||
@ -90,6 +94,10 @@ export class Augmentation {
|
||||
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
this.startingCost = this.baseCost;
|
||||
|
||||
if (params.isSpecial) {
|
||||
this.isSpecial = true;
|
||||
}
|
||||
|
||||
this.level = 0;
|
||||
|
||||
// Set multipliers
|
||||
|
@ -1677,19 +1677,6 @@ function initAugmentations() {
|
||||
}
|
||||
AddToAugmentations(SNA);
|
||||
|
||||
//For BitNode-2, add all Augmentations to crime/evil factions.
|
||||
//Do this before adding special Augmentations that become available in later BitNodes
|
||||
if (Player.bitNodeN === 2) {
|
||||
console.log("Adding all augmentations to crime factions for Bit node 2");
|
||||
Factions["Slum Snakes"].addAllAugmentations(Augmentations);
|
||||
Factions["Tetrads"].addAllAugmentations(Augmentations);
|
||||
Factions["The Syndicate"].addAllAugmentations(Augmentations);
|
||||
Factions["The Dark Army"].addAllAugmentations(Augmentations);
|
||||
Factions["Speakers for the Dead"].addAllAugmentations(Augmentations);
|
||||
Factions["NiteSec"].addAllAugmentations(Augmentations);
|
||||
Factions["The Black Hand"].addAllAugmentations(Augmentations);
|
||||
}
|
||||
|
||||
//Special Bladeburner Augmentations
|
||||
var BladeburnersFactionName = "Bladeburners";
|
||||
if (factionExists(BladeburnersFactionName)) {
|
||||
@ -1708,6 +1695,7 @@ function initAugmentations() {
|
||||
"Increases the player's dexterity by 5%.",
|
||||
bladeburner_success_chance_mult: 1.03,
|
||||
dexterity_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
EsperEyewear.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(EsperEyewear);
|
||||
@ -1725,6 +1713,7 @@ function initAugmentations() {
|
||||
bladeburner_success_chance_mult: 1.03,
|
||||
bladeburner_analysis_mult: 1.05,
|
||||
bladeburner_stamina_gain_mult: 1.02,
|
||||
isSpecial: true,
|
||||
});
|
||||
EMS4Recombination.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(EMS4Recombination);
|
||||
@ -1743,6 +1732,7 @@ function initAugmentations() {
|
||||
strength_mult: 1.05,
|
||||
dexterity_mult: 1.05,
|
||||
bladeburner_success_chance_mult: 1.04,
|
||||
isSpecial: true,
|
||||
});
|
||||
OrionShoulder.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(OrionShoulder);
|
||||
@ -1758,6 +1748,7 @@ function initAugmentations() {
|
||||
"This augmentation:<br>" +
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 6%.",
|
||||
bladeburner_success_chance_mult: 1.06,
|
||||
isSpecial: true,
|
||||
});
|
||||
HyperionV1.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(HyperionV1);
|
||||
@ -1772,6 +1763,7 @@ function initAugmentations() {
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||
prereqs:[AugmentationNames.HyperionV1],
|
||||
bladeburner_success_chance_mult: 1.08,
|
||||
isSpecial: true,
|
||||
});
|
||||
HyperionV2.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(HyperionV2);
|
||||
@ -1790,6 +1782,7 @@ function initAugmentations() {
|
||||
dexterity_mult: 1.07,
|
||||
agility_mult: 1.07,
|
||||
bladeburner_stamina_gain_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
GolemSerum.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(GolemSerum);
|
||||
@ -1805,6 +1798,7 @@ function initAugmentations() {
|
||||
dexterity_exp_mult: 1.1,
|
||||
bladeburner_analysis_mult: 1.1,
|
||||
bladeburner_success_chance_mult: 1.04,
|
||||
isSpecial: true,
|
||||
});
|
||||
VangelisVirus.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(VangelisVirus);
|
||||
@ -1824,6 +1818,7 @@ function initAugmentations() {
|
||||
dexterity_exp_mult: 1.1,
|
||||
bladeburner_analysis_mult: 1.15,
|
||||
bladeburner_success_chance_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
VangelisVirus3.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(VangelisVirus3);
|
||||
@ -1842,6 +1837,7 @@ function initAugmentations() {
|
||||
dexterity_exp_mult: 1.05,
|
||||
agility_exp_mult: 1.05,
|
||||
bladeburner_max_stamina_mult: 1.1,
|
||||
isSpecial: true,
|
||||
});
|
||||
INTERLINKED.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(INTERLINKED);
|
||||
@ -1859,6 +1855,7 @@ function initAugmentations() {
|
||||
agility_mult: 1.05,
|
||||
bladeburner_max_stamina_mult: 1.05,
|
||||
bladeburner_stamina_gain_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeRunner.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeRunner);
|
||||
@ -1879,6 +1876,7 @@ function initAugmentations() {
|
||||
agility_mult: 1.04,
|
||||
bladeburner_stamina_gain_mult: 1.02,
|
||||
bladeburner_success_chance_mult: 1.03,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmor.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmor);
|
||||
@ -1895,6 +1893,7 @@ function initAugmentations() {
|
||||
bladeburner_success_chance_mult: 1.05,
|
||||
bladeburner_stamina_gain_mult: 1.02,
|
||||
bladeburner_max_stamina_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorPowerCells.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorPowerCells);
|
||||
@ -1909,6 +1908,7 @@ function initAugmentations() {
|
||||
prereqs:[AugmentationNames.BladeArmor],
|
||||
defense_mult: 1.05,
|
||||
bladeburner_success_chance_mult: 1.06,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorEnergyShielding.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorEnergyShielding);
|
||||
@ -1922,6 +1922,7 @@ function initAugmentations() {
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||
prereqs:[AugmentationNames.BladeArmor],
|
||||
bladeburner_success_chance_mult: 1.08,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorUnibeam.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorUnibeam);
|
||||
@ -1936,6 +1937,7 @@ function initAugmentations() {
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 10%.",
|
||||
prereqs:[AugmentationNames.BladeArmorUnibeam],
|
||||
bladeburner_success_chance_mult: 1.1,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorOmnibeam.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorOmnibeam);
|
||||
@ -1951,6 +1953,7 @@ function initAugmentations() {
|
||||
prereqs:[AugmentationNames.BladeArmor],
|
||||
bladeburner_analysis_mult: 1.15,
|
||||
bladeburner_success_chance_mult: 1.02,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorIPU.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorIPU);
|
||||
@ -1963,7 +1966,8 @@ function initAugmentations() {
|
||||
"extremely large radius. These specially-modified holograms were specially " +
|
||||
"weaponized by Bladeburner units to be used against Synthoids.<br><br>" +
|
||||
"This augmentation allows you to perform Bladeburner actions and other " +
|
||||
"actions (such as working, commiting crimes, etc.) at the same time."
|
||||
"actions (such as working, commiting crimes, etc.) at the same time.",
|
||||
isSpecial: true,
|
||||
});
|
||||
BladesSimulacrum.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladesSimulacrum);
|
||||
|
@ -57,8 +57,9 @@ export function initBitNodes() {
|
||||
"For every Faction NOT listed above, reputation gains are halved<br>" +
|
||||
"You will no longer gain passive reputation with Factions<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File increases the player's crime success rate, " +
|
||||
"crime money, and charisma multipliers by:<br><br>" +
|
||||
"upgrade its level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes " +
|
||||
"once your karma decreases to a certain value. " +
|
||||
"It also increases the player's crime success rate, crime money, and charisma multipliers by:<br><br>" +
|
||||
"Level 1: 24%<br>" +
|
||||
"Level 2: 36%<br>" +
|
||||
"Level 3: 42%");
|
||||
|
@ -6,7 +6,7 @@
|
||||
import { IMap } from "./types";
|
||||
|
||||
export let CONSTANTS: IMap<any> = {
|
||||
Version: "0.46.1",
|
||||
Version: "0.46.2",
|
||||
|
||||
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
||||
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
||||
@ -276,10 +276,25 @@ export let CONSTANTS: IMap<any> = {
|
||||
LatestUpdate:
|
||||
`
|
||||
v0.46.2
|
||||
* Source-File 2 now allows you to form gangs in other BitNodes when your karma reaches a very large negative value
|
||||
** (Karma is a hidden stat and is lowered by committing crimes)
|
||||
* Gang changes:
|
||||
** Bug Fix: Gangs can no longer clash with themselve
|
||||
** Bug Fix: Winning against another gang should properly reduce their power
|
||||
|
||||
* Bug Fix: Terminal 'wget' command now works properly
|
||||
* Bug Fix: Hacknet Server Hash upgrades now properly reset upon installing Augs/switching BitNodes
|
||||
* Bug Fix: Fixed button for creating Corporations
|
||||
|
||||
v0.46.1
|
||||
* Added a very rudimentary directory system to the Terminal
|
||||
** Details here: https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#filesystem-directories
|
||||
* Added numHashes(), hashCost(), and spendHashes() functions to the Netscript Hacknet Node API
|
||||
* 'Generate Coding Contract' hash upgrade is now more expensive
|
||||
* 'Generate Coding Contract' hash upgrade now generates the contract randomly on the server, rather than on home computer
|
||||
* The cost of selling hashes for money no longer increases each time
|
||||
* Selling hashes for money now costs 4 hashes (in exchange for $1m)
|
||||
* Bug Fix: Hacknet Node earnings should work properly when game is inactive/offline
|
||||
* Bug Fix: Duplicate Sleeve augmentations are now properly reset when switching to a new BitNode
|
||||
`
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||
const tonsPP = 1e27;
|
||||
const tonsP = 1e12;
|
||||
|
||||
|
||||
class ValueAdjusterComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -48,7 +47,7 @@ class ValueAdjusterComponent extends Component {
|
||||
this.setValue = this.setValue.bind(this);
|
||||
}
|
||||
setValue(event) {
|
||||
this.setState({ value: event.target.value });
|
||||
this.setState({ value: parseFloat(event.target.value) });
|
||||
}
|
||||
render() {
|
||||
const { title, add, subtract, reset } = this.props;
|
||||
@ -131,7 +130,6 @@ class DevMenuComponent extends Component {
|
||||
this.setState({ codingcontract: event.target.value });
|
||||
}
|
||||
|
||||
|
||||
addMoney(n) {
|
||||
return function() {
|
||||
Player.gainMoney(n);
|
||||
@ -193,6 +191,12 @@ class DevMenuComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
modifyKarma(modifier) {
|
||||
return function(amt) {
|
||||
Player.karma += (amt * modifier);
|
||||
}
|
||||
}
|
||||
|
||||
tonsOfExp() {
|
||||
Player.gainHackingExp(tonsPP);
|
||||
Player.gainStrengthExp(tonsPP);
|
||||
@ -244,6 +248,12 @@ class DevMenuComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
resetKarma() {
|
||||
return function() {
|
||||
Player.karma = 0;
|
||||
}
|
||||
}
|
||||
|
||||
enableIntelligence() {
|
||||
if(Player.intelligence === 0) {
|
||||
Player.intelligence = 1;
|
||||
@ -812,6 +822,19 @@ class DevMenuComponent extends Component {
|
||||
<button className="std-button" onClick={this.disableIntelligence}>Disable</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span className="text text-center">Karma:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
title="karma"
|
||||
add={this.modifyKarma(1)}
|
||||
subtract={this.modifyKarma(-1)}
|
||||
reset={this.resetKarma()}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -97,16 +97,6 @@ export class Faction {
|
||||
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.
|
||||
*/
|
||||
|
7
src/Faction/FactionHelpers.d.ts
vendored
Normal file
7
src/Faction/FactionHelpers.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { Augmentation } from "../Augmentation/Augmentation";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
|
||||
export declare function getNextNeurofluxLevel(): number;
|
||||
export declare function hasAugmentationPrereqs(aug: Augmentation): boolean;
|
||||
export declare function purchaseAugmentationBoxCreate(aug: Augmentation, fac: Faction): void;
|
||||
export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void;
|
@ -1,694 +0,0 @@
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Engine } from "../engine";
|
||||
import { Faction } from "./Faction";
|
||||
import { Factions } from "./Factions";
|
||||
import { FactionInfos } from "./FactionInfo";
|
||||
import { HackingMission, setInMission } from "../Missions";
|
||||
import { Player } from "../Player";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../Settings/SettingEnums";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
|
||||
import { createSleevePurchasesFromCovenantPopup } from "../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||
|
||||
import {Page, routing} from "../ui/navigationTracking";
|
||||
import {numeralWrapper} from "../ui/numeralFormat";
|
||||
import {dialogBoxCreate} from "../../utils/DialogBox";
|
||||
import {factionInvitationBoxCreate} from "../../utils/FactionInvitationBox";
|
||||
import {removeChildrenFromElement} from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||
import {createElement} from "../../utils/uiHelpers/createElement";
|
||||
import {Reviver, Generic_toJSON,
|
||||
Generic_fromJSON} from "../../utils/JSONReviver";
|
||||
import {formatNumber} from "../../utils/StringHelperFunctions";
|
||||
import {yesNoBoxCreate, yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton, yesNoBoxClose} from "../../utils/YesNoBox";
|
||||
|
||||
function inviteToFaction(faction) {
|
||||
if (Settings.SuppressFactionInvites) {
|
||||
faction.alreadyInvited = true;
|
||||
Player.factionInvitations.push(faction.name);
|
||||
if (routing.isOn(Page.Factions)) {
|
||||
Engine.loadFactionsContent();
|
||||
}
|
||||
} else {
|
||||
factionInvitationBoxCreate(faction);
|
||||
}
|
||||
}
|
||||
|
||||
function joinFaction(faction) {
|
||||
faction.isMember = true;
|
||||
Player.factions.push(faction.name);
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
//Determine what factions you are banned from now that you have joined this faction
|
||||
for(const i in factionInfo.enemies) {
|
||||
const enemy = factionInfo.enemies[i];
|
||||
if (Factions[enemy] instanceof Faction) {
|
||||
Factions[enemy].isBanned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Displays the HTML content for a specific faction
|
||||
function displayFactionContent(factionName) {
|
||||
var faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error("Invalid factionName passed into displayFactionContent: " + factionName);
|
||||
}
|
||||
if (!faction.isMember) {
|
||||
throw new Error("Not a member of this faction, cannot display faction information");
|
||||
}
|
||||
var factionInfo = faction.getInfo();
|
||||
|
||||
removeChildrenFromElement(Engine.Display.factionContent);
|
||||
var elements = [];
|
||||
|
||||
//Header and faction info
|
||||
elements.push(createElement("h1", {
|
||||
innerText:factionName
|
||||
}));
|
||||
elements.push(createElement("pre", {
|
||||
innerHTML:"<i>" + factionInfo.infoText + "</i>"
|
||||
}));
|
||||
elements.push(createElement("p", {
|
||||
innerText:"---------------",
|
||||
}));
|
||||
|
||||
//Faction reputation and favor
|
||||
var favorGain = faction.getFavorGain();
|
||||
if (favorGain.length != 2) {favorGain = 0;}
|
||||
favorGain = favorGain[0];
|
||||
elements.push(createElement("p", {
|
||||
innerText: "Reputation: " + formatNumber(faction.playerReputation, 4),
|
||||
tooltip:"You will earn " + formatNumber(favorGain, 0) +
|
||||
" faction favor upon resetting after installing an Augmentation"
|
||||
}))
|
||||
elements.push(createElement("p", {
|
||||
innerText:"---------------",
|
||||
}));
|
||||
elements.push(createElement("p", {
|
||||
innerText:"Faction Favor: " + formatNumber(faction.favor, 0),
|
||||
tooltip:"Faction favor increases the rate at which " +
|
||||
"you earn reputation for this faction by 1% per favor. Faction favor " +
|
||||
"is gained whenever you reset after installing an Augmentation. The amount of " +
|
||||
"favor you gain depends on how much reputation you have with the faction"
|
||||
}));
|
||||
elements.push(createElement("p", {
|
||||
innerText:"---------------",
|
||||
}));
|
||||
|
||||
//Faction Work Description Text
|
||||
elements.push(createElement("pre", {
|
||||
id:"faction-work-description-text",
|
||||
innerText:"Perform work/carry out assignments for your faction to help further its cause! By doing so " +
|
||||
"you will earn reputation for your faction. You will also gain reputation passively over time, " +
|
||||
"although at a very slow rate. Earning reputation will allow you to purchase Augmentations " +
|
||||
"through this faction, which are powerful upgrades that enhance your abilities. Note that you cannot " +
|
||||
"use your terminal or create scripts when you are performing a task!"
|
||||
}));
|
||||
elements.push(createElement("br"));
|
||||
|
||||
//Hacking Mission Option
|
||||
var hackMissionDiv = createElement("div", { class:"faction-work-div" });
|
||||
var hackMissionDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
hackMissionDiv.appendChild(hackMissionDivWrapper);
|
||||
hackMissionDivWrapper.appendChild(createElement("a", {
|
||||
class:"a-link-button", innerText:"Hacking Mission",
|
||||
clickListener:()=>{
|
||||
Engine.loadMissionContent();
|
||||
var mission = new HackingMission(faction.playerReputation, faction);
|
||||
setInMission(true, mission); //Sets inMission flag to true
|
||||
mission.init();
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
hackMissionDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Attempt a hacking mission for your faction. " +
|
||||
"A mission is a mini game that, if won, earns you " +
|
||||
"significant reputation with this faction. (Recommended hacking level: 200+)"
|
||||
}));
|
||||
elements.push(hackMissionDiv);
|
||||
|
||||
//Hacking Contracts Option
|
||||
var hackDiv = createElement("div", { class:"faction-work-div", });
|
||||
var hackDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
hackDiv.appendChild(hackDivWrapper);
|
||||
hackDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Hacking Contracts",
|
||||
clickListener:()=>{
|
||||
Player.startFactionHackWork(faction);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
hackDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Complete hacking contracts for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your hacking skill. " +
|
||||
"You will gain hacking exp."
|
||||
}));
|
||||
elements.push(hackDiv);
|
||||
|
||||
//Field Work Option
|
||||
var fieldWorkDiv = createElement("div", { class:"faction-work-div" });
|
||||
var fieldWorkDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
fieldWorkDiv.appendChild(fieldWorkDivWrapper);
|
||||
fieldWorkDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Field Work",
|
||||
clickListener:()=>{
|
||||
Player.startFactionFieldWork(faction);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
fieldWorkDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Carry out field missions for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on all of your stats. " +
|
||||
"You will gain exp for all stats."
|
||||
}));
|
||||
elements.push(fieldWorkDiv);
|
||||
|
||||
//Security Work Option
|
||||
var securityWorkDiv = createElement("div", { class:"faction-work-div" });
|
||||
var securityWorkDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
securityWorkDiv.appendChild(securityWorkDivWrapper);
|
||||
securityWorkDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Security Work",
|
||||
clickListener:()=>{
|
||||
Player.startFactionSecurityWork(faction);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
securityWorkDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Serve in a security detail for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your combat stats. " +
|
||||
"You will gain exp for all combat stats."
|
||||
}));
|
||||
elements.push(securityWorkDiv);
|
||||
|
||||
//Donate for reputation
|
||||
var donateDiv = createElement("div", { class:"faction-work-div" });
|
||||
var donateDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
donateDiv.appendChild(donateDivWrapper);
|
||||
var donateRepGain = createElement("p", {
|
||||
innerText:"This donation will result in 0.000 reputation gain"
|
||||
});
|
||||
var donateAmountInput = createElement("input", {
|
||||
class: "text-input", placeholder:"Donation amount",
|
||||
inputListener:()=>{
|
||||
let amt = 0;
|
||||
if(donateAmountInput.value !== "") {
|
||||
amt = parseFloat(donateAmountInput.value);
|
||||
}
|
||||
if (isNaN(amt)) {
|
||||
donateRepGain.innerText = "Invalid donate amount entered!";
|
||||
} else {
|
||||
var repGain = amt / CONSTANTS.DonateMoneyToRepDivisor * Player.faction_rep_mult;
|
||||
donateRepGain.innerText = "This donation will result in " +
|
||||
formatNumber(repGain, 3) + " reputation gain";
|
||||
}
|
||||
},
|
||||
});
|
||||
donateDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Donate Money",
|
||||
clickListener:()=>{
|
||||
var amt = parseFloat(donateAmountInput.value);
|
||||
if (isNaN(amt) || amt < 0) {
|
||||
dialogBoxCreate("Invalid amount entered!");
|
||||
} else if (Player.money.lt(amt)) {
|
||||
dialogBoxCreate("You cannot afford to donate this much money!");
|
||||
} else {
|
||||
Player.loseMoney(amt);
|
||||
var repGain = amt / CONSTANTS.DonateMoneyToRepDivisor * Player.faction_rep_mult;
|
||||
faction.playerReputation += repGain;
|
||||
dialogBoxCreate("You just donated " + numeralWrapper.format(amt, "$0.000a") + " to " +
|
||||
faction.name + " to gain " + formatNumber(repGain, 3) + " reputation");
|
||||
displayFactionContent(factionName);
|
||||
}
|
||||
}
|
||||
}));
|
||||
donateDivWrapper.appendChild(donateAmountInput);
|
||||
donateDivWrapper.appendChild(donateRepGain);
|
||||
elements.push(donateDiv);
|
||||
|
||||
//Purchase Augmentations
|
||||
const purchaseAugmentationsDiv = createElement("div", { class: "faction-work-div", display: "inline" });
|
||||
const purchaseAugmentationsDivWrapper = createElement("div", { class: "faction-work-div-wrapper" });
|
||||
purchaseAugmentationsDiv.appendChild(purchaseAugmentationsDivWrapper);
|
||||
purchaseAugmentationsDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button",
|
||||
innerText:"Purchase Augmentations",
|
||||
margin: "5px",
|
||||
clickListener:()=>{
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.factionAugmentationsContent.style.display = "block";
|
||||
|
||||
displayFactionAugmentations(factionName);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
purchaseAugmentationsDivWrapper.appendChild(createElement("pre", {
|
||||
innerHTML: "<br>As your reputation with this faction rises, you will " +
|
||||
"unlock Augmentations, which you can purchase to enhance " +
|
||||
"your abilities.<br><br>"
|
||||
}));
|
||||
elements.push(purchaseAugmentationsDiv);
|
||||
|
||||
//Gang (BitNode-2)
|
||||
if (Player.bitNodeN == 2 && (factionName == "Slum Snakes" || factionName == "Tetrads" ||
|
||||
factionName == "The Syndicate" || factionName == "The Dark Army" || factionName == "Speakers for the Dead" ||
|
||||
factionName == "NiteSec" || factionName == "The Black Hand")) {
|
||||
//Set everything else to invisible
|
||||
hackMissionDiv.style.display = "none";
|
||||
hackDiv.style.display = "none";
|
||||
fieldWorkDiv.style.display = "none";
|
||||
securityWorkDiv.style.display = "none";
|
||||
donateDiv.style.display = "none";
|
||||
|
||||
//Create the 'Manage Gang' button
|
||||
var gangDiv = createElement("div", {
|
||||
id:"faction-gang-div", class:"faction-work-div", display:"inline"
|
||||
});
|
||||
var gangDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
gangDiv.appendChild(gangDivWrapper);
|
||||
gangDivWrapper.appendChild(createElement("a", {
|
||||
class:"a-link-button", innerText:"Manage Gang",
|
||||
clickListener: () => {
|
||||
if (!Player.inGang()) {
|
||||
// Determine whether this is a hacking gang
|
||||
let hacking = false;
|
||||
if (factionName === "NiteSec" || factionName === "The Black Hand") { hacking = true; }
|
||||
|
||||
// Configure Yes/No buttons for the pop-up
|
||||
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Create Gang";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", () => {
|
||||
Player.startGang(factionName, hacking);
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
Engine.loadGangContent();
|
||||
yesNoBoxClose();
|
||||
});
|
||||
noBtn.addEventListener("click", () => {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
// Pop-up text
|
||||
let gangTypeText = "";
|
||||
if (hacking) {
|
||||
gangTypeText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
"Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " +
|
||||
"is not as important.<br><br>";
|
||||
} else {
|
||||
gangTypeText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
|
||||
"is more important. However, well-managed combat gangs can progress faster than hacking ones.<br><br>";
|
||||
}
|
||||
yesNoBoxCreate(`Would you like to create a new Gang with ${factionName}?<br><br>` +
|
||||
"Note that this will prevent you from creating a Gang with any other Faction until " +
|
||||
"this BitNode is destroyed.<br><br>" +
|
||||
gangTypeText +
|
||||
"Other than hacking vs combat, there are NO differences between the Factions you can " +
|
||||
"create a Gang with, and each of these Factions have all Augmentations available.");
|
||||
} else {
|
||||
Engine.loadGangContent();
|
||||
}
|
||||
}
|
||||
}));
|
||||
gangDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Create and manage a gang for this Faction. " +
|
||||
"Gangs will earn you money and faction reputation."
|
||||
}));
|
||||
//Manage Gang button goes before Faction work stuff
|
||||
elements.splice(7, 1, gangDiv);
|
||||
|
||||
if (Player.inGang() && Player.gang.facName != factionName) {
|
||||
//If the player has a gang but its not for this faction
|
||||
gangDiv.style.display = "none";
|
||||
}
|
||||
//Display all elements
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
Engine.Display.factionContent.appendChild(elements[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Purchase Sleeves from Covenant
|
||||
if (factionName === "The Covenant" && Player.bitNodeN >= 10 && SourceFileFlags[10]) {
|
||||
const covenantPurchaseSleevesDiv = createElement("div", { class: "faction-work-div", display: "inline" });
|
||||
const covenantPurchaseSleevesDivWrapper = createElement("div", { class: "faction-work-div-wrapper" });
|
||||
covenantPurchaseSleevesDiv.appendChild(covenantPurchaseSleevesDivWrapper);
|
||||
covenantPurchaseSleevesDivWrapper.appendChild(createElement("a", {
|
||||
class: "std-button",
|
||||
innerText: "Purchase Duplicate Sleeves",
|
||||
clickListener: () => {
|
||||
createSleevePurchasesFromCovenantPopup(Player);
|
||||
}
|
||||
}));
|
||||
covenantPurchaseSleevesDivWrapper.appendChild(createElement("p", {
|
||||
innerText: "Purchase Duplicate Sleeves. These are permanent! You can purchase up to 5 total.",
|
||||
}));
|
||||
|
||||
elements.push(covenantPurchaseSleevesDiv);
|
||||
}
|
||||
|
||||
// Determine if actions should be possible
|
||||
donateDiv.style.display = faction.favor >= Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction) ? "inline" : "none";
|
||||
|
||||
hackMissionDiv.style.display = factionInfo.offerHackingMission ? "inline": "none";
|
||||
hackDiv.style.display = factionInfo.offerHackingWork ? "inline" : "none";
|
||||
fieldWorkDiv.style.display = factionInfo.offerFieldWork ? "inline" : "none";
|
||||
securityWorkDiv.style.display = factionInfo.offerSecurityWork ? "inline" : "none";
|
||||
|
||||
//Display all elements
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
Engine.Display.factionContent.appendChild(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function displayFactionAugmentations(factionName) {
|
||||
var faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error("Could not find faction " + factionName + " in displayFactionAugmentations");
|
||||
}
|
||||
|
||||
removeChildrenFromElement(Engine.Display.factionAugmentationsContent);
|
||||
var elements = [];
|
||||
|
||||
//Back button
|
||||
elements.push(createElement("a", {
|
||||
innerText:"Back", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Engine.loadFactionContent();
|
||||
displayFactionContent(factionName);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
//Header text
|
||||
elements.push(createElement("h1", {innerText:"Faction Augmentations"}));
|
||||
elements.push(createElement("p", {
|
||||
id:"faction-augmentations-page-desc",
|
||||
innerHTML:"Lists all Augmentations that are available to purchase from " + factionName + "<br><br>" +
|
||||
"Augmentations are powerful upgrades that will enhance your abilities."
|
||||
}));
|
||||
|
||||
elements.push(createElement("br"));
|
||||
elements.push(createElement("br"));
|
||||
|
||||
//Augmentations List
|
||||
var augmentationsList = createElement("ul");
|
||||
|
||||
//Sort buttons
|
||||
const sortByCostBtn = createElement("a", {
|
||||
innerText:"Sort by Cost", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Cost;
|
||||
var augs = faction.augmentations.slice();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
return aug1.baseCost - aug2.baseCost;
|
||||
});
|
||||
removeChildrenFromElement(augmentationsList);
|
||||
createFactionAugmentationDisplayElements(augmentationsList, augs, faction);
|
||||
}
|
||||
});
|
||||
const sortByRepBtn = createElement("a", {
|
||||
innerText:"Sort by Reputation", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Reputation;
|
||||
var augs = faction.augmentations.slice();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
return aug1.baseRepRequirement - aug2.baseRepRequirement;
|
||||
});
|
||||
removeChildrenFromElement(augmentationsList);
|
||||
createFactionAugmentationDisplayElements(augmentationsList, augs, faction);
|
||||
}
|
||||
});
|
||||
const defaultSortBtn = createElement("a", {
|
||||
innerText:"Sort by Default Order", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Default;
|
||||
removeChildrenFromElement(augmentationsList);
|
||||
createFactionAugmentationDisplayElements(augmentationsList, faction.augmentations, faction);
|
||||
}
|
||||
});
|
||||
elements.push(sortByCostBtn);
|
||||
elements.push(sortByRepBtn);
|
||||
elements.push(defaultSortBtn);
|
||||
switch(Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost:
|
||||
sortByCostBtn.click();
|
||||
break;
|
||||
case PurchaseAugmentationsOrderSetting.Reputation:
|
||||
sortByRepBtn.click();
|
||||
break;
|
||||
default:
|
||||
defaultSortBtn.click();
|
||||
break;
|
||||
}
|
||||
|
||||
elements.push(augmentationsList);
|
||||
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
Engine.Display.factionAugmentationsContent.appendChild(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//Takes in an array of Augmentation Names, constructs DOM elements
|
||||
//to list them on the faction page, and appends them to the given
|
||||
//DOM element
|
||||
// @augmentationsList DOM List to append Aug DOM elements to
|
||||
// @augs Array of Aug names
|
||||
// @faction Faction for which to display Augmentations
|
||||
function createFactionAugmentationDisplayElements(augmentationsList, augs, faction) {
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
for (var i = 0; i < augs.length; ++i) {
|
||||
(function () {
|
||||
var aug = Augmentations[augs[i]];
|
||||
if (aug == null) {
|
||||
throw new Error("Invalid Augmentation when trying to create Augmentation display Elements");
|
||||
}
|
||||
var owned = false;
|
||||
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name == aug.name) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < Player.augmentations.length; ++j) {
|
||||
if (Player.augmentations[j].name == aug.name) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var item = createElement("li");
|
||||
var span = createElement("span", { display:"inline-block", margin: "4px", padding: "4px" });
|
||||
var aDiv = createElement("div", {tooltip:aug.info});
|
||||
var aElem = createElement("a", {
|
||||
innerText:aug.name, display:"inline",
|
||||
clickListener:()=>{
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
purchaseAugmentationBoxCreate(aug, faction);
|
||||
} else {
|
||||
purchaseAugmentation(aug, faction);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
aElem.innerText += " - Level " + (getNextNeurofluxLevel());
|
||||
}
|
||||
var pElem = createElement("p", {
|
||||
display:"inline",
|
||||
})
|
||||
var req = aug.baseRepRequirement * factionInfo.augmentationRepRequirementMult;
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
aElem.setAttribute("class", "a-link-button-inactive");
|
||||
pElem.innerHTML = "LOCKED (Requires " + aug.prereqs.join(",") + " as prerequisite(s))";
|
||||
pElem.style.color = "red";
|
||||
} else if (aug.name != AugmentationNames.NeuroFluxGovernor && (aug.owned || owned)) {
|
||||
aElem.setAttribute("class", "a-link-button-inactive");
|
||||
pElem.innerHTML = "ALREADY OWNED";
|
||||
} else if (faction.playerReputation >= req) {
|
||||
aElem.setAttribute("class", "a-link-button");
|
||||
pElem.innerHTML = "UNLOCKED - " + numeralWrapper.format(aug.baseCost * factionInfo.augmentationPriceMult, "$0.000a");
|
||||
} else {
|
||||
aElem.setAttribute("class", "a-link-button-inactive");
|
||||
pElem.innerHTML = "LOCKED (Requires " + formatNumber(req, 1) + " faction reputation) - " + numeralWrapper.format(aug.baseCost * factionInfo.augmentationPriceMult, "$0.000a");
|
||||
pElem.style.color = "red";
|
||||
}
|
||||
aDiv.appendChild(aElem);
|
||||
span.appendChild(aDiv);
|
||||
span.appendChild(pElem);
|
||||
item.appendChild(span);
|
||||
augmentationsList.appendChild(item);
|
||||
}()); //Immediate invocation closure
|
||||
}
|
||||
}
|
||||
|
||||
function purchaseAugmentationBoxCreate(aug, fac) {
|
||||
const factionInfo = fac.getInfo();
|
||||
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Purchase";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
purchaseAugmentation(aug, fac);
|
||||
});
|
||||
noBtn.addEventListener("click", function() {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
|
||||
aug.info + "<br><br>" +
|
||||
"<br>Would you like to purchase the " + aug.name + " Augmentation for $" +
|
||||
formatNumber(aug.baseCost * factionInfo.augmentationPriceMult, 2) + "?");
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
function hasAugmentationPrereqs(aug) {
|
||||
var hasPrereqs = true;
|
||||
if (aug.prereqs && aug.prereqs.length > 0) {
|
||||
for (var i = 0; i < aug.prereqs.length; ++i) {
|
||||
var prereqAug = Augmentations[aug.prereqs[i]];
|
||||
if (prereqAug == null) {
|
||||
console.log("ERROR: Invalid prereq Augmentation: " + aug.prereqs[i]);
|
||||
continue;
|
||||
}
|
||||
if (prereqAug.owned === false) {
|
||||
hasPrereqs = false;
|
||||
|
||||
//Check if the aug is purchased
|
||||
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name === prereqAug.name) {
|
||||
hasPrereqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasPrereqs;
|
||||
}
|
||||
|
||||
function purchaseAugmentation(aug, fac, sing=false) {
|
||||
const factionInfo = fac.getInfo();
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
|
||||
"purchase this one.";
|
||||
if (sing) {return txt;} else {dialogBoxCreate(txt);}
|
||||
} else if (aug.baseCost !== 0 && Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
let txt = "You don't have enough money to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (fac.playerReputation < aug.baseRepRequirement) {
|
||||
let txt = "You don't have enough faction reputation to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
if (Player.firstAugPurchased === false) {
|
||||
Player.firstAugPurchased = true;
|
||||
document.getElementById("augmentations-tab").style.display = "list-item";
|
||||
document.getElementById("character-menu-header").click();
|
||||
document.getElementById("character-menu-header").click();
|
||||
}
|
||||
|
||||
var queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
queuedAugmentation.level = getNextNeurofluxLevel();
|
||||
}
|
||||
Player.queuedAugmentations.push(queuedAugmentation);
|
||||
|
||||
Player.loseMoney((aug.baseCost * factionInfo.augmentationPriceMult));
|
||||
|
||||
//If you just purchased Neuroflux Governor, recalculate the cost
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
var nextLevel = getNextNeurofluxLevel();
|
||||
--nextLevel;
|
||||
var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
||||
aug.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||
aug.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
|
||||
for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) {
|
||||
aug.baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in Augmentations) {
|
||||
if (Augmentations.hasOwnProperty(name)) {
|
||||
Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (sing) {
|
||||
return "You purchased " + aug.name;
|
||||
} else {
|
||||
if(!Settings.SuppressBuyAugmentationConfirmation){
|
||||
dialogBoxCreate("You purchased " + aug.name + ". It's enhancements will not take " +
|
||||
"effect until they are installed. To install your augmentations, go to the " +
|
||||
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
||||
"augmentations will now be more expensive.");
|
||||
}
|
||||
}
|
||||
|
||||
displayFactionAugmentations(fac.name);
|
||||
} else {
|
||||
dialogBoxCreate("Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.");
|
||||
}
|
||||
yesNoBoxClose();
|
||||
}
|
||||
|
||||
function getNextNeurofluxLevel() {
|
||||
// Get current Neuroflux level based on Player's augmentations
|
||||
let currLevel = 0;
|
||||
for (var i = 0; i < Player.augmentations.length; ++i) {
|
||||
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
||||
currLevel = Player.augmentations[i].level;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for purchased but uninstalled Augmentations
|
||||
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||
++currLevel;
|
||||
}
|
||||
}
|
||||
return currLevel + 1;
|
||||
}
|
||||
|
||||
function processPassiveFactionRepGain(numCycles) {
|
||||
var numTimesGain = (numCycles / 600) * Player.faction_rep_mult;
|
||||
for (var name in Factions) {
|
||||
if (Factions.hasOwnProperty(name)) {
|
||||
var faction = Factions[name];
|
||||
|
||||
//TODO Get hard value of 1 rep per "rep gain cycle"" for now..
|
||||
//maybe later make this based on
|
||||
//a player's 'status' like how powerful they are and how much money they have
|
||||
if (faction.isMember) {faction.playerReputation += (numTimesGain * BitNodeMultipliers.FactionPassiveRepGain);}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {getNextNeurofluxLevel, inviteToFaction,
|
||||
joinFaction, displayFactionContent, processPassiveFactionRepGain,
|
||||
purchaseAugmentation};
|
240
src/Faction/FactionHelpers.jsx
Normal file
240
src/Faction/FactionHelpers.jsx
Normal file
@ -0,0 +1,240 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { FactionRoot } from "./ui/Root";
|
||||
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Engine } from "../engine";
|
||||
import { Faction } from "./Faction";
|
||||
import { Factions } from "./Factions";
|
||||
import { HackingMission, setInMission } from "../Missions";
|
||||
import { Player } from "../Player";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
|
||||
import { Page, routing } from "../ui/navigationTracking";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { factionInvitationBoxCreate } from "../../utils/FactionInvitationBox";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON
|
||||
} from "../../utils/JSONReviver";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import {
|
||||
yesNoBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxClose
|
||||
} from "../../utils/YesNoBox";
|
||||
|
||||
export function inviteToFaction(faction) {
|
||||
if (Settings.SuppressFactionInvites) {
|
||||
faction.alreadyInvited = true;
|
||||
Player.factionInvitations.push(faction.name);
|
||||
if (routing.isOn(Page.Factions)) {
|
||||
Engine.loadFactionsContent();
|
||||
}
|
||||
} else {
|
||||
factionInvitationBoxCreate(faction);
|
||||
}
|
||||
}
|
||||
|
||||
export function joinFaction(faction) {
|
||||
faction.isMember = true;
|
||||
Player.factions.push(faction.name);
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
//Determine what factions you are banned from now that you have joined this faction
|
||||
for(const i in factionInfo.enemies) {
|
||||
const enemy = factionInfo.enemies[i];
|
||||
if (Factions[enemy] instanceof Faction) {
|
||||
Factions[enemy].isBanned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function startHackingMission(faction) {
|
||||
const mission = new HackingMission(faction.playerReputation, faction);
|
||||
setInMission(true, mission); //Sets inMission flag to true
|
||||
mission.init();
|
||||
}
|
||||
|
||||
//Displays the HTML content for a specific faction
|
||||
export function displayFactionContent(factionName, initiallyOnAugmentationsPage=false) {
|
||||
const faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error(`Invalid factionName passed into displayFactionContent(): ${factionName}`);
|
||||
}
|
||||
|
||||
if (!faction.isMember) {
|
||||
throw new Error(`Not a member of this faction. Cannot display faction information`);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<FactionRoot
|
||||
engine={Engine}
|
||||
initiallyOnAugmentationsPage={initiallyOnAugmentationsPage}
|
||||
faction={faction}
|
||||
p={Player}
|
||||
startHackingMissionFn={startHackingMission}
|
||||
/>,
|
||||
Engine.Display.factionContent
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export function purchaseAugmentationBoxCreate(aug, fac) {
|
||||
const factionInfo = fac.getInfo();
|
||||
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
yesBtn.innerHTML = "Purchase";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
purchaseAugmentation(aug, fac);
|
||||
});
|
||||
|
||||
const noBtn = yesNoBoxGetNoButton();
|
||||
noBtn.innerHTML = "Cancel";
|
||||
noBtn.addEventListener("click", function() {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
|
||||
aug.info + "<br><br>" +
|
||||
"<br>Would you like to purchase the " + aug.name + " Augmentation for $" +
|
||||
formatNumber(aug.baseCost * factionInfo.augmentationPriceMult, 2) + "?");
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
export function hasAugmentationPrereqs(aug) {
|
||||
let hasPrereqs = true;
|
||||
if (aug.prereqs && aug.prereqs.length > 0) {
|
||||
for (let i = 0; i < aug.prereqs.length; ++i) {
|
||||
const prereqAug = Augmentations[aug.prereqs[i]];
|
||||
if (prereqAug == null) {
|
||||
console.error(`Invalid prereq Augmentation ${aug.prereqs[i]}`);
|
||||
continue;
|
||||
}
|
||||
if (prereqAug.owned === false) {
|
||||
hasPrereqs = false;
|
||||
|
||||
// Check if the aug is purchased
|
||||
for (let j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name === prereqAug.name) {
|
||||
hasPrereqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasPrereqs;
|
||||
}
|
||||
|
||||
export function purchaseAugmentation(aug, fac, sing=false) {
|
||||
const factionInfo = fac.getInfo();
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
|
||||
"purchase this one.";
|
||||
if (sing) {return txt;} else {dialogBoxCreate(txt);}
|
||||
} else if (aug.baseCost !== 0 && Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
let txt = "You don't have enough money to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (fac.playerReputation < aug.baseRepRequirement) {
|
||||
let txt = "You don't have enough faction reputation to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
if (Player.firstAugPurchased === false) {
|
||||
Player.firstAugPurchased = true;
|
||||
document.getElementById("augmentations-tab").style.display = "list-item";
|
||||
document.getElementById("character-menu-header").click();
|
||||
document.getElementById("character-menu-header").click();
|
||||
}
|
||||
|
||||
var queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
queuedAugmentation.level = getNextNeurofluxLevel();
|
||||
}
|
||||
Player.queuedAugmentations.push(queuedAugmentation);
|
||||
|
||||
Player.loseMoney((aug.baseCost * factionInfo.augmentationPriceMult));
|
||||
|
||||
// If you just purchased Neuroflux Governor, recalculate the cost
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
var nextLevel = getNextNeurofluxLevel();
|
||||
--nextLevel;
|
||||
var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
||||
aug.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||
aug.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
|
||||
for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) {
|
||||
aug.baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in Augmentations) {
|
||||
if (Augmentations.hasOwnProperty(name)) {
|
||||
Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (sing) {
|
||||
return "You purchased " + aug.name;
|
||||
} else {
|
||||
if(!Settings.SuppressBuyAugmentationConfirmation){
|
||||
dialogBoxCreate("You purchased " + aug.name + ". It's enhancements will not take " +
|
||||
"effect until they are installed. To install your augmentations, go to the " +
|
||||
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
||||
"augmentations will now be more expensive.");
|
||||
}
|
||||
}
|
||||
|
||||
// Force a rerender of the Augmentations page
|
||||
displayFactionContent(fac.name, true);
|
||||
} else {
|
||||
dialogBoxCreate("Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.");
|
||||
}
|
||||
yesNoBoxClose();
|
||||
}
|
||||
|
||||
export function getNextNeurofluxLevel() {
|
||||
// Get current Neuroflux level based on Player's augmentations
|
||||
let currLevel = 0;
|
||||
for (var i = 0; i < Player.augmentations.length; ++i) {
|
||||
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
||||
currLevel = Player.augmentations[i].level;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for purchased but uninstalled Augmentations
|
||||
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||
++currLevel;
|
||||
}
|
||||
}
|
||||
return currLevel + 1;
|
||||
}
|
||||
|
||||
export function processPassiveFactionRepGain(numCycles) {
|
||||
var numTimesGain = (numCycles / 600) * Player.faction_rep_mult;
|
||||
for (var name in Factions) {
|
||||
if (Factions.hasOwnProperty(name)) {
|
||||
var faction = Factions[name];
|
||||
|
||||
//TODO Get hard value of 1 rep per "rep gain cycle"" for now..
|
||||
//maybe later make this based on
|
||||
//a player's 'status' like how powerful they are and how much money they have
|
||||
if (faction.isMember) {faction.playerReputation += (numTimesGain * BitNodeMultipliers.FactionPassiveRepGain);}
|
||||
}
|
||||
}
|
||||
}
|
163
src/Faction/ui/AugmentationsPage.tsx
Normal file
163
src/Faction/ui/AugmentationsPage.tsx
Normal file
@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Root React Component for displaying a faction's "Purchase Augmentations" page
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
routeToMainPage: () => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
sortOrder: PurchaseAugmentationsOrderSetting;
|
||||
}
|
||||
|
||||
const infoStyleMarkup = {
|
||||
width: "70%",
|
||||
}
|
||||
|
||||
export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
// Flag for whether the player has a gang with this faction
|
||||
isPlayersGang: boolean;
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.isPlayersGang = props.p.inGang() && (props.p.getGangName() === props.faction.name);
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
sortOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||
}
|
||||
|
||||
this.rerender = this.rerender.bind(this);
|
||||
}
|
||||
|
||||
getAugs() {
|
||||
if (this.isPlayersGang) {
|
||||
const augs: string[] = [];
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug.isSpecial) {
|
||||
augs.push(augName);
|
||||
}
|
||||
}
|
||||
|
||||
return augs;
|
||||
} else {
|
||||
return this.props.faction.augmentations.slice();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSorted() {
|
||||
switch (Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost: {
|
||||
return this.getAugsSortedByCost();
|
||||
}
|
||||
case PurchaseAugmentationsOrderSetting.Reputation: {
|
||||
return this.getAugsSortedByReputation();
|
||||
}
|
||||
default:
|
||||
return this.getAugsSortedByDefault();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSortedByCost() {
|
||||
const augs = this.getAugs();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
|
||||
return aug1.baseCost - aug2.baseCost;
|
||||
});
|
||||
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByReputation() {
|
||||
const augs = this.getAugs();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
return aug1.baseRepRequirement - aug2.baseRepRequirement;
|
||||
});
|
||||
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByDefault() {
|
||||
return this.getAugs();
|
||||
}
|
||||
|
||||
switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting) {
|
||||
Settings.PurchaseAugmentationsOrder = newOrder;
|
||||
this.rerender();
|
||||
}
|
||||
|
||||
rerender() {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const augs = this.getAugsSorted();
|
||||
const augList = augs.map((aug) => {
|
||||
return (
|
||||
<PurchaseableAugmentation
|
||||
augName={aug}
|
||||
faction={this.props.faction}
|
||||
key={aug}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton
|
||||
onClick={this.props.routeToMainPage}
|
||||
text={"Back"}
|
||||
/>
|
||||
<h1>Faction Augmentations</h1>
|
||||
<p style={infoStyleMarkup}>
|
||||
These are all of the Augmentations that are available to purchase
|
||||
from {this.props.faction.name}. Augmentations are powerful upgrades
|
||||
that will enhance your abilities.
|
||||
</p>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}
|
||||
text={"Sort by Cost"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
||||
text={"Sort by Reputation"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
||||
text={"Sort by Default Order"}
|
||||
/>
|
||||
<br />
|
||||
{augList}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
101
src/Faction/ui/DonateOption.tsx
Normal file
101
src/Faction/ui/DonateOption.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* React component for a donate option on the Faction UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
donateAmt: number;
|
||||
statusTxt: string;
|
||||
}
|
||||
|
||||
const inputStyleMarkup = {
|
||||
margin: "5px",
|
||||
}
|
||||
|
||||
export class DonateOption extends React.Component<IProps, IState> {
|
||||
// Style markup for block elements. Stored as property
|
||||
blockStyle: object = { display: "block" };
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
donateAmt: 0,
|
||||
statusTxt: "",
|
||||
}
|
||||
|
||||
this.calculateRepGain = this.calculateRepGain.bind(this);
|
||||
this.donate = this.donate.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
|
||||
// Returns rep gain for the current donation amount
|
||||
calculateRepGain(): number {
|
||||
return this.state.donateAmt / CONSTANTS.DonateMoneyToRepDivisor * this.props.p.faction_rep_mult;
|
||||
}
|
||||
|
||||
donate(): void {
|
||||
const fac = this.props.faction;
|
||||
const amt = this.state.donateAmt;
|
||||
if (isNaN(amt) || amt <= 0) {
|
||||
dialogBoxCreate(`Invalid amount entered!`);
|
||||
} else if (!this.props.p.canAfford(amt)) {
|
||||
dialogBoxCreate(`You cannot afford to donate this much money!`);
|
||||
} else {
|
||||
this.props.p.loseMoney(amt);
|
||||
const repGain = this.calculateRepGain();
|
||||
this.props.faction.playerReputation += repGain;
|
||||
dialogBoxCreate(`You just donated ${numeralWrapper.formatMoney(amt)} to ${fac.name} to gain ` +
|
||||
`${numeralWrapper.format(repGain, "0,0.000")} reputation`);
|
||||
this.props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const amt = parseFloat(e.target.value);
|
||||
|
||||
if (isNaN(amt)) {
|
||||
this.setState({
|
||||
donateAmt: 0,
|
||||
statusTxt: "Invalid donate amount entered!",
|
||||
});
|
||||
} else {
|
||||
const repGain = this.calculateRepGain();
|
||||
this.setState({
|
||||
donateAmt: amt,
|
||||
statusTxt: `This donation will result in ${numeralWrapper.format(repGain, "0,0.000")} reputation gain`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={"faction-work-div"}>
|
||||
<div className={"faction-work-div-wrapper"}>
|
||||
<input onChange={this.handleChange} placeholder={"Donation amount"} style={inputStyleMarkup} />
|
||||
<StdButton
|
||||
onClick={this.donate}
|
||||
text={"Donate Money"}
|
||||
/>
|
||||
<p style={this.blockStyle}>{this.state.statusTxt}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
72
src/Faction/ui/Info.tsx
Normal file
72
src/Faction/ui/Info.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* React component for general information about the faction. This includes the
|
||||
* factions "motto", reputation, favor, and gameplay instructions
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { FactionInfo } from "../../Faction/FactionInfo";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { AutoupdatingParagraph } from "../../ui/React/AutoupdatingParagraph";
|
||||
import { ParagraphWithTooltip } from "../../ui/React/ParagraphWithTooltip";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
factionInfo: FactionInfo;
|
||||
}
|
||||
|
||||
type IInnerHTMLMarkup = {
|
||||
__html: string;
|
||||
}
|
||||
|
||||
const blockStyleMarkup = {
|
||||
display: "block",
|
||||
}
|
||||
|
||||
const infoStyleMarkup = {
|
||||
display: "block",
|
||||
width: "70%",
|
||||
}
|
||||
|
||||
export class Info extends React.Component<IProps, any> {
|
||||
render() {
|
||||
|
||||
const formattedRep = numeralWrapper.format(this.props.faction.playerReputation, "0.000a");
|
||||
const favorGain = this.props.faction.getFavorGain()[0];
|
||||
const favorTooltip = "Faction favor increases the rate at which you earn reputation for " +
|
||||
"this faction by 1% per favor. Faction favor is gained whenever you " +
|
||||
"reset after installing an Augmentation. The amount of " +
|
||||
"favor you gain depends on how much reputation you have with the faction"
|
||||
|
||||
const infoText: IInnerHTMLMarkup = {
|
||||
__html: this.props.factionInfo.infoText,
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<i className={"text"} style={infoStyleMarkup} dangerouslySetInnerHTML={infoText}></i>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<AutoupdatingParagraph
|
||||
intervalTime={5e3}
|
||||
text={`Reputation: ${formattedRep}`}
|
||||
tooltip={`You will earn ${numeralWrapper.format(favorGain, "0,0")} faction favor upon resetting after installing an Augmentation`}
|
||||
/>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<ParagraphWithTooltip
|
||||
text={`Faction Favor: ${numeralWrapper.format(this.props.faction.favor, "0,0")}`}
|
||||
tooltip={favorTooltip}
|
||||
/>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<p style={infoStyleMarkup}>
|
||||
Perform work/carry out assignments for your faction to help further its cause!
|
||||
By doing so you will earn reputation for your faction. You will also gain
|
||||
reputation passively over time, although at a very slow rate. Earning
|
||||
reputation will allow you to purchase Augmentations through this faction, which
|
||||
are powerful upgrades that enhance your abilities. Note that you cannot use your
|
||||
terminal or create scripts when you are performing a task!
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
30
src/Faction/ui/Option.tsx
Normal file
30
src/Faction/ui/Option.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* React component for a selectable option on the Faction UI. These
|
||||
* options including working for the faction, hacking missions, purchasing
|
||||
* augmentations, etc.
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
buttonText: string;
|
||||
infoText: string;
|
||||
onClick: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
}
|
||||
|
||||
export class Option extends React.Component<IProps, any> {
|
||||
render() {
|
||||
return (
|
||||
<div className={"faction-work-div"}>
|
||||
<div className={"faction-work-div-wrapper"}>
|
||||
<StdButton
|
||||
onClick={this.props.onClick}
|
||||
text={this.props.buttonText}
|
||||
/>
|
||||
<p>{this.props.infoText}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
151
src/Faction/ui/PurchaseableAugmentation.tsx
Normal file
151
src/Faction/ui/PurchaseableAugmentation.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* React component for displaying a single augmentation for purchase through
|
||||
* the faction UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
getNextNeurofluxLevel,
|
||||
hasAugmentationPrereqs,
|
||||
purchaseAugmentation,
|
||||
purchaseAugmentationBoxCreate,
|
||||
} from "../FactionHelpers";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { IMap } from "../../types";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
augName: string;
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
const spanStyleMarkup = {
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}
|
||||
|
||||
const inlineStyleMarkup = {
|
||||
display: "inline-block",
|
||||
}
|
||||
|
||||
export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
aug: Augmentation | null;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.aug = Augmentations[this.props.augName];
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
getMoneyCost(): number {
|
||||
return this.aug!.baseCost * this.props.faction.getInfo().augmentationPriceMult;
|
||||
}
|
||||
|
||||
getRepCost(): number {
|
||||
return this.aug!.baseRepRequirement * this.props.faction.getInfo().augmentationRepRequirementMult;
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
purchaseAugmentationBoxCreate(this.aug!, this.props.faction);
|
||||
} else {
|
||||
purchaseAugmentation(this.aug!, this.props.faction);
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the player has the prerequisite Augmentations
|
||||
hasPrereqs(): boolean {
|
||||
return hasAugmentationPrereqs(this.aug!);
|
||||
}
|
||||
|
||||
// Whether the player has enough rep for this Augmentation
|
||||
hasReputation(): boolean {
|
||||
return this.props.faction.playerReputation >= this.getRepCost();
|
||||
}
|
||||
|
||||
// Whether the player has this augmentations (purchased OR installed)
|
||||
owned(): boolean {
|
||||
let owned = false;
|
||||
for (const queuedAug of this.props.p.queuedAugmentations) {
|
||||
if (queuedAug.name === this.props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const installedAug of this.props.p.augmentations) {
|
||||
if (installedAug.name === this.props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return owned;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.aug == null) {
|
||||
console.error(`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${this.props.augName}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const moneyCost = this.getMoneyCost();
|
||||
const repCost = this.getRepCost();
|
||||
|
||||
// Determine UI properties
|
||||
let disabled: boolean = false;
|
||||
let statusTxt: string = "";
|
||||
let color: string = "";
|
||||
if (!this.hasPrereqs()) {
|
||||
disabled = true;
|
||||
statusTxt = `LOCKED (Requires ${this.aug.prereqs.join(",")} as prerequisite(s))`;
|
||||
color = "red";
|
||||
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
||||
disabled = true;
|
||||
statusTxt = "ALREADY OWNED";
|
||||
} else if (this.hasReputation()) {
|
||||
statusTxt = `UNLOCKED - ${numeralWrapper.formatMoney(moneyCost)}`;
|
||||
} else {
|
||||
disabled = true;
|
||||
statusTxt = `LOCKED (Requires ${numeralWrapper.format(repCost, "0,0.0")} faction reputation - ${numeralWrapper.formatMoney(moneyCost)})`;
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const txtStyle: IMap<string> = {
|
||||
display: "inline-block",
|
||||
}
|
||||
if (color !== "") { txtStyle.color = color; }
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = this.aug.name;
|
||||
if (this.aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeurofluxLevel()}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<li>
|
||||
<span style={spanStyleMarkup}>
|
||||
<StdButton
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
style={inlineStyleMarkup}
|
||||
text={btnTxt}
|
||||
/>
|
||||
<p style={txtStyle}>{statusTxt}</p>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
}
|
298
src/Faction/ui/Root.tsx
Normal file
298
src/Faction/ui/Root.tsx
Normal file
@ -0,0 +1,298 @@
|
||||
/**
|
||||
* Root React Component for displaying a Faction's UI.
|
||||
* This is the component for displaying a single faction's UI, not the list of all
|
||||
* accessible factions
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { AugmentationsPage } from "./AugmentationsPage";
|
||||
import { DonateOption } from "./DonateOption";
|
||||
import { Info } from "./Info";
|
||||
import { Option } from "./Option";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { createSleevePurchasesFromCovenantPopup } from "../../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
import {
|
||||
yesNoBoxClose,
|
||||
yesNoBoxCreate,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxGetYesButton,
|
||||
} from "../../../utils/YesNoBox";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
initiallyOnAugmentationsPage?: boolean;
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
startHackingMissionFn: (faction: Faction) => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
purchasingAugs: boolean;
|
||||
}
|
||||
|
||||
// Info text for all options on the UI
|
||||
const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and " +
|
||||
"faction reputation";
|
||||
const hackingMissionInfo = "Attempt a hacking mission for your faction. " +
|
||||
"A mission is a mini game that, if won, earns you " +
|
||||
"significant reputation with this faction. (Recommended hacking level: 200+)";
|
||||
const hackingContractsInfo = "Complete hacking contracts for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your hacking skill. " +
|
||||
"You will gain hacking exp.";
|
||||
const fieldWorkInfo = "Carry out field missions for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on all of your stats. " +
|
||||
"You will gain exp for all stats.";
|
||||
const securityWorkInfo = "Serve in a security detail for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your combat stats. " +
|
||||
"You will gain exp for all combat stats.";
|
||||
const augmentationsInfo = "As your reputation with this faction rises, you will " +
|
||||
"unlock Augmentations, which you can purchase to enhance " +
|
||||
"your abilities.";
|
||||
const sleevePurchasesInfo = "Purchase Duplicate Sleeves and upgrades. These are permanent!";
|
||||
|
||||
const GangNames = [
|
||||
"Slum Snakes",
|
||||
"Tetrads",
|
||||
"The Syndicate",
|
||||
"The Dark Army",
|
||||
"Speakers for the Dead",
|
||||
"NiteSec",
|
||||
"The Black Hand"
|
||||
];
|
||||
|
||||
export class FactionRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
purchasingAugs: props.initiallyOnAugmentationsPage ? props.initiallyOnAugmentationsPage : false,
|
||||
}
|
||||
|
||||
this.manageGang = this.manageGang.bind(this);
|
||||
this.rerender = this.rerender.bind(this);
|
||||
this.routeToMain = this.routeToMain.bind(this);
|
||||
this.routeToPurchaseAugs = this.routeToPurchaseAugs.bind(this);
|
||||
this.sleevePurchases = this.sleevePurchases.bind(this);
|
||||
this.startFieldWork = this.startFieldWork.bind(this);
|
||||
this.startHackingContracts = this.startHackingContracts.bind(this);
|
||||
this.startHackingMission = this.startHackingMission.bind(this);
|
||||
this.startSecurityWork = this.startSecurityWork.bind(this);
|
||||
}
|
||||
|
||||
manageGang() {
|
||||
// If player already has a gang, just go to the gang UI
|
||||
if (this.props.p.inGang()) {
|
||||
return this.props.engine.loadGangContent();
|
||||
}
|
||||
|
||||
// Otherwise, we have to create the gang
|
||||
const facName = this.props.faction.name;
|
||||
let isHacking = false;
|
||||
if (facName === "NiteSec" || facName === "The Black Hand") {
|
||||
isHacking = true;
|
||||
}
|
||||
|
||||
// A Yes/No popup box will allow the player to confirm gang creation
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
const noBtn = yesNoBoxGetNoButton();
|
||||
if (yesBtn == null || noBtn == null) { return; }
|
||||
|
||||
yesBtn.innerHTML = "Create Gang";
|
||||
yesBtn.addEventListener("click", () => {
|
||||
this.props.p.startGang(facName, isHacking);
|
||||
const worldMenuHeader = document.getElementById("world-menu-header");
|
||||
if (worldMenuHeader instanceof HTMLElement) {
|
||||
worldMenuHeader.click(); worldMenuHeader.click();
|
||||
}
|
||||
|
||||
this.props.engine.loadGangContent();
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
noBtn.innerHTML = "Cancel";
|
||||
noBtn.addEventListener("click", () => {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
// Pop-up text
|
||||
let gangTypeText = "";
|
||||
if (isHacking) {
|
||||
gangTypeText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
"Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " +
|
||||
"is not as important.<br><br>";
|
||||
} else {
|
||||
gangTypeText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
|
||||
"is more important. However, well-managed combat gangs can progress faster than hacking ones.<br><br>";
|
||||
}
|
||||
yesNoBoxCreate(`Would you like to create a new Gang with ${facName}?<br><br>` +
|
||||
"Note that this will prevent you from creating a Gang with any other Faction until " +
|
||||
"this BitNode is destroyed. It also resets your reputation with this faction.<br><br>" +
|
||||
gangTypeText +
|
||||
"Other than hacking vs combat, there are NO differences between the Factions you can " +
|
||||
"create a Gang with, and each of these Factions have all Augmentations available.");
|
||||
}
|
||||
|
||||
rerender() {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Route to the main faction page
|
||||
routeToMain() {
|
||||
this.setState({ purchasingAugs: false });
|
||||
}
|
||||
|
||||
// Route to the purchase augmentation UI for this faction
|
||||
routeToPurchaseAugs() {
|
||||
this.setState({ purchasingAugs: true });
|
||||
}
|
||||
|
||||
sleevePurchases() {
|
||||
createSleevePurchasesFromCovenantPopup(this.props.p);
|
||||
}
|
||||
|
||||
startFieldWork() {
|
||||
this.props.p.startFactionFieldWork(this.props.faction);
|
||||
}
|
||||
|
||||
startHackingContracts() {
|
||||
this.props.p.startFactionHackWork(this.props.faction);
|
||||
}
|
||||
|
||||
startHackingMission() {
|
||||
const fac = this.props.faction;
|
||||
this.props.engine.loadMissionContent();
|
||||
this.props.startHackingMissionFn(fac);
|
||||
}
|
||||
|
||||
startSecurityWork() {
|
||||
this.props.p.startFactionSecurityWork(this.props.faction);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.purchasingAugs ? this.renderAugmentationsPage() : this.renderMainPage();
|
||||
}
|
||||
|
||||
renderMainPage() {
|
||||
const p = this.props.p;
|
||||
const faction = this.props.faction;
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
// gang faction because if the player has a gang, they cannot do any other action
|
||||
const isPlayersGang = p.inGang() && (p.getGangName() === faction.name);
|
||||
|
||||
|
||||
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
|
||||
// should be shown
|
||||
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
const canDonate = faction.favor >= favorToDonate;
|
||||
|
||||
const canPurchaseSleeves = (faction.name === "The Covenant" && p.bitNodeN >= 10 && SourceFileFlags[10]);
|
||||
|
||||
let canAccessGang = (p.canAccessGang() && GangNames.includes(faction.name));
|
||||
if (p.inGang() && (p.getGangName() !== faction.name)) {
|
||||
canAccessGang = false;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{faction.name}</h1>
|
||||
<Info
|
||||
faction={faction}
|
||||
factionInfo={factionInfo}
|
||||
/>
|
||||
{
|
||||
canAccessGang &&
|
||||
<Option
|
||||
buttonText={"Manage Gang"}
|
||||
infoText={gangInfo}
|
||||
onClick={this.manageGang}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerHackingMission) &&
|
||||
<Option
|
||||
buttonText={"Hacking Mission"}
|
||||
infoText={hackingMissionInfo}
|
||||
onClick={this.startHackingMission}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerHackingWork) &&
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={this.startHackingContracts}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerFieldWork) &&
|
||||
<Option
|
||||
buttonText={"Field Work"}
|
||||
infoText={fieldWorkInfo}
|
||||
onClick={this.startFieldWork}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerSecurityWork) &&
|
||||
<Option
|
||||
buttonText={"Security Work"}
|
||||
infoText={securityWorkInfo}
|
||||
onClick={this.startSecurityWork}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && canDonate) &&
|
||||
<DonateOption
|
||||
faction={this.props.faction}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
/>
|
||||
}
|
||||
<Option
|
||||
buttonText={"Purchase Augmentations"}
|
||||
infoText={augmentationsInfo}
|
||||
onClick={this.routeToPurchaseAugs}
|
||||
/>
|
||||
{
|
||||
canPurchaseSleeves &&
|
||||
<Option
|
||||
buttonText={"Purchase Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={this.sleevePurchases}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderAugmentationsPage() {
|
||||
return (
|
||||
<div>
|
||||
<AugmentationsPage
|
||||
faction={this.props.faction}
|
||||
p={this.props.p}
|
||||
routeToMainPage={this.routeToMain}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -3,8 +3,13 @@
|
||||
* to TypeScript at the moment
|
||||
*/
|
||||
export interface IEngine {
|
||||
hideAllContent: () => void;
|
||||
loadBladeburnerContent: () => void;
|
||||
loadFactionContent: () => void;
|
||||
loadFactionsContent: () => void;
|
||||
loadGangContent: () => void;
|
||||
loadInfiltrationContent: () => void;
|
||||
loadMissionContent: () => void;
|
||||
loadResleevingContent: () => void;
|
||||
loadStockMarketContent: () => void;
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ export function createPurchaseServerPopup(ram: number, p: IPlayer) {
|
||||
* Create a popup that lets the player start a Corporation
|
||||
*/
|
||||
export function createStartCorporationPopup(p: IPlayer) {
|
||||
if (!p.canAccessCorporation() || p.hasCorporation) { return; }
|
||||
if (!p.canAccessCorporation() || p.hasCorporation()) { return; }
|
||||
|
||||
const popupId = "create-corporation-popup";
|
||||
const txt = createElement("p", {
|
||||
|
@ -12,6 +12,7 @@ import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugment
|
||||
import { Company } from "../Company/Company";
|
||||
import { CompanyPosition } from "../Company/CompanyPosition";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { HashManager } from "../Hacknet/HashManager";
|
||||
import { HacknetNode } from "../Hacknet/HacknetNode";
|
||||
import { LocationName } from "../Locations/data/LocationNames";
|
||||
@ -114,6 +115,7 @@ export interface IPlayer {
|
||||
applyForWaiterJob(sing?: boolean): boolean | void;
|
||||
canAccessBladeburner(): boolean;
|
||||
canAccessCorporation(): boolean;
|
||||
canAccessGang(): boolean;
|
||||
canAccessResleeving(): boolean;
|
||||
canAfford(cost: number): boolean;
|
||||
gainHackingExp(exp: number): void;
|
||||
@ -124,6 +126,7 @@ export interface IPlayer {
|
||||
gainCharismaExp(exp: number): void;
|
||||
gainMoney(money: number): void;
|
||||
getCurrentServer(): Server;
|
||||
getGangName(): string;
|
||||
getHomeComputer(): Server;
|
||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
|
||||
getUpgradeHomeRamCost(): number;
|
||||
@ -151,6 +154,10 @@ export interface IPlayer {
|
||||
money: number,
|
||||
time: number,
|
||||
singParams: any): void;
|
||||
startFactionFieldWork(faction: Faction): void;
|
||||
startFactionHackWork(faction: Faction): void;
|
||||
startFactionSecurityWork(faction: Faction): void;
|
||||
startGang(facName: string, isHacking: boolean): void;
|
||||
startWork(companyName: string): void;
|
||||
startWorkPartTime(companyName: string): void;
|
||||
travel(to: CityName): boolean;
|
||||
|
@ -1,17 +1,20 @@
|
||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
||||
import * as gangMethods from "./PlayerObjectGangMethods";
|
||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
||||
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON } from "../../../utils/JSONReviver";
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON
|
||||
} from "../../../utils/JSONReviver";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
export function PlayerObject() {
|
||||
//Skills and stats
|
||||
@ -199,7 +202,15 @@ export function PlayerObject() {
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
};
|
||||
|
||||
Object.assign(PlayerObject.prototype, generalMethods, serverMethods, bladeburnerMethods, corporationMethods);
|
||||
// Apply player methods to the prototype using Object.assign()
|
||||
Object.assign(
|
||||
PlayerObject.prototype,
|
||||
generalMethods,
|
||||
serverMethods,
|
||||
bladeburnerMethods,
|
||||
corporationMethods,
|
||||
gangMethods
|
||||
);
|
||||
|
||||
PlayerObject.prototype.toJSON = function() {
|
||||
return Generic_toJSON("PlayerObject", this);
|
||||
|
34
src/PersonObjects/Player/PlayerObjectGangMethods.js
Normal file
34
src/PersonObjects/Player/PlayerObjectGangMethods.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Gang } from "../../Gang";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
// Amount of negative karma needed to manage a gang in BitNodes other than 2
|
||||
const GangKarmaRequirement = -54000;
|
||||
|
||||
export function canAccessGang() {
|
||||
if (this.bitNodeN === 2) { return true; }
|
||||
|
||||
if (SourceFileFlags[2] <= 0) { return false; }
|
||||
|
||||
return (this.karma <= GangKarmaRequirement);
|
||||
}
|
||||
|
||||
export function getGangName() {
|
||||
return this.gang.facName;
|
||||
}
|
||||
|
||||
export function inGang() {
|
||||
if (this.gang == null || this.gang == undefined) { return false; }
|
||||
|
||||
return (this.gang instanceof Gang);
|
||||
}
|
||||
|
||||
export function startGang(factionName, hacking) {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
|
||||
const fac = Factions[factionName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Invalid faction name when creating gang: ${factionName}`);
|
||||
}
|
||||
fac.playerReputation = 0;
|
||||
}
|
@ -20,7 +20,7 @@ import {Engine} from "../../engine";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
import {Gang, resetGangs} from "../../Gang";
|
||||
import { resetGangs } from "../../Gang";
|
||||
import { hasHacknetServers } from "../../Hacknet/HacknetHelpers";
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
@ -150,8 +150,9 @@ export function prestigeAugmentation() {
|
||||
this.moneySourceA.reset();
|
||||
|
||||
this.hacknetNodes.length = 0;
|
||||
this.hashManager.prestige(this);
|
||||
|
||||
//Re-calculate skills and reset HP
|
||||
// Re-calculate skills and reset HP
|
||||
this.updateSkillLevels();
|
||||
this.hp = this.max_hp;
|
||||
}
|
||||
@ -239,18 +240,19 @@ export function prestigeSourceFile() {
|
||||
this.lastUpdate = new Date().getTime();
|
||||
|
||||
this.hacknetNodes.length = 0;
|
||||
this.hashManager.prestige(this);
|
||||
|
||||
//Gang
|
||||
// Gang
|
||||
this.gang = null;
|
||||
resetGangs();
|
||||
|
||||
//Reset Stock market
|
||||
// Reset Stock market
|
||||
this.hasWseAccount = false;
|
||||
this.hasTixApiAccess = false;
|
||||
this.has4SData = false;
|
||||
this.has4SDataTixApi = false;
|
||||
|
||||
//BitNode 3: Corporatocracy
|
||||
// BitNode 3: Corporatocracy
|
||||
this.corporation = 0;
|
||||
|
||||
// Statistics trackers
|
||||
@ -2174,18 +2176,6 @@ export function checkForFactionInvitations() {
|
||||
return invitedFactions;
|
||||
}
|
||||
|
||||
|
||||
/*************** Gang ****************/
|
||||
//Returns true if Player is in a gang and false otherwise
|
||||
export function inGang() {
|
||||
if (this.gang == null || this.gang == undefined) {return false;}
|
||||
return (this.gang instanceof Gang);
|
||||
}
|
||||
|
||||
export function startGang(factionName, hacking) {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
}
|
||||
|
||||
/************* BitNodes **************/
|
||||
export function setBitNodeNumber(n) {
|
||||
this.bitNodeN = n;
|
||||
|
@ -138,9 +138,9 @@ function prestigeAugmentation() {
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
// Gang, in BitNode 2
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
var faction = Factions[Player.gang.facName];
|
||||
// Gang
|
||||
if (Player.inGang()) {
|
||||
const faction = Factions[Player.gang.facName];
|
||||
if (faction instanceof Faction) {
|
||||
joinFaction(faction);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ BitburnerSaveObject.prototype.getSaveString = function() {
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.FconfSettingsSave = JSON.stringify(FconfSettings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||
}
|
||||
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
||||
@ -270,7 +270,7 @@ function loadGame(saveString) {
|
||||
} else {
|
||||
createNewUpdateText();
|
||||
}
|
||||
if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(saveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
@ -360,7 +360,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (tempPlayer.bitNodeN == 2 && tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
||||
if (tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(tempSaveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
@ -449,7 +449,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
} else {
|
||||
createNewUpdateText();
|
||||
}
|
||||
if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(saveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
@ -546,7 +546,7 @@ BitburnerSaveObject.prototype.exportGame = function() {
|
||||
this.StockMarketSave = JSON.stringify(StockMarket);
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,9 @@ function initSourceFiles() {
|
||||
"Level 1: 16%<br>" +
|
||||
"Level 2: 24%<br>" +
|
||||
"Level 3: 28%");
|
||||
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " +
|
||||
"multipliers by:<br><br>" +
|
||||
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File allows you to form gangs in other BitNodes " +
|
||||
"once your karma decreases to a certain value. It also increases the player's " +
|
||||
"crime success rate, crime money, and charisma multipliers by:<br><br>" +
|
||||
"Level 1: 24%<br>" +
|
||||
"Level 2: 36%<br>" +
|
||||
"Level 3: 42%");
|
||||
|
@ -262,7 +262,6 @@ const Engine = {
|
||||
createProgramContent: null,
|
||||
factionsContent: null,
|
||||
factionContent: null,
|
||||
factionAugmentationsContent: null,
|
||||
augmentationsContent: null,
|
||||
tutorialContent: null,
|
||||
infiltrationContent: null,
|
||||
@ -530,8 +529,8 @@ const Engine = {
|
||||
clearHacknetNodesUI();
|
||||
Engine.Display.createProgramContent.style.display = "none";
|
||||
Engine.Display.factionsContent.style.display = "none";
|
||||
ReactDOM.unmountComponentAtNode(Engine.Display.factionContent);
|
||||
Engine.Display.factionContent.style.display = "none";
|
||||
Engine.Display.factionAugmentationsContent.style.display = "none";
|
||||
Engine.Display.augmentationsContent.style.display = "none";
|
||||
Engine.Display.tutorialContent.style.display = "none";
|
||||
Engine.Display.locationContent.style.display = "none";
|
||||
@ -749,7 +748,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Gang, if applicable
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
Player.gang.process(numCycles, Player);
|
||||
}
|
||||
|
||||
@ -1133,7 +1132,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Gang progress for BitNode 2
|
||||
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
Player.gang.process(numCyclesOffline, Player);
|
||||
}
|
||||
|
||||
@ -1281,13 +1280,9 @@ const Engine = {
|
||||
Engine.Display.factionsContent = document.getElementById("factions-container");
|
||||
Engine.Display.factionsContent.style.display = "none";
|
||||
|
||||
|
||||
Engine.Display.factionContent = document.getElementById("faction-container");
|
||||
Engine.Display.factionContent.style.display = "none";
|
||||
|
||||
Engine.Display.factionAugmentationsContent = document.getElementById("faction-augmentations-container");
|
||||
Engine.Display.factionAugmentationsContent.style.display = "none";
|
||||
|
||||
Engine.Display.augmentationsContent = document.getElementById("augmentations-container");
|
||||
Engine.Display.augmentationsContent.style.display = "none";
|
||||
|
||||
|
@ -117,7 +117,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
|
||||
<div id="script-editor-filename-wrapper">
|
||||
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
|
||||
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
|
||||
<input id="script-editor-filename" type="text" maxlength="100" tabindex="1" />
|
||||
</div>
|
||||
|
||||
<div id="ace-editor"></div>
|
||||
@ -223,8 +223,6 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
||||
<div id="faction-container" class="generic-menupage-container"></div>
|
||||
|
||||
<div id="faction-augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
<!-- Augmentations -->
|
||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
|
74
src/ui/React/AutoupdatingParagraph.tsx
Normal file
74
src/ui/React/AutoupdatingParagraph.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Basic paragraph (p Element) that automatically re-renders itself every X seconds
|
||||
*
|
||||
* NOT recommended for usage - only if you really have to
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
interface IProps {
|
||||
intervalTime?: number;
|
||||
style?: object;
|
||||
text: string;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
i: number;
|
||||
}
|
||||
|
||||
type IInnerHTMLMarkup = {
|
||||
__html: string;
|
||||
}
|
||||
|
||||
export class AutoupdatingParagraph extends React.Component<IProps, IState> {
|
||||
/**
|
||||
* Timer ID for auto-updating implementation (returned value from setInterval())
|
||||
*/
|
||||
interval: number = 0;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
i: 0,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const time = this.props.intervalTime ? this.props.intervalTime : 1000;
|
||||
this.interval = setInterval(() => this.tick(), time);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.setState(prevState => ({
|
||||
i: prevState.i + 1
|
||||
}));
|
||||
}
|
||||
|
||||
render() {
|
||||
const hasTooltip = this.props.tooltip != null && this.props.tooltip !== "";
|
||||
|
||||
const className = "tooltip";
|
||||
|
||||
// Tooltip will be set using inner HTML
|
||||
let tooltipMarkup: IInnerHTMLMarkup | null;
|
||||
if (hasTooltip) {
|
||||
tooltipMarkup = {
|
||||
__html: this.props.tooltip!
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<p className={className} style={this.props.style}>
|
||||
{this.props.text}
|
||||
{
|
||||
hasTooltip &&
|
||||
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
|
||||
}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ export interface IParagraphWithTooltipProps {
|
||||
export class ParagraphWithTooltip extends React.Component<IParagraphWithTooltipProps, any> {
|
||||
render() {
|
||||
return (
|
||||
<p className={"tooltip"}>
|
||||
<p className={"tooltip"} style={this.props.style}>
|
||||
{this.props.text}
|
||||
<span className={"tooltiptext"}>
|
||||
{this.props.tooltip}
|
||||
|
Loading…
Reference in New Issue
Block a user