mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 20:55:44 +01:00
Initial v0.46.0 changes - Fixed BN9 bugs. Rebalanced BN11 and Corporations. Added memory to Dup sleeves. Various bug fixes
This commit is contained in:
parent
83fc4d81b2
commit
c4cb7daac5
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
/* Pop-up boxes */
|
/* Pop-up boxes */
|
||||||
.popup-box-container {
|
.popup-box-container {
|
||||||
display: none; /* Hidden by default */
|
display: none; /* Initially hidden */
|
||||||
position: fixed; /* Stay in place */
|
position: fixed; /* Stay in place */
|
||||||
z-index: 10; /* Sit on top */
|
z-index: 10; /* Sit on top */
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -80,6 +80,16 @@ when you normally install Augmentations.
|
|||||||
The cost of purchasing an Augmentation for a Duplicate Sleeve is **not** affected
|
The cost of purchasing an Augmentation for a Duplicate Sleeve is **not** affected
|
||||||
by how many Augmentations you have purchased for yourself, and vice versa.
|
by how many Augmentations you have purchased for yourself, and vice versa.
|
||||||
|
|
||||||
|
Memory
|
||||||
|
~~~~~~
|
||||||
|
Sleeve memory dictates what a sleeve's synchronization will be when its reset by
|
||||||
|
switching BitNodes. For example, if a sleeve has a memory of 10, then when you
|
||||||
|
switch BitNodes its synchronization will initially be set to 10, rather than 1.
|
||||||
|
|
||||||
|
Memory can only be increased by purchasing upgrades from The Covenant.
|
||||||
|
It is a persistent stat, meaning it never gets reset back to 1.
|
||||||
|
The maximum possible value for a sleeve's memory is 100.
|
||||||
|
|
||||||
Re-sleeving
|
Re-sleeving
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
Re-sleeving is the process of digitizing and transferring your consciousness into a
|
Re-sleeving is the process of digitizing and transferring your consciousness into a
|
||||||
|
@ -10,8 +10,8 @@ getSleeveStats() Netscript Function
|
|||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
{
|
{
|
||||||
shock: current shock of the sleeve [0-1],
|
shock: current shock of the sleeve [0-100],
|
||||||
sync: current sync of the sleeve [0-1],
|
sync: current sync of the sleeve [0-100],
|
||||||
hacking_skill: current hacking skill of the sleeve,
|
hacking_skill: current hacking skill of the sleeve,
|
||||||
strength: current strength of the sleeve,
|
strength: current strength of the sleeve,
|
||||||
defense: current defense of the sleeve,
|
defense: current defense of the sleeve,
|
||||||
|
@ -4,6 +4,6 @@ purchaseSleeveAug() Netscript Function
|
|||||||
.. js:function:: purchaseSleeveAug(sleeveNumber, augName)
|
.. js:function:: purchaseSleeveAug(sleeveNumber, augName)
|
||||||
|
|
||||||
:param int sleeveNumber: Index of the sleeve to buy an aug for. See :ref:`here <netscript_sleeveapi_referencingaduplicatesleeve>`
|
:param int sleeveNumber: Index of the sleeve to buy an aug for. See :ref:`here <netscript_sleeveapi_referencingaduplicatesleeve>`
|
||||||
:param string augName: Name of the aug to buy. See :ref:`here <netscript_sleeveapi_referencingaduplicatesleeve>`
|
:param string augName: Name of the aug to buy. Must be an exact match
|
||||||
|
|
||||||
Return true if the aug was purchased and installed on the sleeve.
|
Return true if the aug was purchased and installed on the sleeve.
|
||||||
|
@ -201,8 +201,9 @@ export function initBitNodes() {
|
|||||||
"were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as " +
|
"were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as " +
|
||||||
"governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.<br><br>" +
|
"governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.<br><br>" +
|
||||||
"In this BitNode:<br><br>" +
|
"In this BitNode:<br><br>" +
|
||||||
|
"Your hacking stat and experience gain are halved<br>" +
|
||||||
"The starting and maximum amount of money available on servers is significantly decreased<br>" +
|
"The starting and maximum amount of money available on servers is significantly decreased<br>" +
|
||||||
"The growth rate of servers is halved<br>" +
|
"The growth rate of servers is significantly reduced<br>" +
|
||||||
"Weakening a server is twice as effective<br>" +
|
"Weakening a server is twice as effective<br>" +
|
||||||
"Company wages are decreased by 50%<br>" +
|
"Company wages are decreased by 50%<br>" +
|
||||||
"Corporation valuations are 99% lower and are therefore significantly less profitable<br>" +
|
"Corporation valuations are 99% lower and are therefore significantly less profitable<br>" +
|
||||||
@ -213,9 +214,9 @@ export function initBitNodes() {
|
|||||||
"upgrade its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH " +
|
"upgrade its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH " +
|
||||||
"the player's salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain). " +
|
"the player's salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain). " +
|
||||||
"This Source-File also increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
"This Source-File also increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
||||||
"Level 1: 24%<br>" +
|
"Level 1: 32%<br>" +
|
||||||
"Level 2: 36%<br>" +
|
"Level 2: 48%<br>" +
|
||||||
"Level 3: 42%");
|
"Level 3: 56%");
|
||||||
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
||||||
"To iterate is human, to recurse divine.<br><br>" +
|
"To iterate is human, to recurse divine.<br><br>" +
|
||||||
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give your Souce-File 12, or " +
|
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give your Souce-File 12, or " +
|
||||||
@ -349,17 +350,20 @@ export function initBitNodeMultipliers(p: IPlayer) {
|
|||||||
BitNodeMultipliers.CodingContractMoney = 0;
|
BitNodeMultipliers.CodingContractMoney = 0;
|
||||||
break;
|
break;
|
||||||
case 9: // Hacktocracy
|
case 9: // Hacktocracy
|
||||||
BitNodeMultipliers.HackingLevelMultiplier = 0.3;
|
BitNodeMultipliers.HackingLevelMultiplier = 0.4;
|
||||||
BitNodeMultipliers.StrengthLevelMultiplier = 0.45;
|
BitNodeMultipliers.StrengthLevelMultiplier = 0.45;
|
||||||
BitNodeMultipliers.DefenseLevelMultiplier = 0.45;
|
BitNodeMultipliers.DefenseLevelMultiplier = 0.45;
|
||||||
BitNodeMultipliers.DexterityLevelMultiplier = 0.45;
|
BitNodeMultipliers.DexterityLevelMultiplier = 0.45;
|
||||||
BitNodeMultipliers.AgilityLevelMultiplier = 0.45;
|
BitNodeMultipliers.AgilityLevelMultiplier = 0.45;
|
||||||
BitNodeMultipliers.CharismaLevelMultiplier = 0.45;
|
BitNodeMultipliers.CharismaLevelMultiplier = 0.45;
|
||||||
BitNodeMultipliers.PurchasedServerLimit = 0;
|
BitNodeMultipliers.PurchasedServerLimit = 0;
|
||||||
BitNodeMultipliers.HomeComputerRamCost = 3;
|
BitNodeMultipliers.HomeComputerRamCost = 5;
|
||||||
BitNodeMultipliers.CrimeMoney = 0.5;
|
BitNodeMultipliers.CrimeMoney = 0.5;
|
||||||
BitNodeMultipliers.ScriptHackMoney = 0.1;
|
BitNodeMultipliers.ScriptHackMoney = 0.1;
|
||||||
BitNodeMultipliers.HackExpGain = 0.1;
|
BitNodeMultipliers.HackExpGain = 0.1;
|
||||||
|
BitNodeMultipliers.ServerStartingMoney = 0.1;
|
||||||
|
BitNodeMultipliers.ServerMaxMoney = 0.1;
|
||||||
|
BitNodeMultipliers.ServerStartingSecurity = 2.5;
|
||||||
break;
|
break;
|
||||||
case 10: // Digital Carbon
|
case 10: // Digital Carbon
|
||||||
BitNodeMultipliers.HackingLevelMultiplier = 0.2;
|
BitNodeMultipliers.HackingLevelMultiplier = 0.2;
|
||||||
@ -385,9 +389,11 @@ export function initBitNodeMultipliers(p: IPlayer) {
|
|||||||
BitNodeMultipliers.BladeburnerRank = 0.8;
|
BitNodeMultipliers.BladeburnerRank = 0.8;
|
||||||
break;
|
break;
|
||||||
case 11: //The Big Crash
|
case 11: //The Big Crash
|
||||||
|
BitNodeMultipliers.HackingLevelMultiplier = 0.5;
|
||||||
|
BitNodeMultipliers.HackExpGain = 0.5;
|
||||||
BitNodeMultipliers.ServerMaxMoney = 0.1;
|
BitNodeMultipliers.ServerMaxMoney = 0.1;
|
||||||
BitNodeMultipliers.ServerStartingMoney = 0.1;
|
BitNodeMultipliers.ServerStartingMoney = 0.1;
|
||||||
BitNodeMultipliers.ServerGrowthRate = 0.5;
|
BitNodeMultipliers.ServerGrowthRate = 0.2;
|
||||||
BitNodeMultipliers.ServerWeakenRate = 2;
|
BitNodeMultipliers.ServerWeakenRate = 2;
|
||||||
BitNodeMultipliers.CrimeMoney = 3;
|
BitNodeMultipliers.CrimeMoney = 3;
|
||||||
BitNodeMultipliers.CompanyWorkMoney = 0.5;
|
BitNodeMultipliers.CompanyWorkMoney = 0.5;
|
||||||
@ -395,8 +401,8 @@ export function initBitNodeMultipliers(p: IPlayer) {
|
|||||||
BitNodeMultipliers.AugmentationMoneyCost = 2;
|
BitNodeMultipliers.AugmentationMoneyCost = 2;
|
||||||
BitNodeMultipliers.InfiltrationMoney = 2.5;
|
BitNodeMultipliers.InfiltrationMoney = 2.5;
|
||||||
BitNodeMultipliers.InfiltrationRep = 2.5;
|
BitNodeMultipliers.InfiltrationRep = 2.5;
|
||||||
BitNodeMultipliers.CorporationValuation = 0.01;
|
BitNodeMultipliers.CorporationValuation = 0.1;
|
||||||
BitNodeMultipliers.CodingContractMoney = 0.5;
|
BitNodeMultipliers.CodingContractMoney = 0.25;
|
||||||
BitNodeMultipliers.FourSigmaMarketDataCost = 4;
|
BitNodeMultipliers.FourSigmaMarketDataCost = 4;
|
||||||
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
|
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
|
||||||
break;
|
break;
|
||||||
|
@ -78,8 +78,8 @@ const RanksPerSkillPoint = 3; //How many ranks needed to get 1 Skill
|
|||||||
|
|
||||||
const ContractBaseMoneyGain = 250e3; //Base Money Gained per contract
|
const ContractBaseMoneyGain = 250e3; //Base Money Gained per contract
|
||||||
|
|
||||||
const HrcHpGain = 2; // HP gained from Hyperbolic Regeneration Chamber
|
const HrcHpGain = 2; // HP Gained from Hyperbolic Regeneration chamber
|
||||||
const HrcStaminaGain = 0.1; // Stamina gained from Hyperbolic Regeneration Chamber
|
const HrcStaminaGain = 1; // Percentage Stamina gained from Hyperbolic Regeneration Chamber
|
||||||
|
|
||||||
//DOM related variables
|
//DOM related variables
|
||||||
var ActiveActionCssClass = "bladeburner-active-action";
|
var ActiveActionCssClass = "bladeburner-active-action";
|
||||||
@ -1417,14 +1417,17 @@ Bladeburner.prototype.completeAction = function() {
|
|||||||
}
|
}
|
||||||
this.startAction(this.action); // Repeat Action
|
this.startAction(this.action); // Repeat Action
|
||||||
break;
|
break;
|
||||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
case ActionTypes["Hyperbolic Regeneration Chamber"]: {
|
||||||
Player.regenerateHp(HrcHpGain);
|
Player.regenerateHp(HrcHpGain);
|
||||||
this.stamina = Math.min(this.maxStamina, this.stamina + HrcStaminaGain);
|
|
||||||
|
const staminaGain = this.maxStamina * (HrcStaminaGain / 100);
|
||||||
|
this.stamina = Math.min(this.maxStamina, this.stamina + staminaGain);
|
||||||
this.startAction(this.action);
|
this.startAction(this.action);
|
||||||
if (this.logging.general) {
|
if (this.logging.general) {
|
||||||
this.log(`Rested in Hyperbolic Regeneration Chamber. Restored ${HrcHpGain} HP and gained ${HrcStaminaGain} stamina`);
|
this.log(`Rested in Hyperbolic Regeneration Chamber. Restored ${HrcHpGain} HP and gained ${numeralWrapper.format(staminaGain, "0.0")} stamina`);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
console.error(`Bladeburner.completeAction() called for invalid action: ${this.action.type}`);
|
console.error(`Bladeburner.completeAction() called for invalid action: ${this.action.type}`);
|
||||||
break;
|
break;
|
||||||
@ -2513,7 +2516,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
|
|||||||
display:"inline-block",
|
display:"inline-block",
|
||||||
innerHTML:action.desc + "\n\n" +
|
innerHTML:action.desc + "\n\n" +
|
||||||
`Estimated success chance: ${formatNumber(estimatedSuccessChance*100, 1)}% ${action.isStealth?stealthIcon:''}${action.isKill?killIcon:''}\n` +
|
`Estimated success chance: ${formatNumber(estimatedSuccessChance*100, 1)}% ${action.isStealth?stealthIcon:''}${action.isKill?killIcon:''}\n` +
|
||||||
|
|
||||||
"Time Required (s): " + formatNumber(actionTime, 0) + "\n" +
|
"Time Required (s): " + formatNumber(actionTime, 0) + "\n" +
|
||||||
"Contracts remaining: " + Math.floor(action.count) + "\n" +
|
"Contracts remaining: " + Math.floor(action.count) + "\n" +
|
||||||
"Successes: " + action.successes + "\n" +
|
"Successes: " + action.successes + "\n" +
|
||||||
|
@ -116,7 +116,7 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
InfiltrationBribeBaseAmount: 100e3, //Amount per clearance level
|
InfiltrationBribeBaseAmount: 100e3, //Amount per clearance level
|
||||||
InfiltrationMoneyValue: 5e3, //Convert "secret" value to money
|
InfiltrationMoneyValue: 5e3, //Convert "secret" value to money
|
||||||
InfiltrationRepValue: 1.4, //Convert "secret" value to faction reputation
|
InfiltrationRepValue: 1.4, //Convert "secret" value to faction reputation
|
||||||
InfiltrationExpPow: 0.7,
|
InfiltrationExpPow: 0.8,
|
||||||
|
|
||||||
//Stock market constants
|
//Stock market constants
|
||||||
WSEAccountCost: 200e6,
|
WSEAccountCost: 200e6,
|
||||||
@ -273,37 +273,20 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
|
|
||||||
LatestUpdate:
|
LatestUpdate:
|
||||||
`
|
`
|
||||||
v0.45.1
|
v0.46.0
|
||||||
* Added two new Corporation Researches
|
* Added BitNode-9: Hacktocracy
|
||||||
* General UI improvements (by hydroflame and koriar)
|
* Changed BitNode-11's multipliers to make it slightly harder overall
|
||||||
* Bug Fix: Sleeve Netscript API should no longer cause Dynamic RAM errors
|
* Source-File 11 is now slightly stronger
|
||||||
* Bug Fix: sleeve.getSleeveStats() should now work properly
|
* Added several functions to Netscript Sleeve API for buying Sleeve augmentations (by hydroflame)
|
||||||
|
* Added a new stat for Duplicate Sleeves: Memory
|
||||||
|
* Increase baseline experience earned from Infiltration, but it now gives diminishing returns (on exp) as you get to higher difficulties/levels
|
||||||
|
* In Bladeburner, stamina gained from Hyperbolic Regeneration Chamber is now a percentage of your max stamina
|
||||||
|
|
||||||
v0.45.0
|
* Corporation Changes:
|
||||||
* Corporation changes:
|
** 'Demand' value of products decreases more slowly
|
||||||
** Decreased the time of a full market cycle from 15 seconds to 10 seconds.
|
** Bug Fix: Fixed a Corporation issue that broke the Market-TA2 Research
|
||||||
** This means that each Corporation 'state' will now only take 2 seconds, rather than 3
|
|
||||||
** Increased initial salaries for newly-hired employees
|
* Bug Fix: Money Statistics tracker was incorrectly recording profits when selling stocks manually
|
||||||
** Increased the cost multiplier for upgrading office size (the cost will increase faster)
|
* Bug Fix: Fixed an issue with the job requirement tooltip for security jobs
|
||||||
** The stats of your employees now has a slightly larger effect on production & sales
|
|
||||||
** Added several new Research upgrades
|
|
||||||
** Market-TA research now allows you to automatically set sale price at optimal values
|
|
||||||
** Market-TA research now works for Products (not just Materials)
|
|
||||||
** Reduced the amount of Scientific Research needed to unlock the Hi-Tech R&D Laboratory from 10k to 5k
|
|
||||||
** Energy Material requirement of the Software industry reduced from 1 to 0.5
|
|
||||||
** It is now slightly easier to increase the Software industry's production multiplier
|
|
||||||
** Industries now have a maximum number of allowed products, starting at 3. This can be increased through research.
|
|
||||||
** You can now see an approximation of how each material affects an industry's production multiplier by clicking the "?" help tip next to it
|
|
||||||
** Significantly changed the effects of the different employee positions. See updated descriptions
|
|
||||||
** Reduced the amount of money you gain from private investors
|
|
||||||
** Training employees is now 3x more effective
|
|
||||||
** Bug Fix: An industry's products are now properly separated between different cities
|
|
||||||
* The QLink Augemntation is now significantly stronger, but also significantly more expensive (by hydroflame)
|
|
||||||
* Added a Netscript API for Duplicate Sleeves (by hydroflame)
|
|
||||||
* Modified the multipliers of BitNode-3 and BitNode-8 to make them slightly harder
|
|
||||||
* After installing Augmentations, Duplicate Sleeves will now default to Synchronize if their Shock is 0
|
|
||||||
* Bug Fix: Bladeburner's Hyperbolic Regeneration Chamber should no longer instantly refill all stamina
|
|
||||||
* Bug Fix: growthAnalyze() function now properly accounts for BitNode multipliers
|
|
||||||
* Bug Fix: The cost of purchasing Augmentations for Duplicate Sleeves no longer scales with how many Augs you've purchased for yourself
|
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
@ -563,13 +563,15 @@ Industry.prototype.processMaterialMarket = function(marketCycles=1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Process change in demand and competition for this industry's products
|
// Process change in demand and competition for this industry's products
|
||||||
Industry.prototype.processProductMarket = function(marketCycles=1) {
|
Industry.prototype.processProductMarket = function(marketCycles=1) {
|
||||||
//Demand gradually decreases, and competition gradually increases
|
// Demand gradually decreases, and competition gradually increases
|
||||||
for (var name in this.products) {
|
for (const name in this.products) {
|
||||||
if (this.products.hasOwnProperty(name)) {
|
if (this.products.hasOwnProperty(name)) {
|
||||||
var product = this.products[name];
|
const product = this.products[name];
|
||||||
var change = getRandomInt(1, 3) * 0.0004;
|
let change = getRandomInt(0, 3) * 0.0004;
|
||||||
|
if (change === 0) { continue; }
|
||||||
|
|
||||||
if (this.type === Industries.Pharmaceutical || this.type === Industries.Software ||
|
if (this.type === Industries.Pharmaceutical || this.type === Industries.Software ||
|
||||||
this.type === Industries.Robotics) {
|
this.type === Industries.Robotics) {
|
||||||
change *= 3;
|
change *= 3;
|
||||||
@ -770,7 +772,17 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
|||||||
* advertisingFactor
|
* advertisingFactor
|
||||||
* this.getSalesMultiplier());
|
* this.getSalesMultiplier());
|
||||||
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
|
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
|
||||||
const optimalPrice = (numerator / denominator) + mat.bCost;
|
let optimalPrice;
|
||||||
|
if (sqrtDenominator === 0 || denominator === 0) {
|
||||||
|
if (sqrtNumerator === 0) {
|
||||||
|
optimalPrice = 0; // No production
|
||||||
|
} else {
|
||||||
|
optimalPrice = mat.bCost + markupLimit;
|
||||||
|
console.warn(`In Corporation, found illegal 0s when trying to calculate MarketTA2 sale cost`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
optimalPrice = (numerator / denominator) + mat.bCost;
|
||||||
|
}
|
||||||
|
|
||||||
// We'll store this "Optimal Price" in a property so that we don't have
|
// We'll store this "Optimal Price" in a property so that we don't have
|
||||||
// to re-calculate it for the UI
|
// to re-calculate it for the UI
|
||||||
@ -1089,7 +1101,12 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
|
|||||||
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
|
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
|
||||||
let optimalPrice;
|
let optimalPrice;
|
||||||
if (sqrtDenominator === 0 || denominator === 0) {
|
if (sqrtDenominator === 0 || denominator === 0) {
|
||||||
optimalPrice = 0;
|
if (sqrtNumerator === 0) {
|
||||||
|
optimalPrice = 0; // No production
|
||||||
|
} else {
|
||||||
|
optimalPrice = product.pCost + markupLimit;
|
||||||
|
console.warn(`In Corporation, found illegal 0s when trying to calculate MarketTA2 sale cost`);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
optimalPrice = (numerator / denominator) + product.pCost;
|
optimalPrice = (numerator / denominator) + product.pCost;
|
||||||
}
|
}
|
||||||
@ -1251,7 +1268,7 @@ Industry.prototype.getAdvertisingFactors = function() {
|
|||||||
|
|
||||||
//Returns a multiplier based on a materials demand and competition that affects sales
|
//Returns a multiplier based on a materials demand and competition that affects sales
|
||||||
Industry.prototype.getMarketFactor = function(mat) {
|
Industry.prototype.getMarketFactor = function(mat) {
|
||||||
return mat.dmd * (100 - mat.cmp)/100;
|
return Math.max(0.1, mat.dmd * (100 - mat.cmp) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a boolean indicating whether this Industry has the specified Research
|
// Returns a boolean indicating whether this Industry has the specified Research
|
||||||
|
@ -86,7 +86,7 @@ export class Material {
|
|||||||
this.mku = 6;
|
this.mku = 6;
|
||||||
break;
|
break;
|
||||||
case "Energy":
|
case "Energy":
|
||||||
this.dmd = 90; this.dmdR = [80, 100];
|
this.dmd = 90; this.dmdR = [80, 99];
|
||||||
this.cmp = 80; this.cmpR = [65, 95];
|
this.cmp = 80; this.cmpR = [65, 95];
|
||||||
this.bCost = 2000; this.mv = 0.2;
|
this.bCost = 2000; this.mv = 0.2;
|
||||||
this.mku = 6;
|
this.mku = 6;
|
||||||
@ -122,26 +122,26 @@ export class Material {
|
|||||||
this.mku = 2;
|
this.mku = 2;
|
||||||
break;
|
break;
|
||||||
case "Real Estate":
|
case "Real Estate":
|
||||||
this.dmd = 50; this.dmdR = [5, 100];
|
this.dmd = 50; this.dmdR = [5, 99];
|
||||||
this.cmp = 50; this.cmpR = [25, 75];
|
this.cmp = 50; this.cmpR = [25, 75];
|
||||||
this.bCost = 80e3; this.mv = 1.5; //Less mv bc its processed twice
|
this.bCost = 80e3; this.mv = 1.5; //Less mv bc its processed twice
|
||||||
this.mku = 1.5;
|
this.mku = 1.5;
|
||||||
break;
|
break;
|
||||||
case "Drugs":
|
case "Drugs":
|
||||||
this.dmd = 60; this.dmdR = [45, 75];
|
this.dmd = 60; this.dmdR = [45, 75];
|
||||||
this.cmp = 70; this.cmpR = [40, 100];
|
this.cmp = 70; this.cmpR = [40, 99];
|
||||||
this.bCost = 40e3; this.mv = 1.6;
|
this.bCost = 40e3; this.mv = 1.6;
|
||||||
this.mku = 1;
|
this.mku = 1;
|
||||||
break;
|
break;
|
||||||
case "Robots":
|
case "Robots":
|
||||||
this.dmd = 90; this.dmdR = [80, 100];
|
this.dmd = 90; this.dmdR = [80, 9];
|
||||||
this.cmp = 90; this.cmpR = [80, 100];
|
this.cmp = 90; this.cmpR = [80, 9];
|
||||||
this.bCost = 75e3; this.mv = 0.5; //Less mv bc its processed twice
|
this.bCost = 75e3; this.mv = 0.5; //Less mv bc its processed twice
|
||||||
this.mku = 1;
|
this.mku = 1;
|
||||||
break;
|
break;
|
||||||
case "AI Cores":
|
case "AI Cores":
|
||||||
this.dmd = 90; this.dmdR = [80, 100];
|
this.dmd = 90; this.dmdR = [80, 99];
|
||||||
this.cmp = 90; this.cmpR = [80, 100];
|
this.cmp = 90; this.cmpR = [80, 9];
|
||||||
this.bCost = 15e3; this.mv = 0.8; //Less mv bc its processed twice
|
this.bCost = 15e3; this.mv = 0.8; //Less mv bc its processed twice
|
||||||
this.mku = 0.5;
|
this.mku = 0.5;
|
||||||
break;
|
break;
|
||||||
|
@ -780,7 +780,12 @@ export class CorporationEventHandler {
|
|||||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
||||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
||||||
|
|
||||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, closeBtn]);
|
const ta2OverridesTa1 = createElement("p", {
|
||||||
|
innerText: "Note that Market-TA.II overrides Market-TA.I. This means that if " +
|
||||||
|
"both are enabled, then Market-TA.II will take effect, not Market-TA.I"
|
||||||
|
});
|
||||||
|
|
||||||
|
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, ta2OverridesTa1, closeBtn]);
|
||||||
} else {
|
} else {
|
||||||
// Market-TA.I only
|
// Market-TA.I only
|
||||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
||||||
@ -1052,7 +1057,12 @@ export class CorporationEventHandler {
|
|||||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
||||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
||||||
|
|
||||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, closeBtn]);
|
const ta2OverridesTa1 = createElement("p", {
|
||||||
|
innerText: "Note that Market-TA.II overrides Market-TA.I. This means that if " +
|
||||||
|
"both are enabled, then Market-TA.II will take effect, not Market-TA.I"
|
||||||
|
});
|
||||||
|
|
||||||
|
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, ta2OverridesTa1, closeBtn]);
|
||||||
} else {
|
} else {
|
||||||
// Market-TA.I only
|
// Market-TA.I only
|
||||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
||||||
|
@ -301,7 +301,7 @@ export class IndustryOffice extends BaseReactComponent {
|
|||||||
|
|
||||||
<p>Avg Employee Morale: {numeralWrapper.format(avgMorale, "0.000")}</p>
|
<p>Avg Employee Morale: {numeralWrapper.format(avgMorale, "0.000")}</p>
|
||||||
<p>Avg Employee Happiness: {numeralWrapper.format(avgHappiness, "0.000")}</p>
|
<p>Avg Employee Happiness: {numeralWrapper.format(avgHappiness, "0.000")}</p>
|
||||||
<p>Avg Energy Morale: {numeralWrapper.format(avgEnergy, "0.000")}</p>
|
<p>Avg Employee Energy: {numeralWrapper.format(avgEnergy, "0.000")}</p>
|
||||||
<p>Total Employee Salary: {numeralWrapper.formatMoney(totalSalary)}</p>
|
<p>Total Employee Salary: {numeralWrapper.formatMoney(totalSalary)}</p>
|
||||||
{
|
{
|
||||||
vechain &&
|
vechain &&
|
||||||
|
@ -218,7 +218,7 @@ function MaterialComponent(props) {
|
|||||||
mat.buy === 0 && mat.imp === 0;
|
mat.buy === 0 && mat.imp === 0;
|
||||||
|
|
||||||
// Purchase material button
|
// Purchase material button
|
||||||
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nf)})`;
|
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nfB)})`;
|
||||||
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
||||||
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division, warehouse);
|
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division, warehouse);
|
||||||
|
|
||||||
@ -229,9 +229,9 @@ function MaterialComponent(props) {
|
|||||||
let sellButtonText;
|
let sellButtonText;
|
||||||
if (mat.sllman[0]) {
|
if (mat.sllman[0]) {
|
||||||
if (isString(mat.sllman[1])) {
|
if (isString(mat.sllman[1])) {
|
||||||
sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nf)}/${mat.sllman[1]})`
|
sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nfB)}/${mat.sllman[1]})`
|
||||||
} else {
|
} else {
|
||||||
sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nf)}/${numeralWrapper.format(mat.sllman[1], nf)})`;
|
sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nfB)}/${numeralWrapper.format(mat.sllman[1], nfB)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mat.marketTa2) {
|
if (mat.marketTa2) {
|
||||||
@ -469,7 +469,7 @@ export class IndustryWarehouse extends BaseReactComponent {
|
|||||||
return (
|
return (
|
||||||
<div className={"cmpy-mgmt-warehouse-panel"}>
|
<div className={"cmpy-mgmt-warehouse-panel"}>
|
||||||
<p className={"tooltip"} style={sizeUsageStyle}>
|
<p className={"tooltip"} style={sizeUsageStyle}>
|
||||||
Storage: {numeralWrapper.format(warehouse.sizeUsed, "0.000")} / {numeralWrapper.format(warehouse.size, "0.000")}
|
Storage: {numeralWrapper.formatBigNumber(warehouse.sizeUsed)} / {numeralWrapper.formatBigNumber(warehouse.size)}
|
||||||
<span className={"tooltiptext"} dangerouslySetInnerHTML={{__html: warehouse.breakdown}}></span>
|
<span className={"tooltiptext"} dangerouslySetInnerHTML={{__html: warehouse.breakdown}}></span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import { PurchaseAugmentationsOrderSetting } from "../Settings/SettingEnums";
|
|||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||||
|
|
||||||
import { createPurchaseSleevesFromCovenantPopup } from "../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
import { createSleevePurchasesFromCovenantPopup } from "../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||||
|
|
||||||
import {Page, routing} from "../ui/navigationTracking";
|
import {Page, routing} from "../ui/navigationTracking";
|
||||||
import {numeralWrapper} from "../ui/numeralFormat";
|
import {numeralWrapper} from "../ui/numeralFormat";
|
||||||
@ -348,7 +348,7 @@ function displayFactionContent(factionName) {
|
|||||||
class: "std-button",
|
class: "std-button",
|
||||||
innerText: "Purchase Duplicate Sleeves",
|
innerText: "Purchase Duplicate Sleeves",
|
||||||
clickListener: () => {
|
clickListener: () => {
|
||||||
createPurchaseSleevesFromCovenantPopup(Player);
|
createSleevePurchasesFromCovenantPopup(Player);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
covenantPurchaseSleevesDivWrapper.appendChild(createElement("p", {
|
covenantPurchaseSleevesDivWrapper.appendChild(createElement("p", {
|
||||||
|
@ -19,7 +19,8 @@ import { generateRandomContractOnHome } from "../CodingContractGenerator
|
|||||||
import { iTutorialSteps, iTutorialNextStep,
|
import { iTutorialSteps, iTutorialNextStep,
|
||||||
ITutorial} from "../InteractiveTutorial";
|
ITutorial} from "../InteractiveTutorial";
|
||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { AddToAllServers } from "../Server/AllServers";
|
import { AddToAllServers,
|
||||||
|
AllServers } from "../Server/AllServers";
|
||||||
import { GetServerByHostname } from "../Server/ServerHelpers";
|
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||||
import { Page, routing } from "../ui/navigationTracking";
|
import { Page, routing } from "../ui/navigationTracking";
|
||||||
@ -33,9 +34,10 @@ import { HacknetRoot } from "./ui/Root";
|
|||||||
let hacknetNodesDiv;
|
let hacknetNodesDiv;
|
||||||
function hacknetNodesInit() {
|
function hacknetNodesInit() {
|
||||||
hacknetNodesDiv = document.getElementById("hacknet-nodes-container");
|
hacknetNodesDiv = document.getElementById("hacknet-nodes-container");
|
||||||
|
document.removeEventListener("DOMContentLoaded", hacknetNodesInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", hacknetNodesInit, false);
|
document.addEventListener("DOMContentLoaded", hacknetNodesInit);
|
||||||
|
|
||||||
// Returns a boolean indicating whether the player has Hacknet Servers
|
// Returns a boolean indicating whether the player has Hacknet Servers
|
||||||
// (the upgraded form of Hacknet Nodes)
|
// (the upgraded form of Hacknet Nodes)
|
||||||
@ -73,7 +75,7 @@ export function purchaseHacknet() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
Player.loseMoney(cost);
|
||||||
Player.hacknetNodes.push(server);
|
Player.hacknetNodes.push(server.ip);
|
||||||
|
|
||||||
// Configure the HacknetServer to actually act as a Server
|
// Configure the HacknetServer to actually act as a Server
|
||||||
AddToAllServers(server);
|
AddToAllServers(server);
|
||||||
@ -308,7 +310,8 @@ function processAllHacknetServerEarnings(numCycles) {
|
|||||||
|
|
||||||
let hashes = 0;
|
let hashes = 0;
|
||||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
||||||
hashes += Player.hacknetNodes[i].process(numCycles);
|
const hserver = AllServers[Player.hacknetNodes[i]]; // hacknetNodes array only contains the IP addresses
|
||||||
|
hashes += hserver.process(numCycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.hashManager.storeHashes(hashes);
|
Player.hashManager.storeHashes(hashes);
|
||||||
@ -316,16 +319,6 @@ function processAllHacknetServerEarnings(numCycles) {
|
|||||||
return hashes;
|
return hashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHacknetNode(name) {
|
|
||||||
for (var i = 0; i < Player.hacknetNodes.length; ++i) {
|
|
||||||
if (Player.hacknetNodes[i].name == name) {
|
|
||||||
return Player.hacknetNodes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function purchaseHashUpgrade(upgName, upgTarget) {
|
export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||||
if (!(Player.hashManager instanceof HashManager)) {
|
if (!(Player.hashManager instanceof HashManager)) {
|
||||||
console.error(`Player does not have a HashManager`);
|
console.error(`Player does not have a HashManager`);
|
||||||
@ -423,7 +416,6 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Hash Upgrade successfully purchased");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import { Generic_fromJSON,
|
|||||||
export const HacknetServerHashesPerLevel: number = 0.001;
|
export const HacknetServerHashesPerLevel: number = 0.001;
|
||||||
|
|
||||||
// Constants for Hacknet Server purchase/upgrade costs
|
// Constants for Hacknet Server purchase/upgrade costs
|
||||||
export const BaseCostForHacknetServer: number = 10e3;
|
export const BaseCostForHacknetServer: number = 50e3;
|
||||||
export const BaseCostFor1GBHacknetServerRam: number = 200e3;
|
export const BaseCostFor1GBHacknetServerRam: number = 200e3;
|
||||||
export const BaseCostForHacknetServerCore: number = 1e6;
|
export const BaseCostForHacknetServerCore: number = 1e6;
|
||||||
export const BaseCostForHacknetServerCache: number = 10e6;
|
export const BaseCostForHacknetServerCache: number = 10e6;
|
||||||
@ -37,7 +37,7 @@ export const MaxNumberHacknetServers: number = 25; // Max number of Hac
|
|||||||
export const HacknetServerMaxLevel: number = 300;
|
export const HacknetServerMaxLevel: number = 300;
|
||||||
export const HacknetServerMaxRam: number = 8192;
|
export const HacknetServerMaxRam: number = 8192;
|
||||||
export const HacknetServerMaxCores: number = 128;
|
export const HacknetServerMaxCores: number = 128;
|
||||||
export const HacknetServerMaxCache: number = 15; // Max cache level. So max capacity is 2 ^ 12
|
export const HacknetServerMaxCache: number = 15;
|
||||||
|
|
||||||
interface IConstructorParams {
|
interface IConstructorParams {
|
||||||
adminRights?: boolean;
|
adminRights?: boolean;
|
||||||
@ -306,6 +306,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
|||||||
this.maxRam *= 2;
|
this.maxRam *= 2;
|
||||||
}
|
}
|
||||||
this.maxRam = Math.round(this.maxRam);
|
this.maxRam = Math.round(this.maxRam);
|
||||||
|
this.updateHashRate(p);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -321,7 +322,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateHashCapacity(): void {
|
updateHashCapacity(): void {
|
||||||
this.hashCapacity = 16 * Math.pow(2, this.cache);
|
this.hashCapacity = 32 * Math.pow(2, this.cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHashRate(p: IPlayer): void {
|
updateHashRate(p: IPlayer): void {
|
||||||
|
@ -11,6 +11,7 @@ import { HashUpgrades } from "./HashUpgrades";
|
|||||||
|
|
||||||
import { IMap } from "../types";
|
import { IMap } from "../types";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { AllServers } from "../Server/AllServers";
|
||||||
import { Generic_fromJSON,
|
import { Generic_fromJSON,
|
||||||
Generic_toJSON,
|
Generic_toJSON,
|
||||||
Reviver } from "../../utils/JSONReviver";
|
Reviver } from "../../utils/JSONReviver";
|
||||||
@ -106,13 +107,29 @@ export class HashManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateCapacity(p: IPlayer): void {
|
updateCapacity(p: IPlayer): void {
|
||||||
if (p.hacknetNodes.length <= 0) { this.capacity = 0; }
|
if (p.hacknetNodes.length <= 0) {
|
||||||
if (!(p.hacknetNodes[0] instanceof HacknetServer)) { this.capacity = 0; }
|
this.capacity = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the Player's `hacknetNodes` property actually holds Hacknet Servers
|
||||||
|
const ip: string = <string>p.hacknetNodes[0];
|
||||||
|
if (typeof ip !== "string") {
|
||||||
|
this.capacity = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hserver = <HacknetServer>AllServers[ip];
|
||||||
|
if (!(hserver instanceof HacknetServer)) {
|
||||||
|
this.capacity = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let total: number = 0;
|
let total: number = 0;
|
||||||
for (let i = 0; i < p.hacknetNodes.length; ++i) {
|
for (let i = 0; i < p.hacknetNodes.length; ++i) {
|
||||||
const hacknetServer = <HacknetServer>(p.hacknetNodes[i]);
|
const h = <HacknetServer>AllServers[<string>p.hacknetNodes[i]];
|
||||||
total += hacknetServer.hashCapacity;
|
total += h.hashCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.capacity = total;
|
this.capacity = total;
|
||||||
|
@ -17,8 +17,10 @@ import { getCostOfNextHacknetNode,
|
|||||||
purchaseHacknet } from "../HacknetHelpers";
|
purchaseHacknet } from "../HacknetHelpers";
|
||||||
|
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
|
import { AllServers } from "../../Server/AllServers";
|
||||||
|
|
||||||
import { createPopup } from "../../ui/React/createPopup";
|
import { createPopup } from "../../ui/React/createPopup";
|
||||||
|
import { PopupCloseButton } from "../../ui/React/PopupCloseButton";
|
||||||
|
|
||||||
export const PurchaseMultipliers = Object.freeze({
|
export const PurchaseMultipliers = Object.freeze({
|
||||||
"x1": 1,
|
"x1": 1,
|
||||||
@ -52,7 +54,12 @@ export class HacknetRoot extends React.Component {
|
|||||||
let total = 0;
|
let total = 0;
|
||||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers()) {
|
||||||
total += Player.hacknetNodes[i].hashRate;
|
const hserver = AllServers[Player.hacknetNodes[i]];
|
||||||
|
if (hserver) {
|
||||||
|
total += hserver.hashRate;
|
||||||
|
} else {
|
||||||
|
console.warn(`Could not find Hacknet Server object in AllServers map (i=${i})`)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
total += Player.hacknetNodes[i].moneyGainRatePerSecond;
|
total += Player.hacknetNodes[i].moneyGainRatePerSecond;
|
||||||
}
|
}
|
||||||
@ -97,10 +104,14 @@ export class HacknetRoot extends React.Component {
|
|||||||
// HacknetNode components
|
// HacknetNode components
|
||||||
const nodes = Player.hacknetNodes.map((node) => {
|
const nodes = Player.hacknetNodes.map((node) => {
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers()) {
|
||||||
|
const hserver = AllServers[node];
|
||||||
|
if (hserver == null) {
|
||||||
|
throw new Error(`Could not find Hacknet Server object in AllServers map for IP: ${node}`);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<HacknetServer
|
<HacknetServer
|
||||||
key={node.hostname}
|
key={hserver.hostname}
|
||||||
node={node}
|
node={hserver}
|
||||||
purchaseMultiplier={this.state.purchaseMultiplier}
|
purchaseMultiplier={this.state.purchaseMultiplier}
|
||||||
recalculate={this.recalculateTotalProduction.bind(this)}
|
recalculate={this.recalculateTotalProduction.bind(this)}
|
||||||
/>
|
/>
|
||||||
|
@ -54,7 +54,7 @@ function InfiltrationInstance(companyName, startLevel, val, maxClearance, diff)
|
|||||||
|
|
||||||
InfiltrationInstance.prototype.expMultiplier = function() {
|
InfiltrationInstance.prototype.expMultiplier = function() {
|
||||||
if (!this.clearanceLevel || isNaN(this.clearanceLevel) || !this.maxClearanceLevel ||isNaN(this.maxClearanceLevel)) return 1;
|
if (!this.clearanceLevel || isNaN(this.clearanceLevel) || !this.maxClearanceLevel ||isNaN(this.maxClearanceLevel)) return 1;
|
||||||
return 2 * this.clearanceLevel / this.maxClearanceLevel;
|
return 2.5 * this.clearanceLevel / this.maxClearanceLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainHackingExp = function(amt) {
|
InfiltrationInstance.prototype.gainHackingExp = function(amt) {
|
||||||
@ -64,7 +64,7 @@ InfiltrationInstance.prototype.gainHackingExp = function(amt) {
|
|||||||
|
|
||||||
InfiltrationInstance.prototype.calcGainedHackingExp = function() {
|
InfiltrationInstance.prototype.calcGainedHackingExp = function() {
|
||||||
if(!this.hackingExpGained || isNaN(this.hackingExpGained)) return 0;
|
if(!this.hackingExpGained || isNaN(this.hackingExpGained)) return 0;
|
||||||
return Math.pow(this.hackingExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
return Math.pow(this.hackingExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainStrengthExp = function(amt) {
|
InfiltrationInstance.prototype.gainStrengthExp = function(amt) {
|
||||||
@ -73,8 +73,8 @@ InfiltrationInstance.prototype.gainStrengthExp = function(amt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.calcGainedStrengthExp = function() {
|
InfiltrationInstance.prototype.calcGainedStrengthExp = function() {
|
||||||
if(!this.strExpGained || isNaN(this.strExpGained)) return 0;
|
if (!this.strExpGained || isNaN(this.strExpGained)) return 0;
|
||||||
return Math.pow(this.strExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
return Math.pow(this.strExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainDefenseExp = function(amt) {
|
InfiltrationInstance.prototype.gainDefenseExp = function(amt) {
|
||||||
@ -83,8 +83,8 @@ InfiltrationInstance.prototype.gainDefenseExp = function(amt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.calcGainedDefenseExp = function() {
|
InfiltrationInstance.prototype.calcGainedDefenseExp = function() {
|
||||||
if(!this.defExpGained || isNaN(this.defExpGained)) return 0;
|
if (!this.defExpGained || isNaN(this.defExpGained)) return 0;
|
||||||
return Math.pow(this.defExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
return Math.pow(this.defExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainDexterityExp = function(amt) {
|
InfiltrationInstance.prototype.gainDexterityExp = function(amt) {
|
||||||
@ -93,8 +93,8 @@ InfiltrationInstance.prototype.gainDexterityExp = function(amt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.calcGainedDexterityExp = function() {
|
InfiltrationInstance.prototype.calcGainedDexterityExp = function() {
|
||||||
if(!this.dexExpGained || isNaN(this.dexExpGained)) return 0;
|
if (!this.dexExpGained || isNaN(this.dexExpGained)) return 0;
|
||||||
return Math.pow(this.dexExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
return Math.pow(this.dexExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainAgilityExp = function(amt) {
|
InfiltrationInstance.prototype.gainAgilityExp = function(amt) {
|
||||||
@ -103,8 +103,8 @@ InfiltrationInstance.prototype.gainAgilityExp = function(amt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.calcGainedAgilityExp = function() {
|
InfiltrationInstance.prototype.calcGainedAgilityExp = function() {
|
||||||
if(!this.agiExpGained || isNaN(this.agiExpGained)) return 0;
|
if (!this.agiExpGained || isNaN(this.agiExpGained)) return 0;
|
||||||
return Math.pow(this.agiExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
return Math.pow(this.agiExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainCharismaExp = function(amt) {
|
InfiltrationInstance.prototype.gainCharismaExp = function(amt) {
|
||||||
@ -113,8 +113,8 @@ InfiltrationInstance.prototype.gainCharismaExp = function(amt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.calcGainedCharismaExp = function() {
|
InfiltrationInstance.prototype.calcGainedCharismaExp = function() {
|
||||||
if(!this.chaExpGained || isNaN(this.chaExpGained)) return 0;
|
if (!this.chaExpGained || isNaN(this.chaExpGained)) return 0;
|
||||||
return Math.pow(this.chaExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
return Math.pow(this.chaExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
|
||||||
}
|
}
|
||||||
|
|
||||||
InfiltrationInstance.prototype.gainIntelligenceExp = function(amt) {
|
InfiltrationInstance.prototype.gainIntelligenceExp = function(amt) {
|
||||||
|
@ -327,7 +327,7 @@ function displayLocationContent() {
|
|||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], networkEngineerJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], networkEngineerJob);
|
||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessCompanyPositions[0]], businessJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessCompanyPositions[0]], businessJob);
|
||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], businessConsultantJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], businessConsultantJob);
|
||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.SecurityCompanyPositions[0]], securityJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.SecurityCompanyPositions[2]], securityJob);
|
||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.AgentCompanyPositions[0]], agentJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.AgentCompanyPositions[0]], agentJob);
|
||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.MiscCompanyPositions[1]], employeeJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.MiscCompanyPositions[1]], employeeJob);
|
||||||
setJobRequirementTooltip(loc, CompanyPositions[posNames.PartTimeCompanyPositions[1]], employeePartTimeJob);
|
setJobRequirementTooltip(loc, CompanyPositions[posNames.PartTimeCompanyPositions[1]], employeePartTimeJob);
|
||||||
|
@ -196,8 +196,11 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre
|
|||||||
}
|
}
|
||||||
var runningScriptObj = new RunningScript(script, args);
|
var runningScriptObj = new RunningScript(script, args);
|
||||||
runningScriptObj.threads = threads;
|
runningScriptObj.threads = threads;
|
||||||
server.runScript(runningScriptObj, Player); // Push onto runningScripts
|
|
||||||
addWorkerScript(runningScriptObj, server);
|
addWorkerScript(runningScriptObj, server);
|
||||||
|
|
||||||
|
// Push onto runningScripts.
|
||||||
|
// This has to come after addWorkerScript() because that fn updates RAM usage
|
||||||
|
server.runScript(runningScriptObj, Player);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ export interface IPlayer {
|
|||||||
corporation: any;
|
corporation: any;
|
||||||
currentServer: string;
|
currentServer: string;
|
||||||
factions: string[];
|
factions: string[];
|
||||||
hacknetNodes: (HacknetNode | HacknetServer)[];
|
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
|
||||||
hasWseAccount: boolean;
|
hasWseAccount: boolean;
|
||||||
jobs: IMap<string>;
|
jobs: IMap<string>;
|
||||||
karma: number;
|
karma: number;
|
||||||
|
@ -114,10 +114,9 @@ export class Sleeve extends Person {
|
|||||||
logs: string[] = [];
|
logs: string[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone retains memory% of exp upon prestige. If exp would be lower than previously
|
* Clone retains 'memory' synchronization (and maybe exp?) upon prestige/installing Augs
|
||||||
* kept exp, nothing happens
|
|
||||||
*/
|
*/
|
||||||
memory: number = 0;
|
memory: number = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeve shock. Number between 0 and 100
|
* Sleeve shock. Number between 0 and 100
|
||||||
@ -339,6 +338,31 @@ export class Sleeve extends Person {
|
|||||||
p.gainMoney(gain);
|
p.gainMoney(gain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cost of upgrading this sleeve's memory by a certain amount
|
||||||
|
*/
|
||||||
|
getMemoryUpgradeCost(n: number): number {
|
||||||
|
const amt = Math.round(n);
|
||||||
|
if (amt < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.memory + amt > 100) {
|
||||||
|
return this.getMemoryUpgradeCost(100 - this.memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mult = 1.02;
|
||||||
|
const baseCost = 1e12;
|
||||||
|
let currCost = 0;
|
||||||
|
let currMemory = this.memory-1;
|
||||||
|
for (let i = 0; i < n; ++i) {
|
||||||
|
currCost += (Math.pow(mult, currMemory));
|
||||||
|
++currMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currCost * baseCost;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets reputation gain for the current task
|
* Gets reputation gain for the current task
|
||||||
* Only applicable when working for company or faction
|
* Only applicable when working for company or faction
|
||||||
@ -408,6 +432,20 @@ export class Sleeve extends Person {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on every sleeve for a Source File prestige
|
||||||
|
*/
|
||||||
|
prestige(p: IPlayer) {
|
||||||
|
this.resetTaskStatus();
|
||||||
|
this.earningsForSleeves = createTaskTracker();
|
||||||
|
this.earningsForPlayer = createTaskTracker();
|
||||||
|
this.logs = [];
|
||||||
|
this.shock = 1;
|
||||||
|
this.storedCycles = 0;
|
||||||
|
this.sync = Math.max(this.memory, 1);
|
||||||
|
this.shockRecovery(p);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process loop
|
* Process loop
|
||||||
* Returns an object containing the amount of experience that should be
|
* Returns an object containing the amount of experience that should be
|
||||||
@ -818,6 +856,15 @@ export class Sleeve extends Person {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upgradeMemory(n: number): void {
|
||||||
|
if (n < 0) {
|
||||||
|
console.warn(`Sleeve.upgradeMemory() called with negative value: ${n}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.memory = Math.min(100, Math.round(this.memory + n));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize the current object to a JSON save state.
|
* Serialize the current object to a JSON save state.
|
||||||
*/
|
*/
|
||||||
@ -830,7 +877,7 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
|
|||||||
// You can only purchase Augmentations that are actually available from
|
// You can only purchase Augmentations that are actually available from
|
||||||
// your factions. I.e. you must be in a faction that has the Augmentation
|
// your factions. I.e. you must be in a faction that has the Augmentation
|
||||||
// and you must also have enough rep in that faction in order to purchase it.
|
// and you must also have enough rep in that faction in order to purchase it.
|
||||||
|
|
||||||
const ownedAugNames: string[] = sleeve.augmentations.map((e) => {return e.name});
|
const ownedAugNames: string[] = sleeve.augmentations.map((e) => {return e.name});
|
||||||
const availableAugs: Augmentation[] = [];
|
const availableAugs: Augmentation[] = [];
|
||||||
|
|
||||||
|
@ -1,48 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* Implements the purchasing of extra Duplicate Sleeves from The Covenant
|
* Implements the purchasing of extra Duplicate Sleeves from The Covenant,
|
||||||
|
* as well as the purchasing of upgrades (memory)
|
||||||
*/
|
*/
|
||||||
import { Sleeve } from "./Sleeve";
|
|
||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { CovenantPurchasesRoot } from "./ui/CovenantPurchasesRoot";
|
||||||
|
import { createPopup,
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
removePopup } from "../../ui/React/createPopup";
|
||||||
import { yesNoBoxCreate,
|
|
||||||
yesNoBoxClose,
|
|
||||||
yesNoBoxGetYesButton,
|
|
||||||
yesNoBoxGetNoButton } from "../../../utils/YesNoBox";
|
|
||||||
|
|
||||||
export const MaxSleevesFromCovenant: number = 5;
|
export const MaxSleevesFromCovenant: number = 5;
|
||||||
|
export const BaseCostPerSleeve: number = 10e12;
|
||||||
|
export const PopupId: string = "covenant-sleeve-purchases-popup";
|
||||||
|
|
||||||
export function createPurchaseSleevesFromCovenantPopup(p: IPlayer) {
|
export function createSleevePurchasesFromCovenantPopup(p: IPlayer) {
|
||||||
if (p.sleevesFromCovenant >= MaxSleevesFromCovenant) { return; }
|
const removePopupFn = removePopup.bind(null, PopupId);
|
||||||
|
createPopup(PopupId, CovenantPurchasesRoot, { p: p, closeFn: removePopupFn });
|
||||||
// First sleeve purchased costs the base amount. Then, the price of
|
|
||||||
// each successive one increases by the same amount
|
|
||||||
const baseCostPerExtraSleeve: number = 10e12;
|
|
||||||
const cost: number = (p.sleevesFromCovenant + 1) * baseCostPerExtraSleeve;
|
|
||||||
|
|
||||||
const yesBtn = yesNoBoxGetYesButton();
|
|
||||||
const noBtn = yesNoBoxGetNoButton();
|
|
||||||
|
|
||||||
yesBtn!.addEventListener("click", () => {
|
|
||||||
if (p.canAfford(cost)) {
|
|
||||||
p.loseMoney(cost);
|
|
||||||
p.sleevesFromCovenant += 1;
|
|
||||||
p.sleeves.push(new Sleeve(p));
|
|
||||||
yesNoBoxClose();
|
|
||||||
} else {
|
|
||||||
dialogBoxCreate("You cannot afford to purchase a Duplicate Sleeve", false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
noBtn!.addEventListener("click", () => {
|
|
||||||
yesNoBoxClose();
|
|
||||||
});
|
|
||||||
|
|
||||||
const txt = `Would you like to purchase an additional Duplicate Sleeve from The Covenant for ` +
|
|
||||||
`${numeralWrapper.formatMoney(cost)}?<br><br>` +
|
|
||||||
`These Duplicate Sleeves are permanent. You can purchase a total of 5 Duplicate ` +
|
|
||||||
`Sleeves from The Covenant`;
|
|
||||||
yesNoBoxCreate(txt);
|
|
||||||
}
|
}
|
||||||
|
@ -383,7 +383,8 @@ function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
|
|||||||
`HP: ${numeralWrapper.format(sleeve.hp, "0,0")} / ${numeralWrapper.format(sleeve.max_hp, "0,0")}`,
|
`HP: ${numeralWrapper.format(sleeve.hp, "0,0")} / ${numeralWrapper.format(sleeve.max_hp, "0,0")}`,
|
||||||
`City: ${sleeve.city}`,
|
`City: ${sleeve.city}`,
|
||||||
`Shock: ${numeralWrapper.format(100 - sleeve.shock, "0,0.000")}`,
|
`Shock: ${numeralWrapper.format(100 - sleeve.shock, "0,0.000")}`,
|
||||||
`Sync: ${numeralWrapper.format(sleeve.sync, "0,0.000")}`].join("<br>");
|
`Sync: ${numeralWrapper.format(sleeve.sync, "0,0.000")}`,
|
||||||
|
`Memory: ${numeralWrapper.format(sleeve.memory, "0")}`].join("<br>");
|
||||||
|
|
||||||
let repGainText: string = "";
|
let repGainText: string = "";
|
||||||
if (sleeve.currentTask === SleeveTaskType.Company || sleeve.currentTask === SleeveTaskType.Faction) {
|
if (sleeve.currentTask === SleeveTaskType.Company || sleeve.currentTask === SleeveTaskType.Faction) {
|
||||||
|
@ -45,5 +45,13 @@ export const SleeveFaq: string =
|
|||||||
"are not available for sleeves.<br><br>",
|
"are not available for sleeves.<br><br>",
|
||||||
|
|
||||||
"<strong><u>Do sleeves get reset when installing Augmentations or switching BitNodes?</u></strong><br>",
|
"<strong><u>Do sleeves get reset when installing Augmentations or switching BitNodes?</u></strong><br>",
|
||||||
"Sleeves are reset when switching BitNodes, but not when installing Augmentations."
|
"Sleeves are reset when switching BitNodes, but not when installing Augmentations.<br><br>",
|
||||||
|
|
||||||
|
"<strong><u>What is Memory?</u></strong><br>",
|
||||||
|
"Sleeve memory dictates what a sleeve's synchronization will be",
|
||||||
|
"when its reset by switching BitNodes. For example, if a sleeve has a memory of 25,",
|
||||||
|
"then when you switch BitNodes its synchronization will initially be set to 25, rather than 1.<br><br>",
|
||||||
|
"Memory can only be increased by purchasing upgrades from The Covenant. It is a",
|
||||||
|
"persistent stat, meaning it never gets resets back to 1. The maximum possible",
|
||||||
|
"value for a sleeve's memory is 100."
|
||||||
].join(" ");
|
].join(" ");
|
||||||
|
112
src/PersonObjects/Sleeve/ui/CovenantPurchasesRoot.tsx
Normal file
112
src/PersonObjects/Sleeve/ui/CovenantPurchasesRoot.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Root React component for the popup that lets player purchase Duplicate
|
||||||
|
* Sleeves and Sleeve-related upgrades from The Covenant
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { CovenantSleeveUpgrades } from "./CovenantSleeveUpgrades";
|
||||||
|
|
||||||
|
import { Sleeve } from "../Sleeve";
|
||||||
|
import { BaseCostPerSleeve,
|
||||||
|
MaxSleevesFromCovenant,
|
||||||
|
PopupId } from "../SleeveCovenantPurchases";
|
||||||
|
import { IPlayer } from "../../IPlayer";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||||
|
|
||||||
|
import { PopupCloseButton } from "../../../ui/React/PopupCloseButton";
|
||||||
|
import { StdButton } from "../../../ui/React/StdButton";
|
||||||
|
|
||||||
|
import { dialogBoxCreate } from "../../../../utils/DialogBox";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
closeFn: () => void;
|
||||||
|
p: IPlayer;
|
||||||
|
rerender: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
update: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CovenantPurchasesRoot extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
update: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rerender = this.rerender.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cost to purchase a new Duplicate Sleeve
|
||||||
|
*/
|
||||||
|
purchaseCost(): number {
|
||||||
|
return (this.props.p.sleevesFromCovenant + 1) * BaseCostPerSleeve;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force a rerender by just changing an arbitrary state value
|
||||||
|
*/
|
||||||
|
rerender() {
|
||||||
|
this.setState((state: IState) => ({
|
||||||
|
update: state.update + 1,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// Purchasing a new Duplicate Sleeve
|
||||||
|
let purchaseDisabled = false;
|
||||||
|
if (!this.props.p.canAfford(this.purchaseCost())) {
|
||||||
|
purchaseDisabled = true;
|
||||||
|
}
|
||||||
|
if (this.props.p.sleevesFromCovenant >= MaxSleevesFromCovenant) {
|
||||||
|
purchaseDisabled = true;
|
||||||
|
}
|
||||||
|
const purchaseOnClick = () => {
|
||||||
|
if (this.props.p.sleevesFromCovenant >= MaxSleevesFromCovenant) { return; }
|
||||||
|
|
||||||
|
if (this.props.p.canAfford(this.purchaseCost())) {
|
||||||
|
this.props.p.loseMoney(this.purchaseCost());
|
||||||
|
this.props.p.sleevesFromCovenant += 1;
|
||||||
|
this.props.p.sleeves.push(new Sleeve(this.props.p));
|
||||||
|
this.rerender();
|
||||||
|
} else {
|
||||||
|
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purchasing Upgrades for Sleeves
|
||||||
|
const upgradePanels = [];
|
||||||
|
for (let i = 0; i < this.props.p.sleeves.length; ++i) {
|
||||||
|
const sleeve = this.props.p.sleeves[i];
|
||||||
|
upgradePanels.push(
|
||||||
|
<CovenantSleeveUpgrades {...this.props} sleeve={sleeve} index={i} rerender={this.rerender} key={i} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<PopupCloseButton popup={PopupId} text={"Close"} />
|
||||||
|
<p>
|
||||||
|
Would you like to purchase an additional Duplicate Sleeve from The Covenant
|
||||||
|
for {numeralWrapper.formatMoney(this.purchaseCost())}?
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
These Duplicate Sleeves are permanent (they persist through BitNodes). You can
|
||||||
|
purchase a total of {MaxSleevesFromCovenant} from The Covenant.
|
||||||
|
</p>
|
||||||
|
<StdButton disabled={purchaseDisabled} onClick={purchaseOnClick} text={"Purchase"} />
|
||||||
|
<br /><br />
|
||||||
|
<p>
|
||||||
|
Here, you can also purchase upgrades for your Duplicate Sleeves. These upgrades
|
||||||
|
are also permanent, meaning they persist across BitNodes.
|
||||||
|
</p>
|
||||||
|
{upgradePanels}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
97
src/PersonObjects/Sleeve/ui/CovenantSleeveMemoryUpgrade.tsx
Normal file
97
src/PersonObjects/Sleeve/ui/CovenantSleeveMemoryUpgrade.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* React component for a panel that lets you purchase upgrades for a Duplicate
|
||||||
|
* Sleeve's Memory (through The Covenant)
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { Sleeve } from "../Sleeve";
|
||||||
|
import { IPlayer } from "../../IPlayer";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||||
|
import { StdButton } from "../../../ui/React/StdButton";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
index: number;
|
||||||
|
p: IPlayer;
|
||||||
|
rerender: () => void;
|
||||||
|
sleeve: Sleeve;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
amt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
amt: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changePurchaseAmount = this.changePurchaseAmount.bind(this);
|
||||||
|
this.purchaseMemory = this.purchaseMemory.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
const n: number = parseInt(e.target.value);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
amt: n,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getPurchaseCost(): number {
|
||||||
|
if (isNaN(this.state.amt)) { return Infinity; }
|
||||||
|
|
||||||
|
const maxMemory = 100 - this.props.sleeve.memory;
|
||||||
|
if (this.state.amt > maxMemory) { return Infinity; }
|
||||||
|
|
||||||
|
return this.props.sleeve.getMemoryUpgradeCost(this.state.amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
purchaseMemory(): void {
|
||||||
|
const cost = this.getPurchaseCost();
|
||||||
|
if (this.props.p.canAfford(cost)) {
|
||||||
|
this.props.sleeve.upgradeMemory(this.state.amt);
|
||||||
|
this.props.p.loseMoney(cost);
|
||||||
|
this.props.rerender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const inputId = `sleeve-${this.props.index}-memory-upgrade-input`;
|
||||||
|
|
||||||
|
// Memory cannot go above 100
|
||||||
|
const maxMemory = 100 - this.props.sleeve.memory;
|
||||||
|
|
||||||
|
// Purchase button props
|
||||||
|
const cost = this.getPurchaseCost();
|
||||||
|
const purchaseBtnDisabled = !this.props.p.canAfford(cost);
|
||||||
|
let purchaseBtnText;
|
||||||
|
if (this.state.amt > maxMemory) {
|
||||||
|
purchaseBtnText = `Memory cannot exceed 100`;
|
||||||
|
} else if (isNaN(this.state.amt)) {
|
||||||
|
purchaseBtnText = "Invalid value";
|
||||||
|
} else {
|
||||||
|
purchaseBtnText = `Purchase ${this.state.amt} memory - ${numeralWrapper.formatMoney(cost)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2><u>Upgrade Memory</u></h2>
|
||||||
|
<p>
|
||||||
|
Purchase a memory upgrade for your sleeve. Note that a sleeve's max memory
|
||||||
|
is 100 (current: {numeralWrapper.format(this.props.sleeve.memory, "0")})
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<label htmlFor={inputId}>
|
||||||
|
Amount of memory to purchase (must be an integer):
|
||||||
|
</label>
|
||||||
|
<input id={inputId} onChange={this.changePurchaseAmount} type={"number"} value={this.state.amt} />
|
||||||
|
<br />
|
||||||
|
<StdButton disabled={purchaseBtnDisabled} onClick={this.purchaseMemory} text={purchaseBtnText} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
28
src/PersonObjects/Sleeve/ui/CovenantSleeveUpgrades.tsx
Normal file
28
src/PersonObjects/Sleeve/ui/CovenantSleeveUpgrades.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* React Component for a panel that lets you purchase upgrades for a single
|
||||||
|
* Duplicate Sleeve through The Covenant
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { CovenantSleeveMemoryUpgrade } from "./CovenantSleeveMemoryUpgrade";
|
||||||
|
|
||||||
|
import { Sleeve } from "../Sleeve";
|
||||||
|
import { IPlayer } from "../../IPlayer";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
index: number;
|
||||||
|
p: IPlayer;
|
||||||
|
rerender: () => void;
|
||||||
|
sleeve: Sleeve;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CovenantSleeveUpgrades extends React.Component<IProps, any> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={"bladeburner-action"}>
|
||||||
|
<h1>Duplicate Sleeve {this.props.index}</h1>
|
||||||
|
<CovenantSleeveMemoryUpgrade {...this.props} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ 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 {Gang, resetGangs} from "./Gang";
|
||||||
|
import { hasHacknetServers } from "./Hacknet/HacknetHelpers";
|
||||||
import { HashManager } from "./Hacknet/HashManager";
|
import { HashManager } from "./Hacknet/HashManager";
|
||||||
import {Locations} from "./Locations";
|
import {Locations} from "./Locations";
|
||||||
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
|
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
|
||||||
@ -117,7 +118,7 @@ function PlayerObject() {
|
|||||||
this.purchasedServers = []; //IP Addresses of purchased servers
|
this.purchasedServers = []; //IP Addresses of purchased servers
|
||||||
|
|
||||||
// Hacknet Nodes/Servers
|
// Hacknet Nodes/Servers
|
||||||
this.hacknetNodes = [];
|
this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers
|
||||||
this.hashManager = new HashManager();
|
this.hashManager = new HashManager();
|
||||||
|
|
||||||
//Factions
|
//Factions
|
||||||
@ -288,7 +289,7 @@ PlayerObject.prototype.prestigeAugmentation = function() {
|
|||||||
for (let i = 0; i < this.sleeves.length; ++i) {
|
for (let i = 0; i < this.sleeves.length; ++i) {
|
||||||
if (this.sleeves[i] instanceof Sleeve) {
|
if (this.sleeves[i] instanceof Sleeve) {
|
||||||
if (this.sleeves[i].shock >= 100) {
|
if (this.sleeves[i].shock >= 100) {
|
||||||
this.sleeves[i].synchronize(this);
|
this.sleeves[i].synchronize(this);
|
||||||
} else {
|
} else {
|
||||||
this.sleeves[i].shockRecovery(this);
|
this.sleeves[i].shockRecovery(this);
|
||||||
}
|
}
|
||||||
@ -382,7 +383,11 @@ PlayerObject.prototype.prestigeSourceFile = function() {
|
|||||||
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
|
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
|
||||||
this.sleeves.length = SourceFileFlags[10] + this.sleevesFromCovenant;
|
this.sleeves.length = SourceFileFlags[10] + this.sleevesFromCovenant;
|
||||||
for (let i = 0; i < this.sleeves.length; ++i) {
|
for (let i = 0; i < this.sleeves.length; ++i) {
|
||||||
this.sleeves[i] = new Sleeve(this);
|
if (this.sleeves[i] instanceof Sleeve) {
|
||||||
|
this.sleeves[i].prestige(this);
|
||||||
|
} else {
|
||||||
|
this.sleeves[i] = new Sleeve(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isWorking = false;
|
this.isWorking = false;
|
||||||
@ -2333,10 +2338,19 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
var totalHacknetRam = 0;
|
var totalHacknetRam = 0;
|
||||||
var totalHacknetCores = 0;
|
var totalHacknetCores = 0;
|
||||||
var totalHacknetLevels = 0;
|
var totalHacknetLevels = 0;
|
||||||
for (var i = 0; i < this.hacknetNodes.length; ++i) {
|
for (let i = 0; i < this.hacknetNodes.length; ++i) {
|
||||||
totalHacknetLevels += this.hacknetNodes[i].level;
|
if (hasHacknetServers()) {
|
||||||
totalHacknetRam += this.hacknetNodes[i].ram;
|
const hserver = AllServers[this.hacknetNodes[i]];
|
||||||
totalHacknetCores += this.hacknetNodes[i].cores;
|
if (hserver) {
|
||||||
|
totalHacknetLevels += hserver.level;
|
||||||
|
totalHacknetRam += hserver.maxRam;
|
||||||
|
totalHacknetCores += hserver.cores;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
totalHacknetLevels += this.hacknetNodes[i].level;
|
||||||
|
totalHacknetRam += this.hacknetNodes[i].ram;
|
||||||
|
totalHacknetCores += this.hacknetNodes[i].cores;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited &&
|
if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited &&
|
||||||
this.hacking_skill >= 80 && totalHacknetRam >= 8 &&
|
this.hacking_skill >= 80 && totalHacknetRam >= 8 &&
|
||||||
|
@ -2,6 +2,8 @@ import { Server } from "./Server";
|
|||||||
import { SpecialServerIps } from "./SpecialServerIps";
|
import { SpecialServerIps } from "./SpecialServerIps";
|
||||||
import { serverMetadata } from "./data/servers";
|
import { serverMetadata } from "./data/servers";
|
||||||
|
|
||||||
|
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||||
|
|
||||||
import { IMap } from "../types";
|
import { IMap } from "../types";
|
||||||
import { createRandomIp,
|
import { createRandomIp,
|
||||||
ipExists } from "../../utils/IPAddress";
|
ipExists } from "../../utils/IPAddress";
|
||||||
@ -11,7 +13,7 @@ import { Reviver } from "../../utils/JSONReviver";
|
|||||||
// Map of all Servers that exist in the game
|
// Map of all Servers that exist in the game
|
||||||
// Key (string) = IP
|
// Key (string) = IP
|
||||||
// Value = Server object
|
// Value = Server object
|
||||||
export let AllServers: IMap<Server> = {};
|
export let AllServers: IMap<Server | HacknetServer> = {};
|
||||||
|
|
||||||
// Saftely add a Server to the AllServers map
|
// Saftely add a Server to the AllServers map
|
||||||
export function AddToAllServers(server: Server): void {
|
export function AddToAllServers(server: Server): void {
|
||||||
|
@ -3,6 +3,7 @@ import { Server } from "./Server";
|
|||||||
|
|
||||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { Programs } from "../Programs/Programs";
|
import { Programs } from "../Programs/Programs";
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ export function prestigeHomeComputer(homeComp: Server) {
|
|||||||
|
|
||||||
//Returns server object with corresponding hostname
|
//Returns server object with corresponding hostname
|
||||||
// Relatively slow, would rather not use this a lot
|
// Relatively slow, would rather not use this a lot
|
||||||
export function GetServerByHostname(hostname: string): Server | null {
|
export function GetServerByHostname(hostname: string): Server | HacknetServer | null {
|
||||||
for (var ip in AllServers) {
|
for (var ip in AllServers) {
|
||||||
if (AllServers.hasOwnProperty(ip)) {
|
if (AllServers.hasOwnProperty(ip)) {
|
||||||
if (AllServers[ip].hostname == hostname) {
|
if (AllServers[ip].hostname == hostname) {
|
||||||
@ -102,7 +103,7 @@ export function GetServerByHostname(hostname: string): Server | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Get server by IP or hostname. Returns null if invalid
|
//Get server by IP or hostname. Returns null if invalid
|
||||||
export function getServer(s: string): Server | null {
|
export function getServer(s: string): Server | HacknetServer | null {
|
||||||
if (!isValidIPAddress(s)) {
|
if (!isValidIPAddress(s)) {
|
||||||
return GetServerByHostname(s);
|
return GetServerByHostname(s);
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,9 @@ function initSourceFiles() {
|
|||||||
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " +
|
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " +
|
||||||
"at that company by 1% per favor (rather than just the reputation gain). This Source-File also " +
|
"at that company by 1% per favor (rather than just the reputation gain). This Source-File also " +
|
||||||
" increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
" increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
||||||
"Level 1: 24%<br>" +
|
"Level 1: 32%<br>" +
|
||||||
"Level 2: 36%<br>" +
|
"Level 2: 48%<br>" +
|
||||||
"Level 3: 42%<br>");
|
"Level 3: 56%<br>");
|
||||||
SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File increases all your multipliers by 1% per level. This effect is multiplicative with itself. " +
|
SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File increases all your multipliers by 1% per level. This effect is multiplicative with itself. " +
|
||||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ function applySourceFile(srcFile) {
|
|||||||
case 11: //The Big Crash
|
case 11: //The Big Crash
|
||||||
var mult = 0;
|
var mult = 0;
|
||||||
for (var i = 0; i < srcFile.lvl; ++i) {
|
for (var i = 0; i < srcFile.lvl; ++i) {
|
||||||
mult += (24 / (Math.pow(2, i)));
|
mult += (32 / (Math.pow(2, i)));
|
||||||
}
|
}
|
||||||
var incMult = 1 + (mult / 100);
|
var incMult = 1 + (mult / 100);
|
||||||
Player.work_money_mult *= incMult;
|
Player.work_money_mult *= incMult;
|
||||||
|
@ -462,9 +462,10 @@ function sellStock(stock, shares) {
|
|||||||
shares = Math.round(shares);
|
shares = Math.round(shares);
|
||||||
if (shares > stock.playerShares) {shares = stock.playerShares;}
|
if (shares > stock.playerShares) {shares = stock.playerShares;}
|
||||||
if (shares === 0) {return false;}
|
if (shares === 0) {return false;}
|
||||||
var gains = stock.price * shares - CONSTANTS.StockMarketCommission;
|
const gains = stock.price * shares - CONSTANTS.StockMarketCommission;
|
||||||
|
const netProfit = ((stock.price - stock.playerAvgPx) * shares) - CONSTANTS.StockMarketCommission;
|
||||||
Player.gainMoney(gains);
|
Player.gainMoney(gains);
|
||||||
Player.recordMoneySource(gains, "stock");
|
Player.recordMoneySource(netProfit, "stock");
|
||||||
stock.playerShares = Math.round(stock.playerShares - shares);
|
stock.playerShares = Math.round(stock.playerShares - shares);
|
||||||
if (stock.playerShares == 0) {
|
if (stock.playerShares == 0) {
|
||||||
stock.playerAvgPx = 0;
|
stock.playerAvgPx = 0;
|
||||||
|
@ -1861,17 +1861,20 @@ let Terminal = {
|
|||||||
visited[ip] = 0;
|
visited[ip] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var stack = [];
|
const stack = [];
|
||||||
var depthQueue = [0];
|
const depthQueue = [0];
|
||||||
var currServ = Player.getCurrentServer();
|
const currServ = Player.getCurrentServer();
|
||||||
stack.push(currServ);
|
stack.push(currServ);
|
||||||
while(stack.length != 0) {
|
while(stack.length != 0) {
|
||||||
var s = stack.pop();
|
const s = stack.pop();
|
||||||
var d = depthQueue.pop();
|
const d = depthQueue.pop();
|
||||||
|
const isHacknet = s instanceof HacknetServer;
|
||||||
if (!all && s.purchasedByPlayer && s.hostname != "home") {
|
if (!all && s.purchasedByPlayer && s.hostname != "home") {
|
||||||
continue; //Purchased server
|
continue; // Purchased server
|
||||||
} else if (visited[s.ip] || d > depth) {
|
} else if (visited[s.ip] || d > depth) {
|
||||||
continue; //Already visited or out-of-depth
|
continue; // Already visited or out-of-depth
|
||||||
|
} else if (!all && isHacknet) {
|
||||||
|
continue; // Hacknet Server
|
||||||
} else {
|
} else {
|
||||||
visited[s.ip] = 1;
|
visited[s.ip] = 1;
|
||||||
}
|
}
|
||||||
@ -1891,8 +1894,8 @@ let Terminal = {
|
|||||||
//var dashes = Array(d * 2 + 1).join("-");
|
//var dashes = Array(d * 2 + 1).join("-");
|
||||||
var c = "NO";
|
var c = "NO";
|
||||||
if (s.hasAdminRights) {c = "YES";}
|
if (s.hasAdminRights) {c = "YES";}
|
||||||
post(dashes + "Root Access: " + c + ", Required hacking skill: " + s.requiredHackingSkill);
|
post(`${dashes}Root Access: ${c} ${!isHacknet ? ", Required hacking skill: " + s.requiredHackingSkill : ""}`);
|
||||||
post(dashes + "Number of open ports required to NUKE: " + s.numOpenPortsRequired);
|
if (!isHacknet) { post(dashes + "Number of open ports required to NUKE: " + s.numOpenPortsRequired); }
|
||||||
post(dashes + "RAM: " + s.maxRam);
|
post(dashes + "RAM: " + s.maxRam);
|
||||||
post(" ");
|
post(" ");
|
||||||
}
|
}
|
||||||
@ -2242,9 +2245,12 @@ let Terminal = {
|
|||||||
post("May take a few seconds to start up the process...");
|
post("May take a few seconds to start up the process...");
|
||||||
var runningScriptObj = new RunningScript(script, args);
|
var runningScriptObj = new RunningScript(script, args);
|
||||||
runningScriptObj.threads = numThreads;
|
runningScriptObj.threads = numThreads;
|
||||||
server.runScript(runningScriptObj, Player);
|
|
||||||
|
|
||||||
addWorkerScript(runningScriptObj, server);
|
addWorkerScript(runningScriptObj, server);
|
||||||
|
|
||||||
|
// This has to come after addWorkerScript() because that fn
|
||||||
|
// updates the RAM usage. This kinda sucks, address if possible
|
||||||
|
server.runScript(runningScriptObj, Player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
src/ui/React/Popup.tsx
Normal file
24
src/ui/React/Popup.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* React component for a popup content container
|
||||||
|
*
|
||||||
|
* Takes in a prop for rendering the content inside the popup
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
type ReactComponent = new(...args: any[]) => React.Component<any, any>
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
content: ReactComponent;
|
||||||
|
id: string;
|
||||||
|
props: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Popup extends React.Component<IProps, any> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={"popup-box-content"} id={`${this.props.id}-content`}>
|
||||||
|
{React.createElement(this.props.content, this.props.props)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import * as React from "react";
|
|||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||||
|
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||||
|
|
||||||
export interface IPopupCloseButtonProps {
|
export interface IPopupCloseButtonProps {
|
||||||
class?: string;
|
class?: string;
|
||||||
@ -43,7 +44,8 @@ export class PopupCloseButton extends React.Component<IPopupCloseButtonProps, an
|
|||||||
|
|
||||||
// TODO Check if this is okay? This is essentially calling to unmount a parent component
|
// TODO Check if this is okay? This is essentially calling to unmount a parent component
|
||||||
if (popup instanceof HTMLElement) {
|
if (popup instanceof HTMLElement) {
|
||||||
ReactDOM.unmountComponentAtNode(popup);
|
ReactDOM.unmountComponentAtNode(popup); // Removes everything inside the wrapper container
|
||||||
|
removeElement(popup); // Removes the wrapper container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ export class PopupCloseButton extends React.Component<IPopupCloseButtonProps, an
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={className} onClick={this.closePopup} style={this.props.style}>
|
<button className={className} onClick={this.closePopup} style={this.props.style}>
|
||||||
{this.props.text};
|
{this.props.text}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ export class StdButton extends React.Component<IStdButtonProps, any> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={className} onClick={this.props.onClick} style={this.props.style}>
|
<button className={className} onClick={this.props.onClick} style={this.props.style}>
|
||||||
{this.props.text};
|
{this.props.text}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,41 +4,45 @@
|
|||||||
* Calling this function with the same ID and React Root Component will trigger a re-render
|
* Calling this function with the same ID and React Root Component will trigger a re-render
|
||||||
*
|
*
|
||||||
* @param id The (hopefully) unique identifier for the popup container
|
* @param id The (hopefully) unique identifier for the popup container
|
||||||
* @param rootComponent Root React Component
|
* @param rootComponent Root React Component for the content (NOT the popup containers themselves)
|
||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
|
import { Popup } from "./Popup";
|
||||||
|
|
||||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
||||||
|
|
||||||
type ReactComponent = new(...args: any[]) => React.Component<any, any>;
|
type ReactComponent = new(...args: any[]) => React.Component<any, any>;
|
||||||
|
|
||||||
export function createPopup(id: string, rootComponent: ReactComponent, props: object): HTMLElement {
|
let gameContainer: HTMLElement;
|
||||||
|
|
||||||
|
function getGameContainer() {
|
||||||
|
let container = document.getElementById("entire-game-container");
|
||||||
|
if (container == null) {
|
||||||
|
throw new Error(`Failed to find game container DOM element`)
|
||||||
|
}
|
||||||
|
|
||||||
|
gameContainer = container;
|
||||||
|
document.removeEventListener("DOMContentLoaded", getGameContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", getGameContainer);
|
||||||
|
|
||||||
|
export function createPopup(id: string, rootComponent: ReactComponent, props: object): HTMLElement | null {
|
||||||
let container = document.getElementById(id);
|
let container = document.getElementById(id);
|
||||||
let content = document.getElementById(`${id}-content`);
|
if (container == null) {
|
||||||
if (container == null || content == null) {
|
|
||||||
container = createElement("div", {
|
container = createElement("div", {
|
||||||
class: "popup-box-container",
|
class: "popup-box-container",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
id: id,
|
id: id,
|
||||||
});
|
});
|
||||||
|
|
||||||
content = createElement("div", {
|
gameContainer.appendChild(container);
|
||||||
class: "popup-box-content",
|
|
||||||
id: `${id}-content`,
|
|
||||||
});
|
|
||||||
|
|
||||||
container.appendChild(content);
|
|
||||||
|
|
||||||
try {
|
|
||||||
document.getElementById("entire-game-container")!.appendChild(container);
|
|
||||||
} catch(e) {
|
|
||||||
console.error(`Exception caught when creating popup: ${e}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render(React.createElement(rootComponent, props), content);
|
ReactDOM.render(<Popup content={rootComponent} id={id} props={props} />, container);
|
||||||
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
@ -47,7 +51,7 @@ export function createPopup(id: string, rootComponent: ReactComponent, props: ob
|
|||||||
* Closes a popup created with the createPopup() function above
|
* Closes a popup created with the createPopup() function above
|
||||||
*/
|
*/
|
||||||
export function removePopup(id: string): void {
|
export function removePopup(id: string): void {
|
||||||
let content = document.getElementById(`${id}-content`);
|
let content = document.getElementById(`${id}`);
|
||||||
if (content == null) { return; }
|
if (content == null) { return; }
|
||||||
|
|
||||||
ReactDOM.unmountComponentAtNode(content);
|
ReactDOM.unmountComponentAtNode(content);
|
Loading…
Reference in New Issue
Block a user