Merge branch 'ui-enhancements' into dev

Updates:
– Character Overview box (top right corner) – redesigned and added colours to the attributes.
– Added prompt colour in the terminal.
– Minor copy fixes (grammar and typos).
– Code formatting cleanup.
– Character > Stats – Fixed spacing issue when Intelligence is not yet available
– Main Menu – Adjusted the spacing and changed the border to outline to improve the readability.
– Tooltip boxes (Firefox only) – fixed the issue when tooltips were generating additional spacing around the <br> tags.
– Multiple general updates to UI to improve accessibility and readability. Aimed to improve the user experience when playing the game on a smaller screen resolutions.
– Accordion/Dropdown buttons – improved the readability of the plus/minus icons.
– Updated the Augmentations accordion icons as they were barely visible.
– Added .editorconfig with the most basic settings.
This commit is contained in:
Mat Jaworski 2018-08-30 01:51:03 +10:00
commit 70bf0ec944
10 changed files with 232 additions and 169 deletions

13
.editorconfig Normal file

@ -0,0 +1,13 @@
root = true
[*]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
[package.json]
indent_size = 2
[md]
trim_trailing_whitespace = false

@ -1,2 +1,12 @@
$fontFamily: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman';
$defaultFontSize: 16px;
/* COLORS */
$hacky-green: #adff2f;
/* Attributes */
$my-stat-hp-color: #dd3434;
$my-stat-money-color: #ffd700;
$my-stat-hack-color: $hacky-green;
$my-stat-cha-color: #a671d1;
$my-stat-int-color: #6495ed;

@ -22,17 +22,15 @@
#script-editor-container {
background-color: transparent;
}
#javascript-editor {
margin: 10px;
height: 80%;
width: 100%;
margin-left: 6px;
padding-left: 6px;
padding-top: 6px;
padding-bottom: 6px;
border: 2px solid var(--my-highlight-color);
z-index: 1;
font-family: $fontFamily;
@ -101,9 +99,7 @@
resize: none;
color: #fff;
margin: 4px;
padding: 2px;
border: 2px solid var(--my-highlight-color);
}
@ -225,15 +221,15 @@
.active-scripts-script-header:after {
content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125;
color: var(--my-font-color);
float: right;
margin-left: 5px;
color: transparent;
text-shadow: 0 0 0 var(--my-font-color);
}
.active-scripts-script-header.active:after {
content: "\2796"; /* "minus" sign (-) */
font-size: $defaultFontSize * 0.8125;
color: var(--my-font-color);
float: right;
margin-left: 5px;
}
@ -244,16 +240,13 @@
width: auto;
display: none;
margin-bottom: 6px;
}
.active-scripts-script-panel p,
.active-scripts-script-panel h2,
.active-scripts-script-panel ul,
.active-scripts-script-panel li {
p, h2, ul, li {
background-color: #555;
width: auto;
color: #fff;
margin-left: 5%;
}
}
.active-scripts-button {
@ -266,13 +259,13 @@
margin: 4px;
padding: 4px;
background-color: #000;
}
.active-scripts-button:hover,
.active-scripts-button:focus {
&:hover,
&:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
}
/* Hacknet Nodes */
@ -291,6 +284,16 @@
float: left;
overflow: hidden;
white-space: nowrap;
&.hacknet-node {
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
margin: 6px;
padding: 7px;
width: 35vw;
border: 2px solid var(--my-highlight-color);
}
}
#hacknet-nodes-list {
@ -316,34 +319,24 @@
display: inline-block;
}
.hacknet-node {
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
margin: 6px;
padding: 6px;
width: 34vw;
border: 2px solid var(--my-highlight-color);
}
.hacknet-node-container {
display: inline-table;
}
.hacknet-node-container .row {
.row {
display: table-row;
height: 30px;
}
.hacknet-node-container .row p {
p {
display: table-cell;
}
}
}
.hacknet-node-container .upgradable-info {
.upgradable-info {
display: inline-block;
margin: 0 4px; /* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: $defaultFontSize * 4;
}
}
.menu-page-text {
@ -426,17 +419,14 @@
}
/* Faction Augmentations */
#faction-augmentations-container{
#faction-augmentations-container {
position: fixed;
padding-top: 10px;
}
#faction-augmentations-container p,
#faction-augmentations-container a,
#faction-augmentations-container ul,
#faction-augmentations-container h1{
p, a, ul, h1 {
margin: 8px;
padding: 4px;
}
}
/* World */
@ -451,11 +441,20 @@
padding-top: 10px;
}
.augmentations-list button,
.augmentations-list div {
.augmentations-list {
button,
div {
color: var(--my-font-color);
padding: 8px;
text-decoration: none;
}
button {
padding: 2px 5px;
}
div {
padding: 6px;
}
}
/* Tutorial */
@ -510,11 +509,12 @@
padding: 6px;
}
#location-container * {
#location-container > * {
margin: 10px 5px 10px 5px;
}
#location-job-reputation, #location-company-favor {
#location-job-reputation,
#location-company-favor {
display: inline;
}
@ -523,6 +523,7 @@
position: fixed;
padding: 6px;
}
#infiltration-left-panel,
#infiltration-right-panel {
display: inline-block;
@ -552,6 +553,7 @@
#stock-market-container {
position: fixed;
padding: 6px;
p {
font-size: $defaultFontSize * 0.8125;
}
@ -559,9 +561,9 @@
font-size: $defaultFontSize * 0.875;
}
h2 {
margin-top:10px;
margin-left:10px;
display:block;
margin-top: 10px;
margin-left: 10px;
display: block;
}
}
@ -583,8 +585,8 @@
}
#stock-market-watchlist-filter {
width:50%;
margin-left:10px;
width: 50%;
margin-left: 10px;
}
.stock-market-input {

@ -8,8 +8,8 @@
z-index: 10; /* Sit on top */
left: 0;
top: 0;
align-items:center;
justify-content:center;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
overflow: auto;
@ -21,7 +21,7 @@
padding: 12px;
border: 5px solid var(--my-highlight-color);
width: 70%;
max-height:80%;
max-height: 80%;
/*
margin: auto;
height:auto;
@ -32,7 +32,7 @@
bottom:0;
right:0;
*/
overflow-y:auto;
overflow-y: auto;
color: var(--my-font-color);
}
@ -158,8 +158,8 @@
border: 5px solid var(--my-highlight-color);
color: var(--my-font-color);
width: 80%;
max-height:80%;
overflow-y:auto;
max-height: 80%;
overflow-y: auto;
}
#game-options-left-panel,

@ -3,10 +3,11 @@
@import "reset";
:root{
:root {
--my-font-color: #6f3;
--my-background-color: #000;
--my-highlight-color: #fff;
--my-prompt-color: #f92672;
}
body {
@ -83,7 +84,7 @@ tr:focus {
display: block;
color: #e6e6e6;
background-color: #555;
padding: 16px;
padding: 12px 8px;
text-decoration: none;
}
@ -105,21 +106,36 @@ tr:focus {
background-color: #aaa;
}
#hacking-menu-header-li,
#character-menu-header-li,
#world-menu-header-li,
#help-menu-header-li {
position: relative;
}
/* Accordion Outline */
.mainmenu-accordion-header {
outline: 2px solid #fff;
}
/* Plus and minus signs */
.mainmenu-accordion-header:after {
content: '\02795';
font-size: $defaultFontSize * 0.8125;
color: #fff;
float: right;
margin-left: 5px;
}
.mainmenu-accordion-header.opened:after {
content: "\2796";
font-size: $defaultFontSize * 0.8125;
position: absolute;
bottom: 25%;
right: 3px;
color: transparent;
text-shadow: 0 0 0 #fff;
}
.mainmenu-accordion-header.opened {
background-color: #222;
&:after {
content: "\2796";
}
}
/* Slide down transition */
@ -129,11 +145,6 @@ tr:focus {
transition: max-height 0.2s ease-out;
}
/* Borders */
.mainmenu-accordion-header {
border: 2px solid #fff;
}
/* Make html links ("a" elements) nice looking buttons with this class */
a:link,
a:visited {
@ -144,7 +155,7 @@ a:visited {
text-decoration: none;
background-color: #555;
color: #fff;
padding: 5px;
padding: 3px 5px;
margin: 5px;
border: 1px solid #333;
@ -167,7 +178,7 @@ a:visited {
text-decoration: none;
background-color: #333;
color: #fff;
padding: 5px;
padding: 3px 5px;
margin: 5px;
border: 1px solid #333;
cursor: default;
@ -188,7 +199,7 @@ a:visited {
text-decoration: none;
background-color: #0a0;
color: #fff;
padding: 5px;
padding: 3px 5px;
margin: 5px;
border: 1px solid #0a0;
cursor: default;
@ -218,9 +229,9 @@ a:visited {
#create-program-tab {
position: relative;
}
#create-program-notification {
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
@ -364,7 +375,7 @@ a:visited {
/* Blinking Cursor */
/* ----- blinking cursor animation ----- */
.typed-cursor{
.typed-cursor {
opacity: 1;
-webkit-animation: blink 0.95s infinite;
-moz-animation: blink 0.95s infinite;
@ -400,16 +411,16 @@ a:visited {
}
/* Status text */
@-webkit-keyframes status-text{
from{
@-webkit-keyframes status-text {
from {
opacity: 1;
}
to{
to {
opacity: 0;
}
}
.status-text{
.status-text {
display: inline-block;
height: 15%;
position: fixed;
@ -437,47 +448,78 @@ a:visited {
#character-overview-wrapper {
position: relative;
}
#character-overview-container {
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: auto; /* Full height */
padding: 8px;
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: 19%;
width: auto;
max-width: 280px;
overflow: auto; /* Enable scroll if needed */
background-color: #444; /* Fallback color */
background-color: #393636; /* Fallback color */
z-index: 1;
}
#character-overview-text {
color: #fff;
background-color: #444;
color: #faffdf;
table {
border-collapse: collapse;
margin: auto;
}
td {
padding: 2px;
vertical-align: middle;
}
}
.character-stat-text {
color: #fff;
background-color: #444;
}
.character-stat-cell {
.character-stat-cell {
text-align: right;
}
#character-hack-wrapper td,
#character-agi-wrapper td {
border-bottom: 1px #aaa solid;
padding-bottom: 10px;
}
#character-str-wrapper td,
#character-cha-wrapper td {
padding-top: 10px;
}
#character-hp-wrapper { color: $my-stat-hp-color; }
#character-money-wrapper { color: $my-stat-money-color; }
#character-hack-wrapper { color: $my-stat-hack-color; }
#character-cha-wrapper { color: $my-stat-cha-color; }
#character-int-wrapper { color: $my-stat-int-color; }
#character-overview-save-button,
#character-overview-options-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
color: #cecece;
display: inline-block;
font-size: $defaultFontSize * 0.875;
font-weight: bold;
height: 22px;
height: 25px;
background-color: #000;
padding: 5px 8px;
}
.character-quick-options {
padding-top: 5px;
margin-top: 10px;
text-align: center;
}
#character-overview-save-button:hover,
@ -489,16 +531,13 @@ a:visited {
cursor: pointer;
}
#character-overview-options-button {
display: inline;
}
/* Scan analyze links from AutoLink */
.scan-analyze-link {
cursor: pointer;
color: #fff;
text-decoration: underline;
}
.scan-analyze-link:hover {
text-decoration: none;
}
@ -509,37 +548,38 @@ a:visited {
font-size: $defaultFontSize * 1.25;
color: #fff;
margin: 6px 6px 0 6px;
padding: 6px;
padding: 4px 6px;
cursor: pointer;
width: 80%;
text-align: left;
border: none;
outline: none;
}
position: relative;
.accordion-header.active,
.accordion-header:hover {
&.active,
&:hover {
background-color: #555;
}
}
.accordion-header.active:hover {
&.active:hover {
background-color: #666;
}
}
.accordion-header:after {
&:after {
content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125;
color: #fff;
float: right;
margin-left: 5px;
}
color: transparent;
text-shadow: 0 0 0 #fff;
position: absolute;
bottom: 3px;
right: 6px;
}
.accordion-header.active:after {
&.active:after {
content: "\2796"; /* "minus" sign (-) */
font-size: $defaultFontSize * 0.8125;
color: #fff;
float: right;
margin-left: 5px;
}
}
.accordion-panel {
@ -551,13 +591,10 @@ a:visited {
background-color: #555;
overflow-y: auto;
overflow-x: none;
}
.accordion-panel div,
.accordion-panel ul,
.accordion-panel p,
.accordion-panel ul > li {
div, ul, p, ul > li {
background-color: #555;
}
}
/* override the global <span> styling */

@ -51,6 +51,7 @@
}
#terminal-input-header {
color: var(--my-prompt-color);
white-space: pre;
}

@ -110,7 +110,7 @@
<div id="script-editor-filename-wrapper">
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
</div>
<div id="javascript-editor"></div>
@ -160,7 +160,7 @@
<fieldset>
<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>
</fieldset>
</div> <!-- End script editor options panel -->
@ -171,7 +171,7 @@
<table id="terminal">
<tr id="terminal-input">
<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>
</tr>
</table>
@ -215,7 +215,7 @@
<div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money"></span><br/>
<span>Total Hacknet Node Prodution:</span><span id="hacknet-nodes-total-production"></span>
<span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production"></span>
</p>
<span id="hacknet-nodes-multipliers">
<a id="hacknet-nodes-1x-multiplier" class="a-link-button-inactive"> x1 </a>
@ -452,7 +452,7 @@
<div id="create-program-container" class="generic-menupage-container">
<p id="create-program-page-text">
This page displays any programs that you are able to create. Writing the code for a program takes time, which
can vary based on how complex the program is. If you are working on creating on a program you can cancel
can vary based on how complex the program is. If you are working on creating a program you can cancel
at any time. Your progress will be saved and you can continue later.
</p>
@ -625,9 +625,9 @@
<!-- Slums -->
<p id="location-slums-description">
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... <br><br><br>
In the Slums you can commit crimes to earn money and experience. Crime attempts are not always
other shadowy entities. The city's government and police have neglected this area for years...
<br><br><br>
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.
</p>
<a class="a-link-button tooltip" id="location-slums-shoplift"> Shoplift </a>
@ -744,7 +744,7 @@
<div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content">
<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" />
<span id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </span>
<span id="yes-no-text-input-box-no" class="popup-box-button"> No </span>
</div>
@ -840,8 +840,8 @@
</table>
</div>
<div class="character-quick-options">
<span id="character-overview-save-button"> Save Game </span>
<span id="character-overview-options-button"> Options </span>
<span id="character-overview-save-button">Save Game</span>
<span id="character-overview-options-button">Options</span>
</div>
</div>
</div>
@ -868,7 +868,7 @@
</span>
</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>
</fieldset>
@ -882,7 +882,7 @@
</span>
</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>
</fieldset>
@ -896,7 +896,7 @@
</span>
</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>
</fieldset>
@ -908,7 +908,7 @@
</span>
</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>
</fieldset>
@ -994,7 +994,7 @@
<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="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="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;">
(DEBUG) Delete Active Scripts
@ -1006,7 +1006,7 @@
<a id="debug-soft-reset" class="a-link-button tooltip" style="display:block;width:46%;">
(DEBUG) Soft Reset
<span class="tooltiptext">
Perform a soft reset. Resets everything as if you had just purchased an Augmentation
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
</span>
</a>
</div>

@ -446,7 +446,7 @@ function updateHacknetNodesContent() {
//Update player's money
updateText("hacknet-nodes-player-money", "$" + formatNumber(Player.money.toNumber(), 2));
updateText("hacknet-nodes-total-production", "$" + formatNumber(Player.totalHacknetNodeProduction, 2) + " / second");
updateText("hacknet-nodes-total-production", "$" + formatNumber(Player.totalHacknetNodeProduction, 2) + " / sec");
//Update information in each owned hacknet node
for (var i = 0; i < Player.hacknetNodes.length; ++i) {
@ -548,7 +548,7 @@ function updateHacknetNodeDomElement(nodeObj) {
updateText("hacknet-node-name-" + nodeName, nodeName);
updateText("hacknet-node-total-production-" + nodeName, "$" + formatNumber(nodeObj.totalMoneyGenerated, 2));
updateText("hacknet-node-production-rate-" + nodeName, "($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / second)");
updateText("hacknet-node-production-rate-" + nodeName, "($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / sec)");
updateText("hacknet-node-level-" + nodeName, nodeObj.level);
updateText("hacknet-node-ram-" + nodeName, nodeObj.ram + "GB");
updateText("hacknet-node-cores-" + nodeName, nodeObj.cores);

@ -2049,7 +2049,7 @@ PlayerObject.prototype.reapplyAllSourceFiles = function() {
//those requirements and will return an array of all factions that the Player should
//receive an invitation to
PlayerObject.prototype.checkForFactionInvitations = function() {
let invitedFactions = []; //Array which will hold all Factions th eplayer should be invited to
let invitedFactions = []; //Array which will hold all Factions the player should be invited to
var numAugmentations = this.augmentations.length;

@ -570,7 +570,7 @@ let Engine = {
var intText = "";
if (Player.intelligence > 0) {
intText = 'Intelligence: ' + (Player.intelligence).toLocaleString() + "<br><br><br>";
intText = 'Intelligence: ' + (Player.intelligence).toLocaleString() + '<br>';
}
let bitNodeTimeText = "";
@ -584,21 +584,21 @@ let Engine = {
'Current City: ' + Player.city + '<br><br>' +
'Employer: ' + Player.companyName + '<br>' +
'Job Title: ' + companyPosition + '<br><br>' +
'Money: $' + formatNumber(Player.money.toNumber(), 2)+ '<br><br><br>' +
'Money: $' + formatNumber(Player.money.toNumber(), 2) + '<br><br><br>' +
'<b>Stats</b><br><br>' +
'Hacking Level: ' + (Player.hacking_skill).toLocaleString() +
" (" + numeral(Player.hacking_exp).format('(0.000a)') + ' experience)<br>' +
' (' + numeral(Player.hacking_exp).format('(0.000a)') + ' experience)<br>' +
'Strength: ' + (Player.strength).toLocaleString() +
" (" + numeral(Player.strength_exp).format('(0.000a)') + ' experience)<br>' +
' (' + numeral(Player.strength_exp).format('(0.000a)') + ' experience)<br>' +
'Defense: ' + (Player.defense).toLocaleString() +
" (" + numeral(Player.defense_exp).format('(0.000a)')+ ' experience)<br>' +
' (' + numeral(Player.defense_exp).format('(0.000a)')+ ' experience)<br>' +
'Dexterity: ' + (Player.dexterity).toLocaleString() +
" (" + numeral(Player.dexterity_exp).format('(0.000a)') + ' experience)<br>' +
' (' + numeral(Player.dexterity_exp).format('(0.000a)') + ' experience)<br>' +
'Agility: ' + (Player.agility).toLocaleString() +
" (" + numeral(Player.agility_exp).format('(0.000a)') + ' experience)<br>' +
' (' + numeral(Player.agility_exp).format('(0.000a)') + ' experience)<br>' +
'Charisma: ' + (Player.charisma).toLocaleString() +
" (" + numeral(Player.charisma_exp).format('(0.000a)') + ' experience)<br>' +
intText +
' (' + numeral(Player.charisma_exp).format('(0.000a)') + ' experience)<br>' +
intText + '<br><br>' +
'<b>Multipliers</b><br><br>' +
'Hacking Chance multiplier: ' + formatNumber(Player.hacking_chance_mult * 100, 2) + '%<br>' +
'Hacking Speed multiplier: ' + formatNumber(Player.hacking_speed_mult * 100, 2) + '%<br>' +