This commit is contained in:
danielyxie 2018-10-26 22:20:30 -05:00
commit 1ec376733f
40 changed files with 170581 additions and 1213 deletions

@ -22,6 +22,9 @@ heard:
The recommended method for reporting a bug is by opening a The recommended method for reporting a bug is by opening a
[Github Issue](https://github.com/danielyxie/bitburner/issues). [Github Issue](https://github.com/danielyxie/bitburner/issues).
Alternatively, you can post a bug by creating a post on the
[game's subreddit](https://www.reddit.com/r/Bitburner/).
Before submitting a bug report, please check to make sure the bug has not Before submitting a bug report, please check to make sure the bug has not
already been reported as an [Issue](https://github.com/danielyxie/bitburner/issues). already been reported as an [Issue](https://github.com/danielyxie/bitburner/issues).
@ -29,6 +32,7 @@ already been reported as an [Issue](https://github.com/danielyxie/bitburner/issu
* **Use a clear and descriptive title** for the issue * **Use a clear and descriptive title** for the issue
* **State your browser, your browser's version, and your computer's OS** * **State your browser, your browser's version, and your computer's OS**
* **Attach your save file**, if you think it would help solve the issue
* **Provide instructions on how to reproduce the bug** in as much detail * **Provide instructions on how to reproduce the bug** in as much detail
as possible. If you cannot reliably reproduce the bug, then just try as possible. If you cannot reliably reproduce the bug, then just try
your best to explain what was happening when the bug occurred your best to explain what was happening when the bug occurred

@ -82,3 +82,27 @@ button {
pointer-events: none; pointer-events: none;
} }
} }
/**
* This is a button that is meant to be used on accordions (accordion-header and accordion-panel classes)
* It has a black background so it does not clash with the default accordion coloring
*/
.accordion-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
&:hover,
&:active {
color: #fff;
text-decoration: none;
cursor: pointer;
}
/* TODO focus selector? */
}

48
css/gang.scss Normal file

@ -0,0 +1,48 @@
@import "mixins";
@import "theme";
/**
* Styling for the Gang mechanic UI (BitNode-2)
*/
#gang-container {
position: fixed;
padding: 6px;
p, pre {
font-size: $defaultFontSize * 0.9375;
}
select {
background-color: black;
color: white;
}
}
#gang-management-subpage > p {
padding: 4px;
}
.gang-member-info-div {
background-color: #555;
display: inline;
float: left;
width: 30%;
}
/**
* Showing owned upgrades in the Equipment Box
*/
.gang-owned-upgrades-div {
display: inline-block;
margin-left: 6px;
width: 75%;
}
.gang-owned-upgrade {
border: 1px solid white;
font-size: 12px;
margin: 1px;
padding: 1px;
}

@ -248,25 +248,6 @@
} }
} }
.active-scripts-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
&:hover,
&:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
}
/* Hacknet Nodes */ /* Hacknet Nodes */
#hacknet-nodes-container { #hacknet-nodes-container {
position: fixed; position: fixed;
@ -623,18 +604,3 @@
margin: 2px; margin: 2px;
padding: 0; padding: 0;
} }
/* Gang */
#gang-container {
position: fixed;
padding: 6px;
}
#gang-management-subpage > p {
padding: 4px;
}
.gang-member-info-div {
float: left;
background-color: #555;
}

@ -114,6 +114,29 @@ a:visited {
position: absolute; position: absolute;
z-index: 99; z-index: 99;
} }
/* Positioned to left of element rather than right */
.tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99;
}
} }
/* Same thing as a normal tooltip except its a bit higher */ /* Same thing as a normal tooltip except its a bit higher */
@ -132,23 +155,6 @@ a:visited {
z-index: 99; z-index: 99;
} }
/* Similar to a normal tooltip except its positioned on the left of the element
rather than the right to avoid exceeding the elements normal width */
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 40%;
bottom: -10%;
position: absolute;
z-index: 99;
}
.tooltip:hover .tooltiptext, .tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh, .tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft { .tooltip:hover .tooltiptextleft {
@ -157,13 +163,14 @@ a:visited {
/* help tip. Question mark that opens popup with info/details */ /* help tip. Question mark that opens popup with info/details */
.help-tip { .help-tip {
content: '?'; background-color: black;
padding: 1px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff; border: 1px solid #fff;
border-radius: 5px; border-radius: 5px;
color: #fff;
content: '?';
display: inline-block; display: inline-block;
margin-left: 3px;
padding: 1px;
} }
.help-tip-big { .help-tip-big {
@ -412,7 +419,7 @@ a:visited {
&:after { &:after {
content: '\02795'; /* "plus" sign (+) */ content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125; font-size: $defaultFontSize * 0.875;
float: right; float: right;
color: transparent; color: transparent;
text-shadow: 0 0 0 #fff; text-shadow: 0 0 0 #fff;
@ -479,3 +486,7 @@ a:visited {
.charisma-purple { .charisma-purple {
color: $my-stat-cha-color; color: $my-stat-cha-color;
} }
.smallfont {
font-size: $defaultFontSize * 0.8125;
}

56961
dist/engine.bundle.js vendored

File diff suppressed because one or more lines are too long

142
dist/engine.css vendored

@ -94,7 +94,8 @@ a:visited {
/* Tool tips (when hovering over an element */ /* Tool tips (when hovering over an element */
.tooltip { .tooltip {
display: inline-block; display: inline-block;
position: relative; } position: relative;
/* Positioned to left of element rather than right */ }
.tooltip .tooltiptext { .tooltip .tooltiptext {
visibility: hidden; visibility: hidden;
width: 300px; width: 300px;
@ -107,6 +108,24 @@ a:visited {
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
z-index: 99; } z-index: 99; }
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99; }
/* Same thing as a normal tooltip except its a bit higher */ /* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh { .tooltip .tooltiptexthigh {
@ -122,21 +141,6 @@ a:visited {
position: absolute; position: absolute;
z-index: 99; } z-index: 99; }
/* Similar to a normal tooltip except its positioned on the left of the element
rather than the right to avoid exceeding the elements normal width */
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 40%;
bottom: -10%;
position: absolute;
z-index: 99; }
.tooltip:hover .tooltiptext, .tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh, .tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft { .tooltip:hover .tooltiptextleft {
@ -144,13 +148,14 @@ a:visited {
/* help tip. Question mark that opens popup with info/details */ /* help tip. Question mark that opens popup with info/details */
.help-tip { .help-tip {
content: '?'; background-color: black;
padding: 1px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff; border: 1px solid #fff;
border-radius: 5px; border-radius: 5px;
display: inline-block; } color: #fff;
content: '?';
display: inline-block;
margin-left: 3px;
padding: 1px; }
.help-tip-big { .help-tip-big {
content: '?'; content: '?';
@ -418,7 +423,7 @@ a:visited {
.accordion-header:after { .accordion-header:after {
content: '\2795'; content: '\2795';
/* "plus" sign (+) */ /* "plus" sign (+) */
font-size: 13px; font-size: 14px;
float: right; float: right;
color: transparent; color: transparent;
text-shadow: 0 0 0 #fff; text-shadow: 0 0 0 #fff;
@ -472,6 +477,9 @@ a:visited {
.charisma-purple { .charisma-purple {
color: #a671d1; } color: #a671d1; }
.smallfont {
font-size: 13px; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/** /**
@ -546,6 +554,29 @@ button {
.std-button-bought:active { .std-button-bought:active {
pointer-events: none; } pointer-events: none; }
/**
* This is a button that is meant to be used on accordions (accordion-header and accordion-panel classes)
* It has a black background so it does not clash with the default accordion coloring
*/
.accordion-button {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: 1px 1px 3px #000;
-moz-box-shadow: 1px 1px 3px #000;
box-shadow: 1px 1px 3px #000;
color: #aaa;
font-size: 16px;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
/* TODO focus selector? */ }
.accordion-button:hover, .accordion-button:active {
color: #fff;
text-decoration: none;
cursor: pointer; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/** /**
@ -921,24 +952,6 @@ button {
color: #fff; color: #fff;
margin-left: 5%; } margin-left: 5%; }
.active-scripts-button {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: 1px 1px 3px #000;
-moz-box-shadow: 1px 1px 3px #000;
box-shadow: 1px 1px 3px #000;
color: #aaa;
font-size: 16px;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000; }
.active-scripts-button:hover, .active-scripts-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer; }
/* Hacknet Nodes */ /* Hacknet Nodes */
#hacknet-nodes-container { #hacknet-nodes-container {
position: fixed; position: fixed;
@ -1227,18 +1240,6 @@ button {
margin: 2px; margin: 2px;
padding: 0; } padding: 0; }
/* Gang */
#gang-container {
position: fixed;
padding: 6px; }
#gang-management-subpage > p {
padding: 4px; }
.gang-member-info-div {
float: left;
background-color: #555; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/* Both Work in progress and BitNode stuff */ /* Both Work in progress and BitNode stuff */
@ -2040,5 +2041,42 @@ button {
-webkit-hyphens: auto; -webkit-hyphens: auto;
-moz-hyphens: auto; } -moz-hyphens: auto; }
/* COLORS */
/* Attributes */
/**
* Styling for the Gang mechanic UI (BitNode-2)
*/
#gang-container {
position: fixed;
padding: 6px; }
#gang-container p, #gang-container pre {
font-size: 15px; }
#gang-container select {
background-color: black;
color: white; }
#gang-management-subpage > p {
padding: 4px; }
.gang-member-info-div {
background-color: #555;
display: inline;
float: left;
width: 30%; }
/**
* Showing owned upgrades in the Equipment Box
*/
.gang-owned-upgrades-div {
display: inline-block;
margin-left: 6px;
width: 75%; }
.gang-owned-upgrade {
border: 1px solid white;
font-size: 12px;
margin: 1px;
padding: 1px; }
/*# sourceMappingURL=engine.css.map*/ /*# sourceMappingURL=engine.css.map*/

111050
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

26
doc/source/gamefrozen.rst Normal file

@ -0,0 +1,26 @@
Game Frozen or Stuck?
=====================
Infinite Loop in NetscriptJS
----------------------------
If your game is frozen or stuck in any way, then the most likely culprit is an
infinitely running loop in :ref:`netscriptjs`. To get past the freezing, run the game with
`?noScripts` in the URL:
`https://danielyxie.github.io/bitburner/?noScripts <https://danielyxie.github.io/bitburner/?noScripts>`_
Then, to fix your script, make sure you have a sleep or any other timed function like `hack()` or
`grow()` in any infinite loops::
while(true) {
// This is an infinite loop that does something
...
await ns.sleep(1000); // Add a 1s sleep to prevent freezing
}
Bug
---
Otherwise, the game is probably frozen/stuck due to a bug. To report a bug, follow
the guidelines `here <https://github.com/danielyxie/bitburner/blob/master/CONTRIBUTING.md#reporting-bugs>`_.

@ -23,9 +23,9 @@ secrets that you've been searching for.
Terminal <terminal> Terminal <terminal>
Coding Contracts <codingcontracts> Coding Contracts <codingcontracts>
Keyboard Shortcuts <shortcuts> Keyboard Shortcuts <shortcuts>
Game Frozen or Stuck? <gamefrozen>
Changelog <changelog> Changelog <changelog>
Indices and tables Indices and tables
================== ==================

@ -25,5 +25,6 @@ to reach out to the developer!
Trade Information eXchange (TIX) API <netscriptixapi> Trade Information eXchange (TIX) API <netscriptixapi>
Singularity Functions <netscriptsingularityfunctions> Singularity Functions <netscriptsingularityfunctions>
Bladeburner API <netscriptbladeburnerapi> Bladeburner API <netscriptbladeburnerapi>
Gang API <netscriptgangapi>
Coding Contract API <netscriptcodingcontractapi> Coding Contract API <netscriptcodingcontractapi>
Miscellaneous <netscriptmisc> Miscellaneous <netscriptmisc>

@ -509,7 +509,7 @@ getHackingMultipliers
:RAM cost: 4 GB :RAM cost: 4 GB
Returns an object containing the Player's hacking related multipliers. These multipliers are Returns an object containing the Player's hacking related multipliers. These multipliers are
returned in fractional forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure:: returned in decimal forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure::
{ {
chance: Player's hacking chance multiplier, chance: Player's hacking chance multiplier,
@ -532,7 +532,7 @@ getHacknetMultipliers
:RAM cost: 4 GB :RAM cost: 4 GB
Returns an object containing the Player's hacknet related multipliers. These multipliers are Returns an object containing the Player's hacknet related multipliers. These multipliers are
returned in fractional forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure:: returned in decimal forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure::
{ {
production: Player's hacknet production multiplier, production: Player's hacknet production multiplier,

@ -0,0 +1,249 @@
Netscript Gang API
==================
Netscript provides the following API for interacting with the game's Gang mechanic.
The Gang API is **not** immediately available to the player and must be unlocked
later in the game
**WARNING: This page contains spoilers for the game**
The Gang API is unlocked in BitNode-2. Currently, BitNode-2 is the only location
where the Gang mechanic is accessible. This may change in the future
**Gang API functions must be accessed through the 'gang' namespace**
In :ref:`netscript1`::
gang.getMemberNames();
gang.recruitMember("Fry");
In :ref:`netscriptjs`::
ns.gang.getMemberNames();
ns.gang.recruitMember("Fry");
getMemberNames
--------------
.. js:function:: getMemberNames()
Get the names of all Gang members
:returns: An array of the names of all Gang members as strings
getGangInformation
------------------
.. js:function:: getGangInformation()
Get general information about the gang
:returns: An object with the gang information.
The object has the following structure::
{
faction: Name of faction that the gang belongs to ("Slum Snakes", etc.)
isHacking: Boolean indicating whether or not its a hacking gang
moneyGainRate: Money earned per second
power: Gang's power for territory warfare
respect: Gang's respect
respectGainRate: Respect earned per second
territory: Amount of territory held. Returned in decimal form, not percentage
territoryClashChance: Clash chance. Returned in decimal form, not percentage
wantedLevel: Gang's wanted level
wantedLevelGainRate: Wanted level gained/lost per second (negative for losses)
}
getOtherGangInformation
-----------------------
.. js:function:: getOtherGangInformation()
Get territory and power information about all gangs
:returns: An object with information about all gangs
The object has the following structure::
{
"Slum Snakes" : {
power: Slum Snakes' power
territory: Slum Snakes' territory, in decimal form
},
"Tetrads" : {
power: ...
territory: ...
},
"The Syndicate" : {
power: ...
territory: ...
},
... (for all six gangs)
}
getMemberInformation
--------------------
.. js:function:: getMemberInformation(name)
:param string name: Name of member
Get stat and equipment-related information about a Gang Member
:returns: An object with the gang member information.
The object has the following structure::
{
agility: Agility stat
agilityEquipMult: Agility multiplier from equipment. Decimal form
agilityAscensionMult: Agility multiplier from ascension. Decimal form
augmentation: Array of names of all owned Augmentations
charisma: Charisma stat
charismaEquipMult: Charisma multiplier from equipment. Decimal form
charismaAscensionMult: Charisma multiplier from ascension. Decimal form
defense: Defense stat
defenseEquipMult: Defense multiplier from equipment. Decimal form
defenseAscensionMult: Defense multiplier from ascension. Decimal form
dexterity: Dexterity stat
dexterityEquipMult: Dexterity multiplier from equipment. Decimal form
dexterityAscensionMult: Dexterity multiplier from ascension. Decimal form
equipment: Array of names of all owned Non-Augmentation Equipment
hacking: Hacking stat
hackingEquipMult: Hacking multiplier from equipment. Decimal form
hackingAscensionMult: Hacking multiplier from ascension. Decimal form
strength: Strength stat
strengthEquipMult: Strength multiplier from equipment. Decimal form
strengthAscensionMult: Strength multiplier from ascension. Decimal form
task: Name of currently assigned task
}
canRecruitMember
----------------
.. js:function:: canRecruitMember()
:returns: Boolean indicating whether a member can currently be recruited
recruitMember
-------------
.. js:function:: recruitMember(name)
:param string name: Name of member to recruit
Attempt to recruit a new gang member.
Possible reasons for failure:
* Cannot currently recruit a new member
* There already exists a member with the specified name
:returns: True if the member was successfully recruited. False otherwise
getTaskNames
------------
.. js:function:: getTaskNames()
Get the name of all valid tasks that Gang members can be assigned to
:returns: Array of strings of all task names
setMemberTask
-------------
.. js:function:: setMemberTask(memberName, taskName)
:param string memberName: Name of Gang member to assign
:param string taskName: Task to assign
Attempts to assign the specified Gang Member to the specified task.
If an invalid task is specified, the Gang member will be set to idle ("Unassigned")
:returns: True if the Gang Member was successfully assigned to the task. False otherwise
getEquipmentNames
-----------------
.. js:function:: getEquipmentNames()
Get the name of all possible equipment/upgrades you can purchase for your
Gang Members. This includes Augmentations.
:returns: Array of strings of the names of all Equpiment/Augmentations
getEquipmentCost
----------------
.. js:function:: getEquipmentCost(equipName)
:param string equipName: Name of equipment
Get the amount of money it takes to purchase a piece of Equipment or an Augmentation.
If an invalid Equipment/Augmentation is specified, this function will return Infinity.
:returns: Cost to purchase the specified Equipment/Augmentation (number). Infinity
for invalid arguments
purchaseEquipment
-----------------
.. js:function:: purchaseEquipment(memberName, equipName)
:param string memberName: Name of Gang member to purchase the equipment for
:param string equipName: Name of Equipment/Augmentation to purchase
Attempt to purchase the specified Equipment/Augmentation for the specified
Gang member.
:returns: True if the equipment was successfully purchased. False otherwise
ascendMember
------------
.. js:function:: ascendMember(name)
:param string name: Name of member to ascend
Ascend the specified Gang Member.
:returns: An object with info about the ascension results.
The object has the following structure::
{
respect: Amount of respect lost from ascending
hack: Hacking multiplier gained from ascending. Decimal form
str: Strength multiplier gained from ascending. Decimal form
def: Defense multiplier gained from ascending. Decimal form
dex: Dexterity multiplier gained from ascending. Decimal form
agi: Agility multiplier gained from ascending. Decimal form
cha: Charisma multiplier gained from ascending. Decimal form
}
setTerritoryWarfare
-------------------
.. js:function:: setTerritoryWarfare(engage)
:param bool engage: Whether or not to engage in territory warfare
Set whether or not the gang should engage in territory warfare
getBonusTime
------------
.. js:function:: getBonusTime()
Returns the amount of accumulated "bonus time" (seconds) for the Gang mechanic.
"Bonus time" is accumulated when the game is offline or if the game is
inactive in the browser.
"Bonus time" makes the game progress faster, up to 10x the normal speed.
:returns: Bonus time for the Gang mechanic in seconds

@ -162,24 +162,43 @@ getCharacterInformation
Returns an object with various information about your character. The object has the following properties:: Returns an object with various information about your character. The object has the following properties::
{ {
bitnode: Current BitNode number bitnode: Current BitNode number
company: Name of company city: Name of city you are currently in
jobTitle: Name of job company: Name of company
city: Name of city you are currently in factions: Array of factions you are currently a member of
factions: Array of factions you are currently a member of jobTitle: Name of job
tor: Boolean indicating whether or not you have a tor router tor: Boolean indicating whether or not you have a tor router
//The following apply to when the character is performing // The following is an object with many of the player's multipliers from Augmentations/Source Files
//some type of working action, such as working for a company/faction mult: {
timeWorked: Timed worked in ms agility: Agility stat
workHackExpGain: Hacking experience earned so far from work agilityExp: Agility exp
workStrExpGain: Str experience earned so far from work companyRep: Company reputation
workDefExpGain: Def experience earned so far from work crimeMoney: Money earned from crimes
workDexExpGain: Dex experience earned so far from work crimeSuccess: Crime success chance
workAgiExpGain: Agi experience earned so far from work defense: Defense stat
workChaExpGain: Cha experience earned so far from work defenseExp: Defense exp
workRepGain: Reputation earned so far from work, if applicable dexterity: Dexterity stat
workMoneyGain: Money earned so far from work, if applicable dexterityExp: Dexterity exp
factionRep: Faction reputation
hacking: Hacking stat
hackingExp: Hacking exp
strength: Strength stat
strengthExp: Strength exp
workMoney: Money earned from jobs
},
// The following apply only to when the character is performing
// some type of working action, such as working for a company/faction
timeWorked: Timed worked in ms
workHackExpGain: Hacking experience earned so far from work
workStrExpGain: Str experience earned so far from work
workDefExpGain: Def experience earned so far from work
workDexExpGain: Dex experience earned so far from work
workAgiExpGain: Agi experience earned so far from work
workChaExpGain: Cha experience earned so far from work
workRepGain: Reputation earned so far from work, if applicable
workMoneyGain: Money earned so far from work, if applicable
} }
isBusy isBusy

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Bitburner</title> <title>Bitburner - development</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
@ -109,7 +109,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="30" tabindex="1" />
</div> </div>
<div id="javascript-editor"></div> <div id="javascript-editor"></div>
@ -159,7 +159,7 @@
<fieldset> <fieldset>
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label> <label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"/> <input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr" />
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em> <em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset> </fieldset>
</div> <!-- End script editor options panel --> </div> <!-- End script editor options panel -->
@ -170,7 +170,7 @@
<table id="terminal"> <table id="terminal">
<tr id="terminal-input"> <tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$ <td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/> <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" />
</td> </td>
</tr> </tr>
</table> </table>
@ -187,7 +187,7 @@
provides information about each script's production. The scripts are categorized by the hostname of the servers on which provides information about each script's production. The scripts are categorized by the hostname of the servers on which
they are running. </p> they are running. </p>
<p id="active-scripts-total-prod">Total online production of <p id="active-scripts-total-prod">Total online production of
Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br/> Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br />
Total online production since last Aug installation: <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span> Total online production since last Aug installation: <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span>
(<span class="money-gold"><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span>)</p> (<span class="money-gold"><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span>)</p>
<ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;"> <ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;">
@ -201,19 +201,19 @@
The Hacknet is a global, decentralized network of machines. It is used by hackers all around The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced. fear of being traced.
<br/><br/> <br /><br />
Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its
resources to the Hacknet network. This allows you to take a small percentage of profits resources to the Hacknet network. This allows you to take a small percentage of profits
from hacks performed on the network. Essentially, you are renting out your Node's computing power. from hacks performed on the network. Essentially, you are renting out your Node's computing power.
<br/><br/> <br /><br />
Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded
in order to increase its computing power and thereby increase the profit you earn from it. in order to increase its computing power and thereby increase the profit you earn from it.
</p> </p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a> <a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br/> <br />
<div id="hacknet-nodes-money-multipliers-div"> <div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money"> <p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br/> <span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br />
<span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span> <span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span>
</p> </p>
<span id="hacknet-nodes-multipliers"> <span id="hacknet-nodes-multipliers">
@ -471,7 +471,8 @@
<!-- Tutorial content --> <!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container"> <div id="tutorial-container" class="generic-menupage-container">
<a id="tutorial-getting-started-link" class="a-link-button" href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a> <a id="tutorial-getting-started-link" class="a-link-button"
href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
<a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a> <a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a>
<a id="tutorial-hacking-link" class="a-link-button"> Hacking </a> <a id="tutorial-hacking-link" class="a-link-button"> Hacking </a>
<a id="tutorial-scripts-link" class="a-link-button"> Scripts </a> <a id="tutorial-scripts-link" class="a-link-button"> Scripts </a>
@ -480,7 +481,8 @@
<a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a> <a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a>
<a id="tutorial-factions-link" class="a-link-button"> Factions </a> <a id="tutorial-factions-link" class="a-link-button"> Factions </a>
<a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a> <a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a>
<a id="tutorial-shortcuts-link" class="a-link-button" href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a> <a id="tutorial-shortcuts-link" class="a-link-button"
href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
<a id="tutorial-back-button" class="a-link-button"> Back </a> <a id="tutorial-back-button" class="a-link-button"> Back </a>
<p id="tutorial-text"> </p> <p id="tutorial-text"> </p>
@ -571,7 +573,7 @@
<p id="location-slums-description"> <p id="location-slums-description">
You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and
other shadowy entities. The city's government and police have neglected this area for years... other shadowy entities. The city's government and police have neglected this area for years...
<br/><br/><br/> <br /><br /><br />
In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always
successful. Your chance at successfully committing a crime is determined by your stats. successful. Your chance at successfully committing a crime is determined by your stats.
</p> </p>
@ -618,7 +620,7 @@
<div id="stock-market-container" class="generic-menupage-container"> <div id="stock-market-container" class="generic-menupage-container">
<p> <p>
Welcome to the World Stock Exchange (WSE)! <br/><br/> Welcome to the World Stock Exchange (WSE)! <br /><br />
To begin trading, you must first purchase an account. WSE accounts will persist To begin trading, you must first purchase an account. WSE accounts will persist
after you 'reset' by installing Augmentations. after you 'reset' by installing Augmentations.
@ -631,7 +633,7 @@
TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE. TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE.
Purchasing access to the TIX API lets you write code to create your own algorithmic/automated Purchasing access to the TIX API lets you write code to create your own algorithmic/automated
trading strategies. trading strategies.
<br/><br/> <br /><br />
If you purchase access to the TIX API, you will retain that access even after If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations. you 'reset' by installing Augmentations.
</p> </p>
@ -641,7 +643,7 @@
<p> <p>
Four Sigma's (4S) Market Data Feed provides information about stocks Four Sigma's (4S) Market Data Feed provides information about stocks
that will help your trading strategies. that will help your trading strategies.
<br/><br/> <br /><br />
If you purchase access to 4S Market Data and/or the 4S TIX API, you will If you purchase access to 4S Market Data and/or the 4S TIX API, you will
retain that access even after you 'reset' by installing Augmentations. retain that access even after you 'reset' by installing Augmentations.
</p> </p>
@ -659,7 +661,7 @@
<a id="stock-market-mode" class="a-link-button tooltip"></a> <a id="stock-market-mode" class="a-link-button tooltip"></a>
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a> <a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a> <a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
<br/><br/> <br /><br />
<input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/> <input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/>
<a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a> <a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a>
<ul id="stock-market-list" style="list-style:none;"> <ul id="stock-market-list" style="list-style:none;">
@ -689,7 +691,7 @@
<div id="yes-no-text-input-box-container" class="popup-box-container"> <div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content"> <div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"> </p> <p id="yes-no-text-input-box-text"> </p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30"/> <input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<button id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </button> <button id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </button>
<button id="yes-no-text-input-box-no" class="popup-box-button"> No </button> <button id="yes-no-text-input-box-no" class="popup-box-button"> No </button>
</div> </div>
@ -701,7 +703,7 @@
<p id="faction-invitation-box-text"> </p> <p id="faction-invitation-box-text"> </p>
<p id="faction-invitation-box-message"> </p> <p id="faction-invitation-box-message"> </p>
<p id="faction-invitation-box-warning"> <p id="faction-invitation-box-warning">
Would you like to join? <br/> <br/> Would you like to join? <br /> <br />
Warning: Joining this faction may prevent you from joining other factions during this run! Warning: Joining this faction may prevent you from joining other factions during this run!
</p> </p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button> <button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
@ -714,8 +716,8 @@
<div id="infiltration-box-content" class="popup-box-content"> <div id="infiltration-box-content" class="popup-box-content">
<p id="infiltration-box-text"> </p> <p id="infiltration-box-text"> </p>
<button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br/><br/> <button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br /><br />
<select id="infiltration-faction-select"> </select> <br/> <select id="infiltration-faction-select"> </select> <br />
<button id="infiltration-box-faction" class="a-link-button"> Give to Faction for Reputation </button> <button id="infiltration-box-faction" class="a-link-button"> Give to Faction for Reputation </button>
</div> </div>
@ -801,7 +803,7 @@
<div id="game-options-content" class="game-options-box"> <div id="game-options-content" class="game-options-box">
<button id="game-options-close-button">&times;</button> <button id="game-options-close-button">&times;</button>
<h1> Game Options </h1> <h1> Game Options </h1>
<br/> <br />
<div id="game-options-left-panel"> <div id="game-options-left-panel">
<!-- Netscript execution time --> <!-- Netscript execution time -->
<fieldset> <fieldset>
@ -813,7 +815,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/> <input type ="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25" />
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -827,7 +829,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/> <input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -841,7 +843,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/> <input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -853,7 +855,7 @@
</span> </span>
</label> </label>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/> <input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em> <em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -965,7 +967,7 @@
<a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a> <a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a>
<a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a> <a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a>
<a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a> <a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a>
<input type="file" id="import-game-file-selector" name="file"/> <input type="file" id="import-game-file-selector" name="file" />
<a id="import-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Import Game </a> <a id="import-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Import Game </a>
<a id="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;"> <a id="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;">
(DEBUG) Delete Active Scripts (DEBUG) Delete Active Scripts

@ -101,7 +101,14 @@ let NetscriptFunctions =
"upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" + "upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" +
"getRamUpgradeCost|getCoreUpgradeCost|" + "getRamUpgradeCost|getCoreUpgradeCost|" +
// Bladeburner functions // Gang API
"gang|" +
"getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" +
"recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" +
"getEquipmentCost|purchaseEquipment|ascendMember|setTerritoryWarfare|" +
"getBonusTime|" +
// Bladeburner API
"bladeburner|getContractNames|getOperationNames|getBlackOpNames|" + "bladeburner|getContractNames|getOperationNames|getBlackOpNames|" +
"getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" + "getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" +
"getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" + "getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" +

@ -152,7 +152,7 @@ function addActiveScriptsItem(workerscript) {
panel.appendChild(createElement("br")); panel.appendChild(createElement("br"));
panel.appendChild(createElement("span", { panel.appendChild(createElement("span", {
innerText: "Log", innerText: "Log",
class: "active-scripts-button", class: "accordion-button",
margin: "4px", margin: "4px",
padding: "4px", padding: "4px",
clickListener: () => { clickListener: () => {
@ -162,7 +162,7 @@ function addActiveScriptsItem(workerscript) {
})); }));
panel.appendChild(createElement("span", { panel.appendChild(createElement("span", {
innerText: "Kill Script", innerText: "Kill Script",
class: "active-scripts-button", class: "accordion-button",
margin: "4px", margin: "4px",
padding: "4px", padding: "4px",
clickListener: () => { clickListener: () => {

@ -9,6 +9,9 @@ import {prestigeAugmentation} from "./Prestige";
import {saveObject} from "./SaveObject"; import {saveObject} from "./SaveObject";
import {Script, RunningScript} from "./Script"; import {Script, RunningScript} from "./Script";
import {Server} from "./Server"; import {Server} from "./Server";
import {OwnedAugmentationsOrderSetting} from "./SettingEnums";
import {Settings} from "./Settings";
import {SourceFiles} from "./SourceFile"; import {SourceFiles} from "./SourceFile";
import {dialogBoxCreate} from "../utils/DialogBox"; import {dialogBoxCreate} from "../utils/DialogBox";
import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement"; import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement";
@ -2570,7 +2573,7 @@ function displayAugmentationsContent() {
})); }));
//Sort Buttons //Sort Buttons
Engine.Display.augmentationsContent.appendChild(createElement("a", { const sortInOrderButton = createElement("a", {
class:"a-link-button", fontSize:"14px", innerText:"Sort in Order", class:"a-link-button", fontSize:"14px", innerText:"Sort in Order",
tooltip:"Sorts the Augmentations alphabetically and Source Files in numerical order (1, 2, 3,...)", tooltip:"Sorts the Augmentations alphabetically and Source Files in numerical order (1, 2, 3,...)",
clickListener:()=>{ clickListener:()=>{
@ -2587,22 +2590,31 @@ function displayAugmentationsContent() {
}); });
displaySourceFiles(augmentationsList, sourceFiles); displaySourceFiles(augmentationsList, sourceFiles);
displayAugmentations(augmentationsList, augs); displayAugmentations(augmentationsList, augs);
}
}));
Engine.Display.augmentationsContent.appendChild(createElement("a", { Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically;
}
});
Engine.Display.augmentationsContent.appendChild(sortInOrderButton);
const sortByAcquirementTimeButton = createElement("a", {
class:"a-link-button", fontSize:"14px", innerText:"Sort by Acquirement Time", class:"a-link-button", fontSize:"14px", innerText:"Sort by Acquirement Time",
tooltip:"Sorts the Augmentations and Source Files based on when you acquired them (same as default)", tooltip:"Sorts the Augmentations and Source Files based on when you acquired them (same as default)",
clickListener:()=>{ clickListener:()=>{
removeChildrenFromElement(augmentationsList); removeChildrenFromElement(augmentationsList);
displaySourceFiles(augmentationsList, Player.sourceFiles); displaySourceFiles(augmentationsList, Player.sourceFiles);
displayAugmentations(augmentationsList, Player.augmentations); displayAugmentations(augmentationsList, Player.augmentations);
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime;
} }
})); });
Engine.Display.augmentationsContent.appendChild(sortByAcquirementTimeButton);
//Source Files - Temporary...Will probably put in a separate pane Later //Source Files - Temporary...Will probably put in a separate pane Later
displaySourceFiles(augmentationsList, Player.sourceFiles); if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
displayAugmentations(augmentationsList, Player.augmentations); sortInOrderButton.click();
} else {
sortByAcquirementTimeButton.click();
}
Engine.Display.augmentationsContent.appendChild(augmentationsList); Engine.Display.augmentationsContent.appendChild(augmentationsList);
} }

@ -28,7 +28,9 @@ function initBitNodes() {
"left behind from the collapse of Western government in the 2050's. As society and civlization broke down, " + "left behind from the collapse of Western government in the 2050's. As society and civlization broke down, " +
"people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " + "people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " +
"factions quickly rose to the top of the modern world.<br><br>" + "factions quickly rose to the top of the modern world.<br><br>" +
"In this BitNode:<br><br>The maximum amount of money available on a server is significantly decreased<br>" + "In this BitNode:<br><br>" +
"Your hacking level is reduced by 20%<br>" +
"The growth rate and maximum amount of money available on servers are significantly decreased<br>" +
"The amount of money gained from crimes and Infiltration is tripled<br>" + "The amount of money gained from crimes and Infiltration is tripled<br>" +
"Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, " + "Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, " +
"NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs " + "NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs " +
@ -214,6 +216,8 @@ function initBitNodeMultipliers() {
case 1: //Source Genesis (every multiplier is 1) case 1: //Source Genesis (every multiplier is 1)
break; break;
case 2: //Rise of the Underworld case 2: //Rise of the Underworld
BitNodeMultipliers.HackingLevelMultiplier = 0.8;
BitNodeMultipliers.ServerGrowthRate = 0.8;
BitNodeMultipliers.ServerMaxMoney = 0.2; BitNodeMultipliers.ServerMaxMoney = 0.2;
BitNodeMultipliers.ServerStartingMoney = 0.4; BitNodeMultipliers.ServerStartingMoney = 0.4;
BitNodeMultipliers.CrimeMoney = 3; BitNodeMultipliers.CrimeMoney = 3;

@ -1768,8 +1768,9 @@ Bladeburner.prototype.createOverviewContent = function() {
}); });
DomElems.overviewStaminaHelpTip = createElement("div", { DomElems.overviewStaminaHelpTip = createElement("div", {
innerText:"?", class:"help-tip", class:"help-tip",
clickListener:()=>{ innerText:"?",
clickListener: ()=> {
dialogBoxCreate("Performing actions will use up your stamina.<br><br>" + dialogBoxCreate("Performing actions will use up your stamina.<br><br>" +
"Your max stamina is determined primarily by your agility stat.<br><br>" + "Your max stamina is determined primarily by your agility stat.<br><br>" +
"Your stamina gain rate is determined by both your agility and your " + "Your stamina gain rate is determined by both your agility and your " +
@ -1781,7 +1782,7 @@ Bladeburner.prototype.createOverviewContent = function() {
"your success rate would be multipled by 85% (100 - 15).<br><br>" + "your success rate would be multipled by 85% (100 - 15).<br><br>" +
"Your max stamina and stamina gain rate can also be increased by " + "Your max stamina and stamina gain rate can also be increased by " +
"training, or through skills and Augmentation upgrades."); "training, or through skills and Augmentation upgrades.");
} },
}); });
DomElems.overviewGen1 = createElement("p", { DomElems.overviewGen1 = createElement("p", {
@ -1831,7 +1832,7 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText: "Bonus time: ", innerText: "Bonus time: ",
display: "inline-block", display: "inline-block",
tooltip: "You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by browser). " + tooltip: "You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by browser). " +
"Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed." "Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed."
}); });
DomElems.overviewSkillPoints = createElement("p", {display:"block"}); DomElems.overviewSkillPoints = createElement("p", {display:"block"});

@ -93,6 +93,8 @@ let CONSTANTS = {
ScriptSingularityFnRamMult: 2, // Multiplier for RAM cost outside of BN-4 ScriptSingularityFnRamMult: 2, // Multiplier for RAM cost outside of BN-4
ScriptGangApiBaseRamCost: 4,
ScriptBladeburnerApiBaseRamCost: 4, ScriptBladeburnerApiBaseRamCost: 4,
NumNetscriptPorts: 20, NumNetscriptPorts: 20,
@ -193,13 +195,6 @@ let CONSTANTS = {
"-Miscellaneous Nodes slowly raise their defense over time<br><br>" + "-Miscellaneous Nodes slowly raise their defense over time<br><br>" +
"-Nodes slowly regenerate health over time.", "-Nodes slowly regenerate health over time.",
/* Gang constant */
GangRespectToReputationRatio: 2, //Respect is divided by this to get rep gain
MaximumGangMembers: 20,
GangRecruitCostMultiplier: 2,
GangTerritoryUpdateTimer: 150,
/* Time Constants */ /* Time Constants */
MillisecondsPer20Hours: 72000000, MillisecondsPer20Hours: 72000000,
GameCyclesPer20Hours: 72000000 / 200, GameCyclesPer20Hours: 72000000 / 200,
@ -258,7 +253,6 @@ let CONSTANTS = {
ClassLeadershipBaseCost: 320, ClassLeadershipBaseCost: 320,
ClassGymBaseCost: 120, ClassGymBaseCost: 120,
CrimeSingFnDivider: 2, //Factor by which exp/profit is reduced when commiting crime through Sing Fn
CrimeShoplift: "shoplift", CrimeShoplift: "shoplift",
CrimeRobStore: "rob a store", CrimeRobStore: "rob a store",
CrimeMug: "mug someone", CrimeMug: "mug someone",
@ -510,10 +504,27 @@ let CONSTANTS = {
` `
v0.41.0 v0.41.0
* WARNING: In NetscriptJS, defining a function called print() is no longer possible * WARNING: In NetscriptJS, defining a function called print() is no longer possible
* Gang Mechanic Changes (BitNode-2):
*** Added a Gang Netscript API
*** Added new 'ascension' mechanic for Gang Members
*** The first three gang members are now 'free' (can be recruited instantly)
*** Maximum number of increased Gang Members increased from 20 to 30
*** Changed the formula for calculating respect needed to recruit the next gang member
*** Added a new category of upgrades for Gang Members: Augmentations
*** Non-Augmentation Gang member upgrades are now significantly weaker
*** Reputation for your Gang faction can no longer be gained through Infiltration
*** Re-worked the territory 'warfare' mechanic so that player can choose when to engage in it
*** Gang Members can now be killed during territory 'warfare'
*** Changed BitNode-2 Multipliers to make hacking slightly less profitable
*** Gang Member Equipment + Upgrades now get cheaper as your gang grows in power and respect
*** The effects of Source-File 2 are now slightly more powerful
* RAM Cost of accessing the global document object lowered from 100 GB to 25 GB * RAM Cost of accessing the global document object lowered from 100 GB to 25 GB
* RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4 * RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4
* b1t_flum3.exe now takes significantly less time to create * b1t_flum3.exe now takes significantly less time to create
* Crimes commited through Singularity function no longer give half money/exp
* Improved number formatting for Player 'work' actions (including crimes, etc.). These numbers should also adhere to locale settings now (by Kline-) * Improved number formatting for Player 'work' actions (including crimes, etc.). These numbers should also adhere to locale settings now (by Kline-)
* The order that Augmentations are listed in (when purchasing from Faction and viewing your Augmentations) is now saved and persists when choosing different orders
* getCharacterInformation() Singularity function now returns multiplier information (from Augmentations/Source Files)
* Bug Fix: Calling print() in NetscriptJS no longer brings up the print dialog * Bug Fix: Calling print() in NetscriptJS no longer brings up the print dialog
* Bug Fix: Fixed a bug that sometimes caused a blank black screen when destroying/resetting/switching BitNodes * Bug Fix: Fixed a bug that sometimes caused a blank black screen when destroying/resetting/switching BitNodes
* Bug Fix: Netscript calls that throw errors will now no longer cause the 'concurrent calls' error if they are caught in the script. i.e. try/catch should now work properly in scripts * Bug Fix: Netscript calls that throw errors will now no longer cause the 'concurrent calls' error if they are caught in the script. i.e. try/catch should now work properly in scripts
@ -521,6 +532,7 @@ let CONSTANTS = {
* Bug Fix: Fixed a bug where calling the scp() Netscript function with invalid hostname/ips would throw an unclear error message * Bug Fix: Fixed a bug where calling the scp() Netscript function with invalid hostname/ips would throw an unclear error message
* Bug Fix: Bladeburner API function getActionCountRemaining() should now work properly for BlackOps * Bug Fix: Bladeburner API function getActionCountRemaining() should now work properly for BlackOps
* Bug Fix: Black Ops can no longer be attempted out-of-order or without the required rank via Bladeburner API * Bug Fix: Black Ops can no longer be attempted out-of-order or without the required rank via Bladeburner API
* Bug Fix: Dynamic RAM Calculation now properly accounts for number of threads
* RAM cost for basic Netscript functions added to documentation (by CBJamo) * RAM cost for basic Netscript functions added to documentation (by CBJamo)
` `

@ -3,6 +3,7 @@ import {Programs} from "./CreateProgram"
import {Factions} from "./Faction"; import {Factions} from "./Faction";
import {Player} from "./Player"; import {Player} from "./Player";
import {AllServers} from "./Server"; import {AllServers} from "./Server";
import {hackWorldDaemon} from "./RedPill";
import {Terminal} from "./Terminal"; import {Terminal} from "./Terminal";
import {exceptionAlert} from "../utils/helpers/exceptionAlert"; import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {createElement} from "../utils/uiHelpers/createElement"; import {createElement} from "../utils/uiHelpers/createElement";
@ -69,7 +70,7 @@ export function createDevMenu() {
const statsHackingExpInput = createElement("input", { const statsHackingExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- hacking exp",
type: "number", type: "number",
}); });
@ -80,14 +81,13 @@ export function createDevMenu() {
Player.gainHackingExp(exp); Player.gainHackingExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block",
innerText: "Add Hacking Exp", innerText: "Add Hacking Exp",
}); });
const statsStrengthExpInput = createElement("input", { const statsStrengthExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- strength exp",
type: "number", type: "number",
}); });
const statsStrengthExpButton = createElement("button", { const statsStrengthExpButton = createElement("button", {
@ -97,14 +97,13 @@ export function createDevMenu() {
Player.gainStrengthExp(exp); Player.gainStrengthExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block", innerText: "Add Strength Exp",
innerText: "Add Hacking Exp",
}); });
const statsDefenseExpInput = createElement("input", { const statsDefenseExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- defense exp",
type: "number", type: "number",
}); });
const statsDefenseExpButton = createElement("button", { const statsDefenseExpButton = createElement("button", {
@ -114,14 +113,13 @@ export function createDevMenu() {
Player.gainDefenseExp(exp); Player.gainDefenseExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block", innerText: "Add Defense Exp",
innerText: "Add Hacking Exp",
}); });
const statsDexterityExpInput = createElement("input", { const statsDexterityExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- dexterity exp",
type: "number", type: "number",
}); });
const statsDexterityExpButton = createElement("button", { const statsDexterityExpButton = createElement("button", {
@ -131,31 +129,29 @@ export function createDevMenu() {
Player.gainDexterityExp(exp); Player.gainDexterityExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block", innerText: "Add Dexterity Exp",
innerText: "Add Hacking Exp",
}); });
const statsAgilityExpInput = createElement("input", { const statsAgilityExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- agility exp",
type: "number", type: "number",
}); });
const statsAgilityExpButton = createElement("button", { const statsAgilityExpButton = createElement("button", {
class: "std-button", class: "std-button",
clickListener: () => { clickListener: () => {
const exp = parseInt(statsAgilityExpButton.value); const exp = parseInt(statsAgilityExpInput.value);
Player.gainAgilityExp(exp); Player.gainAgilityExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block", innerText: "Add Agility Exp",
innerText: "Add Hacking Exp",
}); });
const statsCharismaExpInput = createElement("input", { const statsCharismaExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- charisma exp",
type: "number", type: "number",
}); });
const statsCharismaExpButton = createElement("button", { const statsCharismaExpButton = createElement("button", {
@ -165,14 +161,13 @@ export function createDevMenu() {
Player.gainCharismaExp(exp); Player.gainCharismaExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block", innerText: "Add Charisma Exp",
innerText: "Add Hacking Exp",
}); });
const statsIntelligenceExpInput = createElement("input", { const statsIntelligenceExpInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block", margin: "5px",
placeholder: "+/- hacking exp", placeholder: "+/- intelligence exp",
type: "number", type: "number",
}); });
const statsIntelligenceExpButton = createElement("button", { const statsIntelligenceExpButton = createElement("button", {
@ -182,8 +177,7 @@ export function createDevMenu() {
Player.gainIntelligenceExp(exp); Player.gainIntelligenceExp(exp);
Player.updateSkillLevels(); Player.updateSkillLevels();
}, },
display: "block", innerText: "Add Intelligence Exp",
innerText: "Add Hacking Exp",
}); });
const statsEnableIntelligenceButton = createElement("button", { const statsEnableIntelligenceButton = createElement("button", {
@ -205,7 +199,10 @@ export function createDevMenu() {
// Factions // Factions
const factionsHeader = createElement("h2", {innerText: "Factions"}); const factionsHeader = createElement("h2", {innerText: "Factions"});
const factionsDropdown = createElement("select", {class: "dropdown"}); const factionsDropdown = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const i in Factions) { for (const i in Factions) {
factionsDropdown.options[factionsDropdown.options.length] = new Option(Factions[i].name, Factions[i].name); factionsDropdown.options[factionsDropdown.options.length] = new Option(Factions[i].name, Factions[i].name);
} }
@ -222,7 +219,10 @@ export function createDevMenu() {
// Augmentations / Source Files // Augmentations / Source Files
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"}); const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
const augmentationsDropdown = createElement("select", {class: "dropdown"}); const augmentationsDropdown = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const i in AugmentationNames) { for (const i in AugmentationNames) {
const augName = AugmentationNames[i]; const augName = AugmentationNames[i];
augmentationsDropdown.options[augmentationsDropdown.options.length] = new Option(augName, augName); augmentationsDropdown.options[augmentationsDropdown.options.length] = new Option(augName, augName);
@ -239,7 +239,10 @@ export function createDevMenu() {
// Programs // Programs
const programsHeader = createElement("h2", {innerText: "Programs"}); const programsHeader = createElement("h2", {innerText: "Programs"});
const programsAddDropdown = createElement("select", {class: "dropdown"}); const programsAddDropdown = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const i in Programs) { for (const i in Programs) {
const progName = Programs[i].name; const progName = Programs[i].name;
programsAddDropdown.options[programsAddDropdown.options.length] = new Option(progName, progName); programsAddDropdown.options[programsAddDropdown.options.length] = new Option(progName, progName);
@ -313,17 +316,11 @@ export function createDevMenu() {
innerText: "Connect to server", innerText: "Connect to server",
}); });
// Add everything to container, then append to main menu // Bladeburner
const devMenuContainer = createElement("div", {
class: "generic-menupage-container",
id: devMenuContainerId,
});
const bladeburnerHeader = createElement("h2", {innerText: "Bladeburner"}); const bladeburnerHeader = createElement("h2", {innerText: "Bladeburner"});
const bladeburnerGainRankInput = createElement("input", { const bladeburnerGainRankInput = createElement("input", {
class: "text-input", class: "text-input",
display: "block",
placeholder: "Rank to gain (or negative to lose rank)", placeholder: "Rank to gain (or negative to lose rank)",
type: "number", type: "number",
}); });
@ -338,10 +335,37 @@ export function createDevMenu() {
exceptionAlert(`Failed to change Bladeburner Rank in dev menu: ${e}`); exceptionAlert(`Failed to change Bladeburner Rank in dev menu: ${e}`);
} }
}, },
display: "block",
innerText: "Gain Bladeburner Rank", innerText: "Gain Bladeburner Rank",
});
// Gang
const gangHeader = createElement("h2", {innerText: "Gang"});
const gangStoredCyclesInput = createElement("input", {
class: "text-input",
placeholder: "# Cycles to add",
type: "number",
});
const gangAddStoredCycles = createElement("button", {
class: "std-button",
clickListener: () => {
try {
const cycles = parseInt(gangStoredCyclesInput.value);
Player.gang.storedCycles += cycles;
} catch(e) {
exceptionAlert(`Failed to add stored cycles to gang mechanic: ${e}`);
}
},
innerText: "Add cycles to Gang mechanic",
}) })
// Add everything to container, then append to main menu
const devMenuContainer = createElement("div", {
class: "generic-menupage-container",
id: devMenuContainerId,
});
devMenuContainer.appendChild(devMenuText); devMenuContainer.appendChild(devMenuText);
devMenuContainer.appendChild(genericHeader); devMenuContainer.appendChild(genericHeader);
devMenuContainer.appendChild(addMoney); devMenuContainer.appendChild(addMoney);
@ -351,24 +375,32 @@ export function createDevMenu() {
devMenuContainer.appendChild(statsHeader); devMenuContainer.appendChild(statsHeader);
devMenuContainer.appendChild(statsHackingExpInput); devMenuContainer.appendChild(statsHackingExpInput);
devMenuContainer.appendChild(statsHackingExpButton); devMenuContainer.appendChild(statsHackingExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsStrengthExpInput); devMenuContainer.appendChild(statsStrengthExpInput);
devMenuContainer.appendChild(statsStrengthExpButton); devMenuContainer.appendChild(statsStrengthExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsDefenseExpInput); devMenuContainer.appendChild(statsDefenseExpInput);
devMenuContainer.appendChild(statsDefenseExpButton); devMenuContainer.appendChild(statsDefenseExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsDexterityExpInput); devMenuContainer.appendChild(statsDexterityExpInput);
devMenuContainer.appendChild(statsDexterityExpButton); devMenuContainer.appendChild(statsDexterityExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsAgilityExpInput); devMenuContainer.appendChild(statsAgilityExpInput);
devMenuContainer.appendChild(statsAgilityExpButton); devMenuContainer.appendChild(statsAgilityExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsCharismaExpInput); devMenuContainer.appendChild(statsCharismaExpInput);
devMenuContainer.appendChild(statsCharismaExpButton); devMenuContainer.appendChild(statsCharismaExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsIntelligenceExpInput); devMenuContainer.appendChild(statsIntelligenceExpInput);
devMenuContainer.appendChild(statsIntelligenceExpButton); devMenuContainer.appendChild(statsIntelligenceExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsEnableIntelligenceButton); devMenuContainer.appendChild(statsEnableIntelligenceButton);
devMenuContainer.appendChild(statsDisableIntelligenceButton); devMenuContainer.appendChild(statsDisableIntelligenceButton);
devMenuContainer.appendChild(factionsHeader); devMenuContainer.appendChild(factionsHeader);
devMenuContainer.appendChild(factionsDropdown); devMenuContainer.appendChild(factionsDropdown);
devMenuContainer.appendChild(factionsAddButton); devMenuContainer.appendChild(factionsAddButton);
devMenuContainer.appendChild(augmentationsHeader); devMenuContainer.appendChild(augmentationsHeader);
devMenuContainer.appendChild(augmentationsDropdown);
devMenuContainer.appendChild(augmentationsQueueButton); devMenuContainer.appendChild(augmentationsQueueButton);
devMenuContainer.appendChild(programsHeader); devMenuContainer.appendChild(programsHeader);
devMenuContainer.appendChild(programsAddDropdown); devMenuContainer.appendChild(programsAddDropdown);
@ -382,6 +414,11 @@ export function createDevMenu() {
devMenuContainer.appendChild(bladeburnerHeader); devMenuContainer.appendChild(bladeburnerHeader);
devMenuContainer.appendChild(bladeburnerGainRankInput); devMenuContainer.appendChild(bladeburnerGainRankInput);
devMenuContainer.appendChild(bladeburnerGainRankButton); devMenuContainer.appendChild(bladeburnerGainRankButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(gangHeader);
devMenuContainer.appendChild(gangStoredCyclesInput);
devMenuContainer.appendChild(gangAddStoredCycles);
devMenuContainer.appendChild(createElement("br"));
const entireGameContainer = document.getElementById("entire-game-container"); const entireGameContainer = document.getElementById("entire-game-container");
if (entireGameContainer == null) { if (entireGameContainer == null) {

@ -7,6 +7,7 @@ import {FactionInfos} from "./FactionInfo";
import {Locations} from "./Location"; import {Locations} from "./Location";
import {HackingMission, setInMission} from "./Missions"; import {HackingMission, setInMission} from "./Missions";
import {Player} from "./Player"; import {Player} from "./Player";
import {PurchaseAugmentationsOrderSetting} from "./SettingEnums";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import {Page, routing} from "./ui/navigationTracking"; import {Page, routing} from "./ui/navigationTracking";
@ -446,7 +447,6 @@ function displayFactionContent(factionName) {
} }
} }
var sortOption = null;
function displayFactionAugmentations(factionName) { function displayFactionAugmentations(factionName) {
var faction = Factions[factionName]; var faction = Factions[factionName];
if (faction == null) { if (faction == null) {
@ -481,10 +481,10 @@ function displayFactionAugmentations(factionName) {
var augmentationsList = createElement("ul"); var augmentationsList = createElement("ul");
//Sort buttons //Sort buttons
var sortByCostBtn = createElement("a", { const sortByCostBtn = createElement("a", {
innerText:"Sort by Cost", class:"a-link-button", innerText:"Sort by Cost", class:"a-link-button",
clickListener:()=>{ clickListener:()=>{
sortOption = "cost"; Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Cost;
var augs = faction.augmentations.slice(); var augs = faction.augmentations.slice();
augs.sort((augName1, augName2)=>{ augs.sort((augName1, augName2)=>{
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2]; var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
@ -497,10 +497,10 @@ function displayFactionAugmentations(factionName) {
createFactionAugmentationDisplayElements(augmentationsList, augs, faction); createFactionAugmentationDisplayElements(augmentationsList, augs, faction);
} }
}); });
var sortByRepBtn = createElement("a", { const sortByRepBtn = createElement("a", {
innerText:"Sort by Reputation", class:"a-link-button", innerText:"Sort by Reputation", class:"a-link-button",
clickListener:()=>{ clickListener:()=>{
sortOption = "reputation"; Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Reputation;
var augs = faction.augmentations.slice(); var augs = faction.augmentations.slice();
augs.sort((augName1, augName2)=>{ augs.sort((augName1, augName2)=>{
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2]; var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
@ -513,10 +513,10 @@ function displayFactionAugmentations(factionName) {
createFactionAugmentationDisplayElements(augmentationsList, augs, faction); createFactionAugmentationDisplayElements(augmentationsList, augs, faction);
} }
}); });
var defaultSortBtn = createElement("a", { const defaultSortBtn = createElement("a", {
innerText:"Sort by Default Order", class:"a-link-button", innerText:"Sort by Default Order", class:"a-link-button",
clickListener:()=>{ clickListener:()=>{
sortOption = "default"; Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Default;
removeChildrenFromElement(augmentationsList); removeChildrenFromElement(augmentationsList);
createFactionAugmentationDisplayElements(augmentationsList, faction.augmentations, faction); createFactionAugmentationDisplayElements(augmentationsList, faction.augmentations, faction);
} }
@ -524,11 +524,11 @@ function displayFactionAugmentations(factionName) {
elements.push(sortByCostBtn); elements.push(sortByCostBtn);
elements.push(sortByRepBtn); elements.push(sortByRepBtn);
elements.push(defaultSortBtn); elements.push(defaultSortBtn);
switch(sortOption) { switch(Settings.PurchaseAugmentationsOrder) {
case "cost": case PurchaseAugmentationsOrderSetting.Cost:
sortByCostBtn.click(); sortByCostBtn.click();
break; break;
case "reputation": case PurchaseAugmentationsOrderSetting.Reputation:
sortByRepBtn.click(); sortByRepBtn.click();
break; break;
default: default:

File diff suppressed because it is too large Load Diff

@ -28,10 +28,6 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoTxtInpBoxClose} from "../utils/YesNoBox"; yesNoTxtInpBoxClose} from "../utils/YesNoBox";
function displayLocationContent() { function displayLocationContent() {
if (Engine.Debug) {
console.log("displayLocationContent() called with location " + Player.location)
}
var returnToWorld = document.getElementById("location-return-to-world-button"); var returnToWorld = document.getElementById("location-return-to-world-button");
var locationName = document.getElementById("location-name"); var locationName = document.getElementById("location-name");

@ -9,7 +9,7 @@ function unknownBladeburnerActionErrorMessage(functionName, actionType, actionNa
} }
function unknownBladeburnerExceptionMessage(functionName, err) { function unknownBladeburnerExceptionMessage(functionName, err) {
return `Bladeburner.${functionName}() failed with exception: ` + err; return `bladeburner.${functionName}() failed with exception: ` + err;
} }
function checkBladeburnerAccess(workerScript, functionName) { function checkBladeburnerAccess(workerScript, functionName) {

@ -46,7 +46,8 @@ import {TextFile, getTextFile, createTextFile} from "./TextFile";
import {unknownBladeburnerActionErrorMessage, import {unknownBladeburnerActionErrorMessage,
unknownBladeburnerExceptionMessage, unknownBladeburnerExceptionMessage,
checkBladeburnerAccess} from "./NetscriptBladeburner.js"; checkBladeburnerAccess} from "./NetscriptBladeburner";
import * as nsGang from "./NetscriptGang";
import {WorkerScript, workerScripts, import {WorkerScript, workerScripts,
killWorkerScript, NetscriptPorts} from "./NetscriptWorker"; killWorkerScript, NetscriptPorts} from "./NetscriptWorker";
import {makeRuntimeRejectMsg, netscriptDelay, import {makeRuntimeRejectMsg, netscriptDelay,
@ -155,7 +156,14 @@ function NetscriptFunctions(workerScript) {
var updateDynamicRam = function(fnName, ramCost) { var updateDynamicRam = function(fnName, ramCost) {
if (workerScript.dynamicLoadedFns[fnName]) {return;} if (workerScript.dynamicLoadedFns[fnName]) {return;}
workerScript.dynamicLoadedFns[fnName] = true; workerScript.dynamicLoadedFns[fnName] = true;
workerScript.dynamicRamUsage += ramCost;
const threads = workerScript.scriptRef.threads;
if (typeof threads !== 'number') {
console.warn(`WorkerScript detected NaN for threadcount for ${workerScript.name} on ${workerScript.serverIp}`);
threads = 1;
}
workerScript.dynamicRamUsage += (ramCost * threads);
if (workerScript.dynamicRamUsage > 1.01 * workerScript.ramUsage) { if (workerScript.dynamicRamUsage > 1.01 * workerScript.ramUsage) {
throw makeRuntimeRejectMsg(workerScript, throw makeRuntimeRejectMsg(workerScript,
"Dynamic RAM usage calculated to be greater than initial RAM usage on fn: " + fnName + "Dynamic RAM usage calculated to be greater than initial RAM usage on fn: " + fnName +
@ -1101,7 +1109,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ps() failed. Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "ps() failed. Invalid IP or hostname passed in: " + ip);
} }
const processes = []; const processes = [];
for(const i in server.runningScripts) { for (const i in server.runningScripts) {
const script = server.runningScripts[i]; const script = server.runningScripts[i];
processes.push({filename:script.filename, threads: script.threads, args: script.args.slice()}) processes.push({filename:script.filename, threads: script.threads, args: script.args.slice()})
} }
@ -2679,12 +2687,29 @@ function NetscriptFunctions(workerScript) {
} }
return { return {
bitnode: Player.bitNodeN, bitnode: Player.bitNodeN,
company: Player.companyName,
jobTitle: companyPositionTitle,
city: Player.city, city: Player.city,
company: Player.companyName,
factions: Player.factions.slice(), factions: Player.factions.slice(),
tor: SpecialServerIps.hasOwnProperty("Darkweb Server"), jobTitle: companyPositionTitle,
mult: {
agility: Player.agility_mult,
agilityExp: Player.agility_exp_mult,
companyRep: Player.company_rep_mult,
crimeMoney: Player.crime_money_mult,
crimeSuccess: Player.crime_success_mult,
defense: Player.defense_mult,
defenseExp: Player.defense_exp_mult,
dexterity: Player.dexterity_mult,
dexterityExp: Player.dexterity_exp_mult,
factionRep: Player.faction_rep_mult,
hacking: Player.hacking_mult,
hackingExp: Player.hacking_exp_mult,
strength: Player.strength_mult,
strengthExp: Player.strength_exp_mult,
workMoney: Player.work_money_mult,
},
timeWorked: Player.timeWorked, timeWorked: Player.timeWorked,
tor: SpecialServerIps.hasOwnProperty("Darkweb Server"),
workHackExpGain: Player.workHackExpGained, workHackExpGain: Player.workHackExpGained,
workStrExpGain: Player.workStrExpGained, workStrExpGain: Player.workStrExpGained,
workDefExpGain: Player.workDefExpGained, workDefExpGain: Player.workDefExpGained,
@ -3331,7 +3356,7 @@ function NetscriptFunctions(workerScript) {
if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.commitCrime == null) { if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.commitCrime == null) {
workerScript.scriptRef.log("Attempting to commit crime: "+crime.name+"..."); workerScript.scriptRef.log("Attempting to commit crime: "+crime.name+"...");
} }
return crime.commit(CONSTANTS.CrimeSingFnDivider, {workerscript: workerScript}); return crime.commit(1, {workerscript: workerScript});
}, },
getCrimeChance : function(crimeRoughName) { getCrimeChance : function(crimeRoughName) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
@ -3534,7 +3559,262 @@ function NetscriptFunctions(workerScript) {
return true; return true;
}, },
//Bladeburner API // Gang API
gang : {
getMemberNames : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getMemberNames", CONSTANTS.ScriptGangApiBaseRamCost / 4);
}
updateDynamicRam("getMemberNames", CONSTANTS.ScriptGangApiBaseRamCost / 4);
nsGang.checkGangApiAccess(workerScript, "getMemberNames");
try {
const names = [];
for (const member of Player.gang.members) {
names.push(member.name);
}
return names;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberNames", e));
}
},
getGangInformation : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getGangInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getGangInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getGangInformation");
try {
return {
faction: Player.gang.facName,
isHacking: Player.gang.isHackingGang,
moneyGainRate: Player.gang.moneyGainRate,
power: Player.gang.getPower(),
respect: Player.gang.respect,
respectGainRate: Player.gang.respectGainRate,
territory: Player.gang.getTerritory(),
territoryClashChance: Player.gang.territoryClashChance,
territoryWarfareEngaged: Player.gang.territoryWarfareEngaged,
wantedLevel: Player.gang.wanted,
wantedLevelGainRate: Player.gang.wantedGainRate,
}
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getGangInformation", e));
}
},
getOtherGangInformation : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getOtherGangInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getOtherGangInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getOtherGangInformation");
try {
return Object.assign(AllGangs);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getOtherGangInformation", e));
}
},
getMemberInformation : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("getMemberInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getMemberInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getMemberInformation");
try {
for (const member of Player.gang.members) {
if (member.name === name) {
return {
agility: member.agi,
agilityEquipMult: member.agi_mult,
agilityAscensionMult: member.agi_asc_mult,
augmentations: member.augmentations.slice(),
charisma: member.cha,
charismaEquipMult: member.cha_mult,
charismaAscensionMult: member.cha_asc_mult,
defense: member.def,
defenseEquipMult: member.def_mult,
defenseAscensionMult: member.def_asc_mult,
dexterity: member.dex,
dexterityEquipMult: member.dex_mult,
dexterityAscensionMult: member.dex_asc_mult,
equipment: member.upgrades.slice(),
hacking: member.hack,
hackingEquipMult: member.hack_mult,
hackingAscensionMult: member.hack_asc_mult,
strength: member.str,
strengthEquipMult: member.str_mult,
strengthAscensionMult: member.str_asc_mult,
task: member.task.name,
}
}
}
workerScript.log(`Invalid argument passed to gang.getMemberInformation(). No gang member could be found with name ${name}`);
return {}; // Member could not be found
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberInformation", e));
}
},
canRecruitMember : function() {
if (workerScript.checkingRam) {
return updateStaticRam("canRecruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 4);
}
updateDynamicRam("canRecruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 4);
nsGang.checkGangApiAccess(workerScript, "canRecruitMember");
try {
return Player.gang.canRecruitMember();
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("canRecruitMember", e));
}
},
recruitMember : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "recruitMember");
try {
return Player.gang.recruitMember(name);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("recruitMember", e));
}
},
getTaskNames : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getTaskNames", CONSTANTS.ScriptGangApiBaseRamCost / 4);
}
updateDynamicRam("getTaskNames", CONSTANTS.ScriptGangApiBaseRamCost / 4);
nsGang.checkGangApiAccess(workerScript, "getTaskNames");
try {
const tasks = Player.gang.getAllTaskNames();
tasks.unshift("Unassigned");
return tasks;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getTaskNames", e));
}
},
setMemberTask : function(memberName, taskName) {
if (workerScript.checkingRam) {
return updateStaticRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "setMemberTask");
try {
for (const member of Player.gang.members) {
if (member.name === memberName) {
return member.assignToTask(taskName);
}
}
workerScript.log(`Invalid argument passed to gang.setMemberTask(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setMemberTask", e));
}
},
getEquipmentNames : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getEquipmentNames", CONSTANTS.ScriptGangApiBaseRamCost / 4);
}
updateDynamicRam("getEquipmentNames", CONSTANTS.ScriptGangApiBaseRamCost / 4);
nsGang.checkGangApiAccess(workerScript, "getEquipmentNames");
try {
return Player.gang.getAllUpgradeNames();
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentNames", e));
}
},
getEquipmentCost : function(equipName) {
if (workerScript.checkingRam) {
return updateStaticRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getEquipmentCost");
try {
return Player.gang.getUpgradeCost(equipName);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentCost", e));
}
},
purchaseEquipment : function(memberName, equipName) {
if (workerScript.checkingRam) {
return updateStaticRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost);
}
updateDynamicRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost);
nsGang.checkGangApiAccess(workerScript, "purchaseEquipment");
try {
for (const member in Player.gang.members) {
if (member.name === memberName) {
return member.buyUpgrade(equipName, Player, Player.gang);
}
}
workerScript.log(`Invalid argument passed to gang.purchaseEquipment(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("purchaseEquipment", e));
}
},
ascendMember : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("ascendMember", CONSTANTS.ScriptGangApiBaseRamCost);
}
updateDynamicRam("ascendMember", CONSTANTS.ScriptGangApiBaseRamCost);
nsGang.checkGangApiAccess(workerScript, "ascendMember");
try {
for (const member in Player.gang.members) {
if (member.name === name) {
return Player.gang.ascendMember(member, workerScript);
}
}
workerScript.log(`Invalid argument passed to gang.ascendMember(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("ascendMember", e));
}
},
setTerritoryWarfare : function(engage) {
if (workerScript.checkingRam) {
return updateStaticRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "setTerritoryWarfare");
try {
if (engage) {
Player.gang.territoryWarfareEngaged = true;
} else {
Player.gang.territoryWarfareEngaged = false;
}
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e));
}
},
getBonusTime : function() {
if (workerScript.checkingRam) { return 0; }
nsGang.checkGangApiAccess(workerScript, "getBonusTime");
try {
return Math.round(Player.gang.storedCycles / 5);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getBonusTime", e));
}
},
}, // end gang namespace
// Bladeburner API
bladeburner : { bladeburner : {
getContractNames : function() { getContractNames : function() {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {

15
src/NetscriptGang.js Normal file

@ -0,0 +1,15 @@
import {Player} from "./Player";
import {Gang} from "./Gang";
import {makeRuntimeRejectMsg} from "./NetscriptEvaluator";
export function unknownGangApiExceptionMessage(functionName, err) {
return `gang.${functionName}() failed with exception: ` + err;
}
export function checkGangApiAccess(workerScript, functionName) {
const accessDenied = `gang.${functionName}() failed because you do not currently have a Gang`;
const hasAccess = Player.gang instanceof Gang;
if (!hasAccess) {
throw makeRuntimeRejectMsg(workerScript, accessDenied);
}
}

0
src/Player.js Executable file → Normal file

@ -314,8 +314,8 @@ function prestigeSourceFile() {
stockMarketList.removeChild(stockMarketList.firstChild); stockMarketList.removeChild(stockMarketList.firstChild);
} }
if (Player.inGang()) { Player.gang.clearUI(); }
Player.gang = null; Player.gang = null;
deleteGangDisplayContent();
Player.corporation = null; Player.corporation = null;
Player.bladeburner = null; Player.bladeburner = null;

@ -219,7 +219,8 @@ function scriptEditorInit() {
}); });
//Get functions from namespaces //Get functions from namespaces
if (name === "bladeburner" || name === "hacknet") { const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang"];
if (namespaces.includes(name)) {
let namespace = fns[name]; let namespace = fns[name];
if (typeof namespace !== "object") {continue;} if (typeof namespace !== "object") {continue;}
let namespaceFns = Object.keys(namespace); let namespaceFns = Object.keys(namespace);
@ -557,6 +558,8 @@ async function parseOnlyRamCalculate(server, code, workerScript) {
func = workerScript.env.vars.bladeburner[ref]; func = workerScript.env.vars.bladeburner[ref];
} else if (ref in workerScript.env.vars.codingcontract) { } else if (ref in workerScript.env.vars.codingcontract) {
func = workerScript.env.vars.codingcontract[ref]; func = workerScript.env.vars.codingcontract[ref];
} else if (ref in workerScript.env.vars.gang) {
func = workerScript.env.vars.gang[ref];
} else { } else {
func = workerScript.env.get(ref); func = workerScript.env.get(ref);
} }

16
src/SettingEnums.ts Normal file

@ -0,0 +1,16 @@
/**
* Enum Of allowed values for the 'OwnedAugmentationsOrder' setting
*/
export enum OwnedAugmentationsOrderSetting {
Alphabetically,
AcquirementTime,
}
/**
* Enum Of allowed values for the 'OwnedAugmentationsOrder' setting
*/
export enum PurchaseAugmentationsOrderSetting {
Cost,
Default,
Reputation,
}

@ -1,4 +1,5 @@
import { ISelfInitializer, ISelfLoading } from "./types"; import { ISelfInitializer, ISelfLoading } from "./types";
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
/** /**
* Represents the default settings the player could customize. * Represents the default settings the player could customize.
@ -75,6 +76,16 @@ interface ISettings extends IDefaultSettings {
* TODO: This should really be an enum of allowed values. * TODO: This should really be an enum of allowed values.
*/ */
EditorTheme: string; EditorTheme: string;
/**
* What order the player's owned Augmentations/Source Files should be displayed in
*/
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting;
/**
* What order the Augmentations should be displayed in when purchasing from a Faction
*/
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting;
} }
const defaultSettings: IDefaultSettings = { const defaultSettings: IDefaultSettings = {
@ -104,6 +115,8 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
Locale: "en", Locale: "en",
MaxLogCapacity: defaultSettings.MaxLogCapacity, MaxLogCapacity: defaultSettings.MaxLogCapacity,
MaxPortCapacity: defaultSettings.MaxPortCapacity, MaxPortCapacity: defaultSettings.MaxPortCapacity,
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation, SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
SuppressFactionInvites: defaultSettings.SuppressFactionInvites, SuppressFactionInvites: defaultSettings.SuppressFactionInvites,
SuppressHospitalizationPopup: defaultSettings.SuppressHospitalizationPopup, SuppressHospitalizationPopup: defaultSettings.SuppressHospitalizationPopup,

@ -27,9 +27,9 @@ function initSourceFiles() {
"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 increases the player's crime success rate, crime money, and charisma " +
"multipliers by:<br><br>" + "multipliers by:<br><br>" +
"Level 1: 20%<br>" + "Level 1: 24%<br>" +
"Level 2: 30%<br>" + "Level 2: 36%<br>" +
"Level 3: 35%"); "Level 3: 42%");
SourceFiles["SourceFile3"] = new SourceFile(3,"This Source-File lets you create corporations on other BitNodes (although " + SourceFiles["SourceFile3"] = new SourceFile(3,"This Source-File lets you create corporations on other BitNodes (although " +
"some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" + "some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" +
"Level 1: 8%<br>" + "Level 1: 8%<br>" +
@ -126,7 +126,7 @@ function applySourceFile(srcFile) {
case 2: //Rise of the Underworld case 2: //Rise of the Underworld
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (20 / (Math.pow(2, i))); mult += (24 / (Math.pow(2, i)));
} }
var incMult = 1 + (mult / 100); var incMult = 1 + (mult / 100);
Player.crime_money_mult *= incMult; Player.crime_money_mult *= incMult;

284
src/data/gangmembertasks.ts Normal file

@ -0,0 +1,284 @@
/* tslint:disable:max-line-length */
/**
* Defines the parameters that can be used to initialize and describe a GangMemberTask
* (defined in Gang.js)
*/
export interface IGangMemberTaskMetadata {
/**
* Description of the task
*/
desc: string;
/**
* Whether or not this task is meant for Combat-type gangs
*/
isCombat: boolean;
/**
* Whether or not this task is for Hacking-type gangs
*/
isHacking: boolean;
/**
* Name of the task
*/
name: string;
/**
* An object containing weighting parameters for the task. These parameters are used for
* various calculations (respect gain, wanted gain, etc.)
*/
params?: any;
}
/**
* Array of metadata for all Gang Member tasks. Used to construct the global GangMemberTask
* objects in Gang.js
*/
export const gangMemberTasksMetadata: IGangMemberTaskMetadata[] = [
{
desc: "This gang member is currently idle",
isCombat: true,
isHacking: true,
name: "Unassigned",
params: {hackWeight: 100}, // This is just to get by the weight check in the GangMemberTask constructor
},
{
desc: "Assign this gang member to create and distribute ransomware<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: false,
isHacking: true,
name: "Ransomware",
params: {baseRespect: 0.00005, baseWanted: 0.00001, baseMoney: 1, hackWeight: 100, difficulty: 1},
},
{
desc: "Assign this gang member to attempt phishing scams and attacks<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: false,
isHacking: true,
name: "Phishing",
params: {baseRespect: 0.00008, baseWanted: 0.001, baseMoney: 2.5, hackWeight: 85, chaWeight: 15, difficulty: 3.5},
},
{
desc: "Assign this gang member to attempt identity theft<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "Identity Theft",
params: {baseRespect: 0.0001, baseWanted: 0.01, baseMoney: 6, hackWeight: 80, chaWeight: 20, difficulty: 5},
},
{
desc: "Assign this gang member to carry out DDoS attacks<br><br>Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "DDoS Attacks",
params: {baseRespect: 0.0004, baseWanted: 0.05, hackWeight: 100, difficulty: 8},
},
{
desc: "Assign this gang member to create and distribute malicious viruses<br><br>Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "Plant Virus",
params: {baseRespect: 0.0006, baseWanted: 0.05, hackWeight: 100, difficulty: 12},
},
{
desc: "Assign this gang member to commit financial fraud and digital counterfeiting<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: false,
isHacking: true,
name: "Fraud & Counterfeiting",
params: {baseRespect: 0.0005, baseWanted: 0.1, baseMoney: 15, hackWeight: 80, chaWeight: 20, difficulty: 20},
},
{
desc: "Assign this gang member to launder money<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "Money Laundering",
params: {baseRespect: 0.0006, baseWanted: 0.2, baseMoney: 40, hackWeight: 75, chaWeight: 25, difficulty: 25},
},
{
desc: "Assign this gang member to commit acts of cyberterrorism<br><br>Greatly increases respect - Greatly increases wanted level",
isCombat: false,
isHacking: true,
name: "Cyberterrorism",
params: {baseRespect: 0.001, baseWanted: 0.5, hackWeight: 80, chaWeight: 20, difficulty: 36},
},
{
desc: "Assign this gang member to be an ethical hacker for corporations<br><br>Earns money - Lowers wanted level",
isCombat: false,
isHacking: true,
name: "Ethical Hacking",
params: {baseWanted: -0.001, baseMoney: 1, hackWeight: 90, chaWeight: 10, difficulty: 1},
},
{
desc: "Assign this gang member to mug random people on the streets<br><br>Earns money - Slightly increases respect - Very slightly increases wanted level",
isCombat: true,
isHacking: false,
name: "Mug People",
params: {
baseRespect: 0.00005, baseWanted: 0.00005, baseMoney: 1.2,
strWeight: 25, defWeight: 25, dexWeight: 25, agiWeight: 10, chaWeight: 15,
difficulty: 1,
},
},
{
desc: "Assign this gang member to sell drugs<br><br>Earns money - Slightly increases respect - Slightly increases wanted level - Scales slightly with territory",
isCombat: true,
isHacking: false,
name: "Deal Drugs",
params: {
baseRespect: 0.00006, baseWanted: 0.002, baseMoney: 5,
agiWeight: 20, dexWeight: 20, chaWeight: 60,
difficulty: 3.5,
territory: {
money: 1.2,
respect: 1,
wanted: 1.15,
},
},
},
{
desc: "Assign this gang member to extort civilians in your territory<br><br>Earns money - Slightly increases respect - Increases wanted - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Strongarm Civilians",
params: {
baseRespect: 0.00004, baseWanted: 0.0035, baseMoney: 2.5,
hackWeight: 10, strWeight: 25, defWeight: 25, dexWeight: 20, agiWeight: 10, chaWeight: 10,
difficulty: 5,
territory: {
money: 1.6,
respect: 1.1,
wanted: 1.5
}
}
},
{
desc: "Assign this gang member to run cons<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: true,
isHacking: false,
name: "Run a Con",
params: {
baseRespect: 0.00012, baseWanted: 0.04, baseMoney: 15,
strWeight: 5, defWeight: 5, agiWeight: 25, dexWeight: 25, chaWeight: 40,
difficulty: 14,
},
},
{
desc: "Assign this gang member to commit armed robbery on stores, banks and armored cars<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: true,
isHacking: false,
name: "Armed Robbery",
params: {
baseRespect: 0.00014, baseWanted: 0.08, baseMoney: 38,
hackWeight: 20, strWeight: 15, defWeight: 15, agiWeight: 10, dexWeight: 20, chaWeight: 20,
difficulty: 20,
},
},
{
desc: "Assign this gang member to traffick illegal arms<br><br>Earns money - Increases respect - Increases wanted level - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Traffick Illegal Arms",
params: {
baseRespect: 0.0002, baseWanted: 0.18, baseMoney: 58,
hackWeight: 15, strWeight: 20, defWeight: 20, dexWeight: 20, chaWeight: 25,
difficulty: 32,
territory: {
money: 1.4,
respect: 1.3,
wanted: 1.25,
},
},
},
{
desc: "Assign this gang member to threaten and black mail high-profile targets<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: true,
isHacking: false,
name: "Threaten & Blackmail",
params: {
baseRespect: 0.0002, baseWanted: 0.1, baseMoney: 24,
hackWeight: 25, strWeight: 25, dexWeight: 25, chaWeight: 25,
difficulty: 28,
},
},
{
desc: "Assign this gang member to engage in human trafficking operations<br><br>Earns money - Increases respect - Increases wanted level - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Human Trafficking",
params: {
baseRespect: 0.005, baseWanted: 0.4, baseMoney: 120,
hackWeight: 30, strWeight: 5, defWeight: 5, dexWeight: 30, chaWeight: 30,
difficulty: 36,
territory: {
money: 1.5,
respect: 1.5,
wanted: 1.6,
}
}
},
{
desc: "Assign this gang member to commit acts of terrorism<br><br>Greatly increases respect - Greatly increases wanted level - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Terrorism",
params: {
baseRespect: 0.01, baseWanted: 1.5,
hackWeight: 20, strWeight: 20, defWeight: 20, dexWeight: 20, chaWeight: 20,
difficulty: 36,
territory: {
money: 1,
respect: 2,
wanted: 2,
},
},
},
{
desc: "Assign this gang member to be a vigilante and protect the city from criminals<br><br>Decreases wanted level",
isCombat: true,
isHacking: true,
name: "Vigilante Justice",
params: {
baseWanted: -0.001,
hackWeight: 20, strWeight: 20, defWeight: 20, dexWeight: 20, agiWeight: 20,
difficulty: 1,
territory: {
money: 1,
respect: 1,
wanted: 0.9, // Gets harder with more territory
},
},
},
{
desc: "Assign this gang member to increase their combat stats (str, def, dex, agi)",
isCombat: true,
isHacking: true,
name: "Train Combat",
params: {
strWeight: 25, defWeight: 25, dexWeight: 25, agiWeight: 25,
difficulty: 5
},
},
{
desc: "Assign this gang member to train their hacking skills",
isCombat: true,
isHacking: true,
name: "Train Hacking",
params: {hackWeight: 100, difficulty: 8},
},
{
desc: "Assign this gang member to train their charisma",
isCombat: true,
isHacking: true,
name: "Train Charisma",
params: {chaWeight: 100, difficulty: 8},
},
{
desc: "Assign this gang member to engage in territorial warfare with other gangs. Members assigned to this task will help increase your gang's territory and will defend your territory from being taken.",
isCombat: true,
isHacking: true,
name: "Territory Warfare",
params: {
hackWeight: 15, strWeight: 20, defWeight: 20, dexWeight: 20, agiWeight: 20, chaWeight: 5,
difficulty: 5
},
},
];

@ -0,0 +1,191 @@
/**
* Defines the parameters that can be used to initialize and describe a GangMemberUpgrade
* (defined in Gang.js)
*/
export interface IGangMemberUpgradeMetadata {
cost: number;
mults: any;
name: string;
upgType: string;
}
/**
* Array of metadata for all Gang Member upgrades. Used to construct the global GangMemberUpgrade
* objects in Gang.js
*/
export const gangMemberUpgradesMetadata: IGangMemberUpgradeMetadata[] = [
{
cost: 1e6,
mults: {str: 1.04, def: 1.04},
name: "Baseball Bat",
upgType: "w",
},
{
cost: 12e6,
mults: {str: 1.08, def: 1.08, dex: 1.08},
name: "Katana",
upgType: "w",
},
{
cost: 25e6,
mults: {str: 1.1, def: 1.1, dex: 1.1, agi: 1.1},
name: "Glock 18C",
upgType: "w",
},
{
cost: 50e6,
mults: {str: 1.12, def: 1.12, agi: 1.1},
name: "P90C",
upgType: "w",
},
{
cost: 60e6,
mults: {str: 1.2, def: 1.2},
name: "Steyr AUG",
upgType: "w",
},
{
cost: 100e6,
mults: {str: 1.25, def: 1.25},
name: "AK-47",
upgType: "w",
},
{
cost: 150e6,
mults: {str: 1.3, def: 1.3},
name: "M15A10 Assault Rifle",
upgType: "w",
},
{
cost: 225e6,
mults: {str: 1.3, dex: 1.3, agi: 1.3},
name: "AWM Sniper Rifle",
upgType: "w",
},
{
cost: 2e6,
mults: {def: 1.04},
name: "Bulletproof Vest",
upgType: "a",
},
{
cost: 5e6,
mults: {def: 1.08},
name: "Full Body Armor",
upgType: "a",
},
{
cost: 25e6,
mults: {def: 1.15, agi: 1.15},
name: "Liquid Body Armor",
upgType: "a",
},
{
cost: 40e6,
mults: {def: 1.2},
name: "Graphene Plating Armor",
upgType: "a",
},
{
cost: 3e6,
mults: {agi: 1.04, cha: 1.04},
name: "Ford Flex V20",
upgType: "v",
},
{
cost: 9e6,
mults: {agi: 1.08, cha: 1.08},
name: "ATX1070 Superbike",
upgType: "v",
},
{
cost: 18e6,
mults: {agi: 1.12, cha: 1.12},
name: "Mercedes-Benz S9001",
upgType: "v",
},
{
cost: 30e6,
mults: {agi: 1.16, cha: 1.16},
name: "White Ferrari",
upgType: "v",
},
{
cost: 5e6,
mults: {hack: 1.05},
name: "NUKE Rootkit",
upgType: "r",
},
{
cost: 15e6,
mults: {hack: 1.1},
name: "Soulstealer Rootkit",
upgType: "r",
},
{
cost: 50e6,
mults: {hack: 1.15},
name: "Demon Rootkit",
upgType: "r",
},
{
cost: 10e9,
mults: {str: 1.3, dex: 1.3},
name: "Bionic Arms",
upgType: "g",
},
{
cost: 10e9,
mults: {agi: 1.6},
name: "Bionic Legs",
upgType: "g",
},
{
cost: 15e9,
mults: {str: 1.15, def: 1.15, dex: 1.15, agi: 1.15},
name: "Bionic Spine",
upgType: "g",
},
{
cost: 20e9,
mults: {str: 1.4, def: 1.4},
name: "BrachiBlades",
upgType: "g",
},
{
cost: 12e9,
mults: {str: 1.2, def: 1.2},
name: "Nanofiber Weave",
upgType: "g",
},
{
cost: 25e9,
mults: {str: 1.5, agi: 1.5},
name: "Synthetic Heart",
upgType: "g",
},
{
cost: 15e9,
mults: {str: 1.3, def: 1.3},
name: "Synfibril Muscle",
upgType: "g",
},
{
cost: 5e9,
mults: {hack: 1.05},
name: "BitWire",
upgType: "g",
},
{
cost: 10e9,
mults: {hack: 1.15},
name: "Neuralstimulator",
upgType: "g",
},
{
cost: 50e9,
mults: {str: 1.7, def: 1.7},
name: "Graphene Bone Lacings",
upgType: "g",
},
];

@ -41,8 +41,6 @@ import {FconfSettings} from "./Fconf";
import {displayLocationContent, import {displayLocationContent,
initLocationButtons} from "./Location"; initLocationButtons} from "./Location";
import {Locations} from "./Locations"; import {Locations} from "./Locations";
import {displayGangContent, updateGangContent,
Gang} from "./Gang";
import {displayHacknetNodesContent, processAllHacknetNodeEarnings, import {displayHacknetNodesContent, processAllHacknetNodeEarnings,
updateHacknetNodesContent} from "./HacknetNode"; updateHacknetNodesContent} from "./HacknetNode";
import {iTutorialStart} from "./InteractiveTutorial"; import {iTutorialStart} from "./InteractiveTutorial";
@ -90,6 +88,7 @@ import "../css/loader.scss";
import "../css/missions.scss"; import "../css/missions.scss";
import "../css/companymanagement.scss"; import "../css/companymanagement.scss";
import "../css/bladeburner.scss"; import "../css/bladeburner.scss";
import "../css/gang.scss";
/* Shortcuts to navigate through the game /* Shortcuts to navigate through the game
* Alt-t - Terminal * Alt-t - Terminal
@ -420,7 +419,7 @@ const Engine = {
loadGangContent: function() { loadGangContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
if (document.getElementById("gang-container") || Player.inGang()) { if (document.getElementById("gang-container") || Player.inGang()) {
displayGangContent(); Player.gang.displayGangContent(Player);
routing.navigateTo(Page.Gang); routing.navigateTo(Page.Gang);
} else { } else {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -482,6 +481,9 @@ const Engine = {
document.getElementById("gang-container").style.display = "none"; document.getElementById("gang-container").style.display = "none";
} }
if (Player.inGang()) {
Player.gang.clearUI();
}
if (Player.corporation instanceof Corporation) { if (Player.corporation instanceof Corporation) {
Player.corporation.clearUI(); Player.corporation.clearUI();
} }
@ -522,7 +524,6 @@ const Engine = {
displayCharacterOverviewInfo: function() { displayCharacterOverviewInfo: function() {
Engine.overview.update(); Engine.overview.update();
const save = document.getElementById("character-overview-save-button"); const save = document.getElementById("character-overview-save-button");
const flashClass = "flashing-button"; const flashClass = "flashing-button";
if(!Settings.AutosaveInterval) { if(!Settings.AutosaveInterval) {
@ -887,7 +888,7 @@ const Engine = {
//Gang, if applicable //Gang, if applicable
if (Player.bitNodeN == 2 && Player.inGang()) { if (Player.bitNodeN == 2 && Player.inGang()) {
Player.gang.process(numCycles); Player.gang.process(numCycles, Player);
} }
//Mission //Mission
@ -1004,8 +1005,8 @@ const Engine = {
} }
if (Engine.Counters.updateDisplaysLong <= 0) { if (Engine.Counters.updateDisplaysLong <= 0) {
if (routing.isOn(Page.Gang)) { if (routing.isOn(Page.Gang) && Player.inGang()) {
updateGangContent(); Player.gang.updateGangContent();
} else if (routing.isOn(Page.ScriptEditor)) { } else if (routing.isOn(Page.ScriptEditor)) {
updateScriptEditorContent(); updateScriptEditorContent();
} }
@ -1312,7 +1313,7 @@ const Engine = {
//Gang progress for BitNode 2 //Gang progress for BitNode 2
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) { if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
Player.gang.process(numCyclesOffline); Player.gang.process(numCyclesOffline, Player);
} }
//Bladeburner offline progress //Bladeburner offline progress

@ -65,7 +65,8 @@ function infiltrationBoxCreate(inst) {
var selector = document.getElementById("infiltration-faction-select"); var selector = document.getElementById("infiltration-faction-select");
selector.innerHTML = ""; selector.innerHTML = "";
for (let i = 0; i < Player.factions.length; ++i) { for (let i = 0; i < Player.factions.length; ++i) {
if (Player.factions[i] === "Bladeburners") {continue;} if (Player.factions[i] === "Bladeburners") { continue; }
if (Player.inGang() && Player.gang.facName === Player.factions[i]) { continue; }
selector.innerHTML += "<option value='" + Player.factions[i] + selector.innerHTML += "<option value='" + Player.factions[i] +
"'>" + Player.factions[i] + "</option>"; "'>" + Player.factions[i] + "</option>";
} }

@ -27,4 +27,6 @@ export const KEY: IMap<number> = {
U: 85, U: 85,
UPARROW: 38, UPARROW: 38,
W: 87, W: 87,
"1": 49,
"2": 50,
}; };

@ -66,6 +66,7 @@ interface ICreateElementStyleOptions {
interface ICreateElementTooltipOptions { interface ICreateElementTooltipOptions {
tooltip?: string; tooltip?: string;
tooltipleft?: string; tooltipleft?: string;
tooltipsmall?: string;
} }
/** /**
@ -216,6 +217,12 @@ function setElementTooltip(el: HTMLElement, params: ICreateElementTooltipOptions
class: "tooltiptextleft", class: "tooltiptextleft",
innerHTML: params.tooltipleft, innerHTML: params.tooltipleft,
})); }));
} else if (params.tooltipsmall !== undefined) {
el.className += " tooltip";
el.appendChild(createElement("span", {
class: "tooltiptext smallfont",
innerHTML: params.tooltipsmall,
}))
} }
} }