mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 13:43:49 +01:00
v0.46.2
This commit is contained in:
parent
98a04e4932
commit
7417fb6ef8
@ -75,7 +75,7 @@
|
|||||||
margin: 4px;
|
margin: 4px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
resize: none;
|
resize: none;
|
||||||
width: 50%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#script-editor-status {
|
#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;
|
margin: 4px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
resize: none;
|
resize: none;
|
||||||
width: 50%; }
|
width: 60%; }
|
||||||
|
|
||||||
#script-editor-status {
|
#script-editor-status {
|
||||||
float: left;
|
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
|
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
|
v0.46.1 - 4/12/2019
|
||||||
-------------------
|
-------------------
|
||||||
* Added a very rudimentary directory system to the Terminal
|
* Added a very rudimentary directory system to the Terminal
|
||||||
|
@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
|||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.46'
|
version = '0.46'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# 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
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -8,6 +8,7 @@ recruitMember() Netscript Function
|
|||||||
Attempt to recruit a new gang member.
|
Attempt to recruit a new gang member.
|
||||||
|
|
||||||
Possible reasons for failure:
|
Possible reasons for failure:
|
||||||
|
|
||||||
* Cannot currently recruit a new member
|
* Cannot currently recruit a new member
|
||||||
* There already exists a member with the specified name
|
* There already exists a member with the specified name
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ hashCost() Netscript Function
|
|||||||
|
|
||||||
.. warning:: This page contains spoilers for the game
|
.. 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
|
: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">
|
<div id="script-editor-filename-wrapper">
|
||||||
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
|
<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>
|
||||||
|
|
||||||
<div id="ace-editor"></div>
|
<div id="ace-editor"></div>
|
||||||
@ -221,8 +221,6 @@
|
|||||||
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
||||||
<div id="faction-container" class="generic-menupage-container"></div>
|
<div id="faction-container" class="generic-menupage-container"></div>
|
||||||
|
|
||||||
<div id="faction-augmentations-container" class="generic-menupage-container"></div>
|
|
||||||
|
|
||||||
<!-- Augmentations -->
|
<!-- Augmentations -->
|
||||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||||
|
|
||||||
|
@ -114,5 +114,5 @@
|
|||||||
"watch": "webpack --watch --mode production",
|
"watch": "webpack --watch --mode production",
|
||||||
"watch:dev": "webpack --watch --mode development"
|
"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 {
|
interface IConstructorParams {
|
||||||
info: string;
|
info: string;
|
||||||
|
isSpecial?: boolean;
|
||||||
moneyCost: number;
|
moneyCost: number;
|
||||||
name: string;
|
name: string;
|
||||||
prereqs?: string[];
|
prereqs?: string[];
|
||||||
@ -62,6 +63,9 @@ export class Augmentation {
|
|||||||
// Description of what this Aug is and what it does
|
// Description of what this Aug is and what it does
|
||||||
info: string = "";
|
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
|
// Augmentation level - for repeatable Augs like NeuroFlux Governor
|
||||||
level: number = 0;
|
level: number = 0;
|
||||||
|
|
||||||
@ -90,6 +94,10 @@ export class Augmentation {
|
|||||||
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||||
this.startingCost = this.baseCost;
|
this.startingCost = this.baseCost;
|
||||||
|
|
||||||
|
if (params.isSpecial) {
|
||||||
|
this.isSpecial = true;
|
||||||
|
}
|
||||||
|
|
||||||
this.level = 0;
|
this.level = 0;
|
||||||
|
|
||||||
// Set multipliers
|
// Set multipliers
|
||||||
|
@ -1677,19 +1677,6 @@ function initAugmentations() {
|
|||||||
}
|
}
|
||||||
AddToAugmentations(SNA);
|
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
|
//Special Bladeburner Augmentations
|
||||||
var BladeburnersFactionName = "Bladeburners";
|
var BladeburnersFactionName = "Bladeburners";
|
||||||
if (factionExists(BladeburnersFactionName)) {
|
if (factionExists(BladeburnersFactionName)) {
|
||||||
@ -1708,6 +1695,7 @@ function initAugmentations() {
|
|||||||
"Increases the player's dexterity by 5%.",
|
"Increases the player's dexterity by 5%.",
|
||||||
bladeburner_success_chance_mult: 1.03,
|
bladeburner_success_chance_mult: 1.03,
|
||||||
dexterity_mult: 1.05,
|
dexterity_mult: 1.05,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
EsperEyewear.addToFactions([BladeburnersFactionName]);
|
EsperEyewear.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(EsperEyewear);
|
resetAugmentation(EsperEyewear);
|
||||||
@ -1725,6 +1713,7 @@ function initAugmentations() {
|
|||||||
bladeburner_success_chance_mult: 1.03,
|
bladeburner_success_chance_mult: 1.03,
|
||||||
bladeburner_analysis_mult: 1.05,
|
bladeburner_analysis_mult: 1.05,
|
||||||
bladeburner_stamina_gain_mult: 1.02,
|
bladeburner_stamina_gain_mult: 1.02,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
EMS4Recombination.addToFactions([BladeburnersFactionName]);
|
EMS4Recombination.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(EMS4Recombination);
|
resetAugmentation(EMS4Recombination);
|
||||||
@ -1743,6 +1732,7 @@ function initAugmentations() {
|
|||||||
strength_mult: 1.05,
|
strength_mult: 1.05,
|
||||||
dexterity_mult: 1.05,
|
dexterity_mult: 1.05,
|
||||||
bladeburner_success_chance_mult: 1.04,
|
bladeburner_success_chance_mult: 1.04,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
OrionShoulder.addToFactions([BladeburnersFactionName]);
|
OrionShoulder.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(OrionShoulder);
|
resetAugmentation(OrionShoulder);
|
||||||
@ -1758,6 +1748,7 @@ function initAugmentations() {
|
|||||||
"This augmentation:<br>" +
|
"This augmentation:<br>" +
|
||||||
"Increases the player's success chance in Bladeburner contracts/operations by 6%.",
|
"Increases the player's success chance in Bladeburner contracts/operations by 6%.",
|
||||||
bladeburner_success_chance_mult: 1.06,
|
bladeburner_success_chance_mult: 1.06,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
HyperionV1.addToFactions([BladeburnersFactionName]);
|
HyperionV1.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(HyperionV1);
|
resetAugmentation(HyperionV1);
|
||||||
@ -1772,6 +1763,7 @@ function initAugmentations() {
|
|||||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||||
prereqs:[AugmentationNames.HyperionV1],
|
prereqs:[AugmentationNames.HyperionV1],
|
||||||
bladeburner_success_chance_mult: 1.08,
|
bladeburner_success_chance_mult: 1.08,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
HyperionV2.addToFactions([BladeburnersFactionName]);
|
HyperionV2.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(HyperionV2);
|
resetAugmentation(HyperionV2);
|
||||||
@ -1790,6 +1782,7 @@ function initAugmentations() {
|
|||||||
dexterity_mult: 1.07,
|
dexterity_mult: 1.07,
|
||||||
agility_mult: 1.07,
|
agility_mult: 1.07,
|
||||||
bladeburner_stamina_gain_mult: 1.05,
|
bladeburner_stamina_gain_mult: 1.05,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
GolemSerum.addToFactions([BladeburnersFactionName]);
|
GolemSerum.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(GolemSerum);
|
resetAugmentation(GolemSerum);
|
||||||
@ -1805,6 +1798,7 @@ function initAugmentations() {
|
|||||||
dexterity_exp_mult: 1.1,
|
dexterity_exp_mult: 1.1,
|
||||||
bladeburner_analysis_mult: 1.1,
|
bladeburner_analysis_mult: 1.1,
|
||||||
bladeburner_success_chance_mult: 1.04,
|
bladeburner_success_chance_mult: 1.04,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
VangelisVirus.addToFactions([BladeburnersFactionName]);
|
VangelisVirus.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(VangelisVirus);
|
resetAugmentation(VangelisVirus);
|
||||||
@ -1824,6 +1818,7 @@ function initAugmentations() {
|
|||||||
dexterity_exp_mult: 1.1,
|
dexterity_exp_mult: 1.1,
|
||||||
bladeburner_analysis_mult: 1.15,
|
bladeburner_analysis_mult: 1.15,
|
||||||
bladeburner_success_chance_mult: 1.05,
|
bladeburner_success_chance_mult: 1.05,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
VangelisVirus3.addToFactions([BladeburnersFactionName]);
|
VangelisVirus3.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(VangelisVirus3);
|
resetAugmentation(VangelisVirus3);
|
||||||
@ -1842,6 +1837,7 @@ function initAugmentations() {
|
|||||||
dexterity_exp_mult: 1.05,
|
dexterity_exp_mult: 1.05,
|
||||||
agility_exp_mult: 1.05,
|
agility_exp_mult: 1.05,
|
||||||
bladeburner_max_stamina_mult: 1.1,
|
bladeburner_max_stamina_mult: 1.1,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
INTERLINKED.addToFactions([BladeburnersFactionName]);
|
INTERLINKED.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(INTERLINKED);
|
resetAugmentation(INTERLINKED);
|
||||||
@ -1859,6 +1855,7 @@ function initAugmentations() {
|
|||||||
agility_mult: 1.05,
|
agility_mult: 1.05,
|
||||||
bladeburner_max_stamina_mult: 1.05,
|
bladeburner_max_stamina_mult: 1.05,
|
||||||
bladeburner_stamina_gain_mult: 1.05,
|
bladeburner_stamina_gain_mult: 1.05,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeRunner.addToFactions([BladeburnersFactionName]);
|
BladeRunner.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeRunner);
|
resetAugmentation(BladeRunner);
|
||||||
@ -1879,6 +1876,7 @@ function initAugmentations() {
|
|||||||
agility_mult: 1.04,
|
agility_mult: 1.04,
|
||||||
bladeburner_stamina_gain_mult: 1.02,
|
bladeburner_stamina_gain_mult: 1.02,
|
||||||
bladeburner_success_chance_mult: 1.03,
|
bladeburner_success_chance_mult: 1.03,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeArmor.addToFactions([BladeburnersFactionName]);
|
BladeArmor.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeArmor);
|
resetAugmentation(BladeArmor);
|
||||||
@ -1895,6 +1893,7 @@ function initAugmentations() {
|
|||||||
bladeburner_success_chance_mult: 1.05,
|
bladeburner_success_chance_mult: 1.05,
|
||||||
bladeburner_stamina_gain_mult: 1.02,
|
bladeburner_stamina_gain_mult: 1.02,
|
||||||
bladeburner_max_stamina_mult: 1.05,
|
bladeburner_max_stamina_mult: 1.05,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeArmorPowerCells.addToFactions([BladeburnersFactionName]);
|
BladeArmorPowerCells.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeArmorPowerCells);
|
resetAugmentation(BladeArmorPowerCells);
|
||||||
@ -1909,6 +1908,7 @@ function initAugmentations() {
|
|||||||
prereqs:[AugmentationNames.BladeArmor],
|
prereqs:[AugmentationNames.BladeArmor],
|
||||||
defense_mult: 1.05,
|
defense_mult: 1.05,
|
||||||
bladeburner_success_chance_mult: 1.06,
|
bladeburner_success_chance_mult: 1.06,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeArmorEnergyShielding.addToFactions([BladeburnersFactionName]);
|
BladeArmorEnergyShielding.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeArmorEnergyShielding);
|
resetAugmentation(BladeArmorEnergyShielding);
|
||||||
@ -1922,6 +1922,7 @@ function initAugmentations() {
|
|||||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||||
prereqs:[AugmentationNames.BladeArmor],
|
prereqs:[AugmentationNames.BladeArmor],
|
||||||
bladeburner_success_chance_mult: 1.08,
|
bladeburner_success_chance_mult: 1.08,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeArmorUnibeam.addToFactions([BladeburnersFactionName]);
|
BladeArmorUnibeam.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeArmorUnibeam);
|
resetAugmentation(BladeArmorUnibeam);
|
||||||
@ -1936,6 +1937,7 @@ function initAugmentations() {
|
|||||||
"Increases the player's success chance in Bladeburner contracts/operations by 10%.",
|
"Increases the player's success chance in Bladeburner contracts/operations by 10%.",
|
||||||
prereqs:[AugmentationNames.BladeArmorUnibeam],
|
prereqs:[AugmentationNames.BladeArmorUnibeam],
|
||||||
bladeburner_success_chance_mult: 1.1,
|
bladeburner_success_chance_mult: 1.1,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeArmorOmnibeam.addToFactions([BladeburnersFactionName]);
|
BladeArmorOmnibeam.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeArmorOmnibeam);
|
resetAugmentation(BladeArmorOmnibeam);
|
||||||
@ -1951,6 +1953,7 @@ function initAugmentations() {
|
|||||||
prereqs:[AugmentationNames.BladeArmor],
|
prereqs:[AugmentationNames.BladeArmor],
|
||||||
bladeburner_analysis_mult: 1.15,
|
bladeburner_analysis_mult: 1.15,
|
||||||
bladeburner_success_chance_mult: 1.02,
|
bladeburner_success_chance_mult: 1.02,
|
||||||
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
BladeArmorIPU.addToFactions([BladeburnersFactionName]);
|
BladeArmorIPU.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladeArmorIPU);
|
resetAugmentation(BladeArmorIPU);
|
||||||
@ -1963,7 +1966,8 @@ function initAugmentations() {
|
|||||||
"extremely large radius. These specially-modified holograms were specially " +
|
"extremely large radius. These specially-modified holograms were specially " +
|
||||||
"weaponized by Bladeburner units to be used against Synthoids.<br><br>" +
|
"weaponized by Bladeburner units to be used against Synthoids.<br><br>" +
|
||||||
"This augmentation allows you to perform Bladeburner actions and other " +
|
"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]);
|
BladesSimulacrum.addToFactions([BladeburnersFactionName]);
|
||||||
resetAugmentation(BladesSimulacrum);
|
resetAugmentation(BladesSimulacrum);
|
||||||
|
@ -57,8 +57,9 @@ export function initBitNodes() {
|
|||||||
"For every Faction NOT listed above, reputation gains are halved<br>" +
|
"For every Faction NOT listed above, reputation gains are halved<br>" +
|
||||||
"You will no longer gain passive reputation with Factions<br><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 " +
|
"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, " +
|
"upgrade its level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes " +
|
||||||
"crime money, and charisma multipliers by:<br><br>" +
|
"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 1: 24%<br>" +
|
||||||
"Level 2: 36%<br>" +
|
"Level 2: 36%<br>" +
|
||||||
"Level 3: 42%");
|
"Level 3: 42%");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import { IMap } from "./types";
|
import { IMap } from "./types";
|
||||||
|
|
||||||
export let CONSTANTS: IMap<any> = {
|
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
|
/** 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
|
* 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:
|
LatestUpdate:
|
||||||
`
|
`
|
||||||
v0.46.2
|
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:
|
* Gang changes:
|
||||||
** Bug Fix: Gangs can no longer clash with themselve
|
** Bug Fix: Gangs can no longer clash with themselve
|
||||||
** Bug Fix: Winning against another gang should properly reduce their power
|
** Bug Fix: Winning against another gang should properly reduce their power
|
||||||
|
|
||||||
* Bug Fix: Terminal 'wget' command now works properly
|
* 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 tonsPP = 1e27;
|
||||||
const tonsP = 1e12;
|
const tonsP = 1e12;
|
||||||
|
|
||||||
|
|
||||||
class ValueAdjusterComponent extends Component {
|
class ValueAdjusterComponent extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -48,7 +47,7 @@ class ValueAdjusterComponent extends Component {
|
|||||||
this.setValue = this.setValue.bind(this);
|
this.setValue = this.setValue.bind(this);
|
||||||
}
|
}
|
||||||
setValue(event) {
|
setValue(event) {
|
||||||
this.setState({ value: event.target.value });
|
this.setState({ value: parseFloat(event.target.value) });
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const { title, add, subtract, reset } = this.props;
|
const { title, add, subtract, reset } = this.props;
|
||||||
@ -131,7 +130,6 @@ class DevMenuComponent extends Component {
|
|||||||
this.setState({ codingcontract: event.target.value });
|
this.setState({ codingcontract: event.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
addMoney(n) {
|
addMoney(n) {
|
||||||
return function() {
|
return function() {
|
||||||
Player.gainMoney(n);
|
Player.gainMoney(n);
|
||||||
@ -193,6 +191,12 @@ class DevMenuComponent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modifyKarma(modifier) {
|
||||||
|
return function(amt) {
|
||||||
|
Player.karma += (amt * modifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tonsOfExp() {
|
tonsOfExp() {
|
||||||
Player.gainHackingExp(tonsPP);
|
Player.gainHackingExp(tonsPP);
|
||||||
Player.gainStrengthExp(tonsPP);
|
Player.gainStrengthExp(tonsPP);
|
||||||
@ -244,6 +248,12 @@ class DevMenuComponent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetKarma() {
|
||||||
|
return function() {
|
||||||
|
Player.karma = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enableIntelligence() {
|
enableIntelligence() {
|
||||||
if(Player.intelligence === 0) {
|
if(Player.intelligence === 0) {
|
||||||
Player.intelligence = 1;
|
Player.intelligence = 1;
|
||||||
@ -812,6 +822,19 @@ class DevMenuComponent extends Component {
|
|||||||
<button className="std-button" onClick={this.disableIntelligence}>Disable</button>
|
<button className="std-button" onClick={this.disableIntelligence}>Disable</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,16 +97,6 @@ export class Faction {
|
|||||||
return [favorGain, rep];
|
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.
|
* 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
|
* to TypeScript at the moment
|
||||||
*/
|
*/
|
||||||
export interface IEngine {
|
export interface IEngine {
|
||||||
|
hideAllContent: () => void;
|
||||||
loadBladeburnerContent: () => void;
|
loadBladeburnerContent: () => void;
|
||||||
|
loadFactionContent: () => void;
|
||||||
|
loadFactionsContent: () => void;
|
||||||
|
loadGangContent: () => void;
|
||||||
loadInfiltrationContent: () => void;
|
loadInfiltrationContent: () => void;
|
||||||
|
loadMissionContent: () => void;
|
||||||
loadResleevingContent: () => void;
|
loadResleevingContent: () => void;
|
||||||
loadStockMarketContent: () => void;
|
loadStockMarketContent: () => void;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ export function createPurchaseServerPopup(ram: number, p: IPlayer) {
|
|||||||
* Create a popup that lets the player start a Corporation
|
* Create a popup that lets the player start a Corporation
|
||||||
*/
|
*/
|
||||||
export function createStartCorporationPopup(p: IPlayer) {
|
export function createStartCorporationPopup(p: IPlayer) {
|
||||||
if (!p.canAccessCorporation() || p.hasCorporation) { return; }
|
if (!p.canAccessCorporation() || p.hasCorporation()) { return; }
|
||||||
|
|
||||||
const popupId = "create-corporation-popup";
|
const popupId = "create-corporation-popup";
|
||||||
const txt = createElement("p", {
|
const txt = createElement("p", {
|
||||||
|
@ -12,6 +12,7 @@ import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugment
|
|||||||
import { Company } from "../Company/Company";
|
import { Company } from "../Company/Company";
|
||||||
import { CompanyPosition } from "../Company/CompanyPosition";
|
import { CompanyPosition } from "../Company/CompanyPosition";
|
||||||
import { CityName } from "../Locations/data/CityNames";
|
import { CityName } from "../Locations/data/CityNames";
|
||||||
|
import { Faction } from "../Faction/Faction";
|
||||||
import { HashManager } from "../Hacknet/HashManager";
|
import { HashManager } from "../Hacknet/HashManager";
|
||||||
import { HacknetNode } from "../Hacknet/HacknetNode";
|
import { HacknetNode } from "../Hacknet/HacknetNode";
|
||||||
import { LocationName } from "../Locations/data/LocationNames";
|
import { LocationName } from "../Locations/data/LocationNames";
|
||||||
@ -114,6 +115,7 @@ export interface IPlayer {
|
|||||||
applyForWaiterJob(sing?: boolean): boolean | void;
|
applyForWaiterJob(sing?: boolean): boolean | void;
|
||||||
canAccessBladeburner(): boolean;
|
canAccessBladeburner(): boolean;
|
||||||
canAccessCorporation(): boolean;
|
canAccessCorporation(): boolean;
|
||||||
|
canAccessGang(): boolean;
|
||||||
canAccessResleeving(): boolean;
|
canAccessResleeving(): boolean;
|
||||||
canAfford(cost: number): boolean;
|
canAfford(cost: number): boolean;
|
||||||
gainHackingExp(exp: number): void;
|
gainHackingExp(exp: number): void;
|
||||||
@ -124,6 +126,7 @@ export interface IPlayer {
|
|||||||
gainCharismaExp(exp: number): void;
|
gainCharismaExp(exp: number): void;
|
||||||
gainMoney(money: number): void;
|
gainMoney(money: number): void;
|
||||||
getCurrentServer(): Server;
|
getCurrentServer(): Server;
|
||||||
|
getGangName(): string;
|
||||||
getHomeComputer(): Server;
|
getHomeComputer(): Server;
|
||||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
|
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
|
||||||
getUpgradeHomeRamCost(): number;
|
getUpgradeHomeRamCost(): number;
|
||||||
@ -151,6 +154,10 @@ export interface IPlayer {
|
|||||||
money: number,
|
money: number,
|
||||||
time: number,
|
time: number,
|
||||||
singParams: any): void;
|
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;
|
startWork(companyName: string): void;
|
||||||
startWorkPartTime(companyName: string): void;
|
startWorkPartTime(companyName: string): void;
|
||||||
travel(to: CityName): boolean;
|
travel(to: CityName): boolean;
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
|
||||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
|
||||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
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 { HashManager } from "../../Hacknet/HashManager";
|
||||||
import { CityName } from "../../Locations/data/CityNames";
|
import { CityName } from "../../Locations/data/CityNames";
|
||||||
|
|
||||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||||
import { Reviver,
|
import {
|
||||||
|
Reviver,
|
||||||
Generic_toJSON,
|
Generic_toJSON,
|
||||||
Generic_fromJSON } from "../../../utils/JSONReviver";
|
Generic_fromJSON
|
||||||
|
} from "../../../utils/JSONReviver";
|
||||||
|
|
||||||
import Decimal from "decimal.js";
|
import Decimal from "decimal.js";
|
||||||
|
|
||||||
@ -199,7 +202,15 @@ export function PlayerObject() {
|
|||||||
this.scriptProdSinceLastAug = 0;
|
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() {
|
PlayerObject.prototype.toJSON = function() {
|
||||||
return Generic_toJSON("PlayerObject", this);
|
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 { Faction } from "../../Faction/Faction";
|
||||||
import { Factions } from "../../Faction/Factions";
|
import { Factions } from "../../Faction/Factions";
|
||||||
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
||||||
import {Gang, resetGangs} from "../../Gang";
|
import { resetGangs } from "../../Gang";
|
||||||
import { hasHacknetServers } from "../../Hacknet/HacknetHelpers";
|
import { hasHacknetServers } from "../../Hacknet/HacknetHelpers";
|
||||||
import { HashManager } from "../../Hacknet/HashManager";
|
import { HashManager } from "../../Hacknet/HashManager";
|
||||||
import { Cities } from "../../Locations/Cities";
|
import { Cities } from "../../Locations/Cities";
|
||||||
@ -150,8 +150,9 @@ export function prestigeAugmentation() {
|
|||||||
this.moneySourceA.reset();
|
this.moneySourceA.reset();
|
||||||
|
|
||||||
this.hacknetNodes.length = 0;
|
this.hacknetNodes.length = 0;
|
||||||
|
this.hashManager.prestige(this);
|
||||||
|
|
||||||
//Re-calculate skills and reset HP
|
// Re-calculate skills and reset HP
|
||||||
this.updateSkillLevels();
|
this.updateSkillLevels();
|
||||||
this.hp = this.max_hp;
|
this.hp = this.max_hp;
|
||||||
}
|
}
|
||||||
@ -239,18 +240,19 @@ export function prestigeSourceFile() {
|
|||||||
this.lastUpdate = new Date().getTime();
|
this.lastUpdate = new Date().getTime();
|
||||||
|
|
||||||
this.hacknetNodes.length = 0;
|
this.hacknetNodes.length = 0;
|
||||||
|
this.hashManager.prestige(this);
|
||||||
|
|
||||||
//Gang
|
// Gang
|
||||||
this.gang = null;
|
this.gang = null;
|
||||||
resetGangs();
|
resetGangs();
|
||||||
|
|
||||||
//Reset Stock market
|
// Reset Stock market
|
||||||
this.hasWseAccount = false;
|
this.hasWseAccount = false;
|
||||||
this.hasTixApiAccess = false;
|
this.hasTixApiAccess = false;
|
||||||
this.has4SData = false;
|
this.has4SData = false;
|
||||||
this.has4SDataTixApi = false;
|
this.has4SDataTixApi = false;
|
||||||
|
|
||||||
//BitNode 3: Corporatocracy
|
// BitNode 3: Corporatocracy
|
||||||
this.corporation = 0;
|
this.corporation = 0;
|
||||||
|
|
||||||
// Statistics trackers
|
// Statistics trackers
|
||||||
@ -2174,18 +2176,6 @@ export function checkForFactionInvitations() {
|
|||||||
return invitedFactions;
|
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 **************/
|
/************* BitNodes **************/
|
||||||
export function setBitNodeNumber(n) {
|
export function setBitNodeNumber(n) {
|
||||||
this.bitNodeN = n;
|
this.bitNodeN = n;
|
||||||
|
@ -138,9 +138,9 @@ function prestigeAugmentation() {
|
|||||||
// Messages
|
// Messages
|
||||||
initMessages();
|
initMessages();
|
||||||
|
|
||||||
// Gang, in BitNode 2
|
// Gang
|
||||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
if (Player.inGang()) {
|
||||||
var faction = Factions[Player.gang.facName];
|
const faction = Factions[Player.gang.facName];
|
||||||
if (faction instanceof Faction) {
|
if (faction instanceof Faction) {
|
||||||
joinFaction(faction);
|
joinFaction(faction);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ BitburnerSaveObject.prototype.getSaveString = function() {
|
|||||||
this.SettingsSave = JSON.stringify(Settings);
|
this.SettingsSave = JSON.stringify(Settings);
|
||||||
this.FconfSettingsSave = JSON.stringify(FconfSettings);
|
this.FconfSettingsSave = JSON.stringify(FconfSettings);
|
||||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
if (Player.inGang()) {
|
||||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||||
}
|
}
|
||||||
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
||||||
@ -270,7 +270,7 @@ function loadGame(saveString) {
|
|||||||
} else {
|
} else {
|
||||||
createNewUpdateText();
|
createNewUpdateText();
|
||||||
}
|
}
|
||||||
if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||||
try {
|
try {
|
||||||
loadAllGangs(saveObj.AllGangsSave);
|
loadAllGangs(saveObj.AllGangsSave);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@ -360,7 +360,7 @@ function loadImportedGame(saveObj, saveString) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
if (tempPlayer.bitNodeN == 2 && tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
if (tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
||||||
try {
|
try {
|
||||||
loadAllGangs(tempSaveObj.AllGangsSave);
|
loadAllGangs(tempSaveObj.AllGangsSave);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@ -449,7 +449,7 @@ function loadImportedGame(saveObj, saveString) {
|
|||||||
} else {
|
} else {
|
||||||
createNewUpdateText();
|
createNewUpdateText();
|
||||||
}
|
}
|
||||||
if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||||
try {
|
try {
|
||||||
loadAllGangs(saveObj.AllGangsSave);
|
loadAllGangs(saveObj.AllGangsSave);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@ -546,7 +546,7 @@ BitburnerSaveObject.prototype.exportGame = function() {
|
|||||||
this.StockMarketSave = JSON.stringify(StockMarket);
|
this.StockMarketSave = JSON.stringify(StockMarket);
|
||||||
this.SettingsSave = JSON.stringify(Settings);
|
this.SettingsSave = JSON.stringify(Settings);
|
||||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
if (Player.inGang()) {
|
||||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,9 @@ function initSourceFiles() {
|
|||||||
"Level 1: 16%<br>" +
|
"Level 1: 16%<br>" +
|
||||||
"Level 2: 24%<br>" +
|
"Level 2: 24%<br>" +
|
||||||
"Level 3: 28%");
|
"Level 3: 28%");
|
||||||
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " +
|
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File allows you to form gangs in other BitNodes " +
|
||||||
"multipliers by:<br><br>" +
|
"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 1: 24%<br>" +
|
||||||
"Level 2: 36%<br>" +
|
"Level 2: 36%<br>" +
|
||||||
"Level 3: 42%");
|
"Level 3: 42%");
|
||||||
|
@ -262,7 +262,6 @@ const Engine = {
|
|||||||
createProgramContent: null,
|
createProgramContent: null,
|
||||||
factionsContent: null,
|
factionsContent: null,
|
||||||
factionContent: null,
|
factionContent: null,
|
||||||
factionAugmentationsContent: null,
|
|
||||||
augmentationsContent: null,
|
augmentationsContent: null,
|
||||||
tutorialContent: null,
|
tutorialContent: null,
|
||||||
infiltrationContent: null,
|
infiltrationContent: null,
|
||||||
@ -530,8 +529,8 @@ const Engine = {
|
|||||||
clearHacknetNodesUI();
|
clearHacknetNodesUI();
|
||||||
Engine.Display.createProgramContent.style.display = "none";
|
Engine.Display.createProgramContent.style.display = "none";
|
||||||
Engine.Display.factionsContent.style.display = "none";
|
Engine.Display.factionsContent.style.display = "none";
|
||||||
|
ReactDOM.unmountComponentAtNode(Engine.Display.factionContent);
|
||||||
Engine.Display.factionContent.style.display = "none";
|
Engine.Display.factionContent.style.display = "none";
|
||||||
Engine.Display.factionAugmentationsContent.style.display = "none";
|
|
||||||
Engine.Display.augmentationsContent.style.display = "none";
|
Engine.Display.augmentationsContent.style.display = "none";
|
||||||
Engine.Display.tutorialContent.style.display = "none";
|
Engine.Display.tutorialContent.style.display = "none";
|
||||||
Engine.Display.locationContent.style.display = "none";
|
Engine.Display.locationContent.style.display = "none";
|
||||||
@ -749,7 +748,7 @@ const Engine = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gang, if applicable
|
// Gang, if applicable
|
||||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
if (Player.inGang()) {
|
||||||
Player.gang.process(numCycles, Player);
|
Player.gang.process(numCycles, Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,7 +1132,7 @@ const Engine = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gang progress for BitNode 2
|
// Gang progress for BitNode 2
|
||||||
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
|
if (Player.inGang()) {
|
||||||
Player.gang.process(numCyclesOffline, Player);
|
Player.gang.process(numCyclesOffline, Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1281,13 +1280,9 @@ const Engine = {
|
|||||||
Engine.Display.factionsContent = document.getElementById("factions-container");
|
Engine.Display.factionsContent = document.getElementById("factions-container");
|
||||||
Engine.Display.factionsContent.style.display = "none";
|
Engine.Display.factionsContent.style.display = "none";
|
||||||
|
|
||||||
|
|
||||||
Engine.Display.factionContent = document.getElementById("faction-container");
|
Engine.Display.factionContent = document.getElementById("faction-container");
|
||||||
Engine.Display.factionContent.style.display = "none";
|
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 = document.getElementById("augmentations-container");
|
||||||
Engine.Display.augmentationsContent.style.display = "none";
|
Engine.Display.augmentationsContent.style.display = "none";
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
|
|
||||||
<div id="script-editor-filename-wrapper">
|
<div id="script-editor-filename-wrapper">
|
||||||
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
|
<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>
|
||||||
|
|
||||||
<div id="ace-editor"></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) -->
|
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
||||||
<div id="faction-container" class="generic-menupage-container"></div>
|
<div id="faction-container" class="generic-menupage-container"></div>
|
||||||
|
|
||||||
<div id="faction-augmentations-container" class="generic-menupage-container"></div>
|
|
||||||
|
|
||||||
<!-- Augmentations -->
|
<!-- Augmentations -->
|
||||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
<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> {
|
export class ParagraphWithTooltip extends React.Component<IParagraphWithTooltipProps, any> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<p className={"tooltip"}>
|
<p className={"tooltip"} style={this.props.style}>
|
||||||
{this.props.text}
|
{this.props.text}
|
||||||
<span className={"tooltiptext"}>
|
<span className={"tooltiptext"}>
|
||||||
{this.props.tooltip}
|
{this.props.tooltip}
|
||||||
|
Loading…
Reference in New Issue
Block a user