Re-designed Active Scripts tab. Re-designed growth mechanic to depend on server security. Server growth no longer occurss manually. Bug fixes

This commit is contained in:
Daniel Xie
2017-06-06 16:22:57 -05:00
parent d3fa9f8c6e
commit 1a7a247b4d
12 changed files with 154 additions and 174 deletions

View File

@ -144,27 +144,113 @@ background-color: #555;
padding: 4px;
}
.active-scripts-list > li {
margin: 6px;
width: 70%;
.active-scripts-server-header {
background-color: #444;
font-size: 20px;
color: white;
margin: 6px 6px 0px 6px;
padding: 6px;
cursor: pointer;
width: 60%;
text-align: left;
border: none;
outline: none;
}
.active-scripts-list>li h2{
.active-scripts-server-header.active,
.active-scripts-server-header:hover {
background-color: #555;
}
.active-scripts-server-header.active:hover {
background-color: #666;
}
.active-scripts-server-header:after {
content: '\02795'; /* "plus" sign (+) */
font-size: 13px;
color: white;
float: right;
margin-left: 5px;
}
.active-scripts-server-header.active:after {
content: "\2796"; /* "minus" sign (-) */
font-size: 13px;
color: white;
float: right;
margin-left: 5px;
}
.active-scripts-server-panel {
margin: 0px 6px 6px 6px;
padding: 6px;
width: 55%;
margin-left: 5%;
display: none;
}
.active-scripts-server-panel div,
.active-scripts-server-panel ul,
.active-scripts-server-panel ul > li {
background-color: #555;
}
.active-scripts-script-header {
background-color: #555;
color: #66ff33;
padding-top: 10px;
padding-left: 10px;
background-color: #333;
text-decoration: none;
padding: 4px;
padding-left: 10px;
cursor: pointer;
width: auto;
text-align: left;
border: none;
outline: none;
}
.active-scripts-list>li p {
color: #66ff33;
padding: 10px;
padding-left: 40px;
background-color: #333;
text-decoration: none;
.active-scripts-script-header:hover,
.active-scripts-script-header.active:hover {
background-color: #666;
}
.active-scripts-script-header.active {
background-color: #555;
}
.active-scripts-script-header:after {
content: '\02795'; /* "plus" sign (+) */
font-size: 13px;
color: #66ff33;
float: right;
margin-left: 5px;
}
.active-scripts-script-header.active:after {
content: "\2796"; /* "minus" sign (-) */
font-size: 13px;
color: #66ff33;
float: right;
margin-left: 5px;
}
.active-scripts-script-panel {
padding: 0 18px;
background-color: #555;
width: auto;
display: none;
}
.active-scripts-script-panel p,
.active-scripts-script-panel h2,
.active-scripts-script-panel ul,
.active-scripts-script-panel li {
background-color: #555;
width: auto;
color: white;
margin-left: 5%;
}
/* Hacknet Nodes */
#hacknet-nodes-container {
position: fixed;

View File

@ -59,6 +59,7 @@
<script src="src/InteractiveTutorial.js"></script>
<script src="src/Alias.js"></script>
<script src="src/Message.js"></script>
<script src="src/ActiveScriptsUI.js"></script>
<script src="src/engine.js"></script>
@ -164,8 +165,9 @@
<!-- Active scripts info page -->
<div id="active-scripts-container">
<p id="active-scripts-text"> This page displays a list of all scripts that are currently running across every machine. It also gives
information about their production </p>
<p id="active-scripts-text"> This page displays a list of all of your scripts that are currently running across every machine. It also
provides information about each script's production. The scripts are categorized by the hostname of the servers on which
they are running. </p>
<p id="active-scripts-total-prod"> Total online production rate: </p>
<ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;">
</ul>

View File

@ -11,14 +11,14 @@ CONSTANTS = {
/* Base costs */
BaseCostFor1GBOfRamHome: 40000,
BaseCostFor1GBOfRamServer: 35000, //1 GB of RAM
BaseCostFor1GBOfRamServer: 50000, //1 GB of RAM
BaseCostFor1GBOfRamHacknetNode: 30000,
BaseCostForHacknetNode: 1000,
BaseCostForHacknetNodeCore: 500000,
/* Hacknet Node constants */
HacknetNodeMoneyGainPerLevel: 1.6,
HacknetNodeMoneyGainPerLevel: 1.55,
HacknetNodePurchaseNextMult: 1.42, //Multiplier when purchasing an additional hacknet node
HacknetNodeUpgradeLevelMult: 1.045, //Multiplier for cost when upgrading level
HacknetNodeUpgradeRamMult: 1.28, //Multiplier for cost when upgrading RAM
@ -68,9 +68,10 @@ CONSTANTS = {
ScriptHNUpgCoreRamCost: 0.8,
//Server constants
ServerGrowthRate: 1.0015, //Growth rate
ServerFortifyAmount: 0.002, //Amount by which server's security increases when its hacked
ServerWeakenAmount: 0.1, //Amount by which server's security decreases when weakened
ServerBaseGrowthRate: 1.02, //Unadjusted Growth rate
ServerMaxGrowthRate: 1.003, //Maximum possible growth rate (max rate accounting for server security)
ServerFortifyAmount: 0.002, //Amount by which server's security increases when its hacked/grown
ServerWeakenAmount: 0.1, //Amount by which server's security decreases when weakened
//Augmentation Constants
AugmentationCostMultiplier: 4.5, //Used for balancing costs without having to readjust every Augmentation cost
@ -220,8 +221,8 @@ CONSTANTS = {
"When you successfully hack a server. You steal a certain percentage of that server's total money. This " +
"percentage is determined by the server's security and your hacking skill level. The amount of money " +
"on a server is not limitless. So, if you constantly hack a server and deplete its money, then you will " +
"encounter diminishing returns in your hacking (since you are only hacking a certain percentage). A server " +
"will regain money at a slow rate over time. <br><br>" +
"encounter diminishing returns in your hacking (since you are only hacking a certain percentage). You can " +
"increase the amount of money on a server using a script and the grow() function in Netscript.<br><br>" +
"<h1>Server Security</h1><br>" +
"Each server has a security level, which is denoted by a number between 1 and 100. A higher number means " +
"the server has stronger security. As mentioned above, a server's security level is an important factor " +
@ -229,7 +230,8 @@ CONSTANTS = {
"only gives an estimate (with 5% uncertainty). You can also check a server's security in a script, using the " +
"<i>getServerSecurityLevel(server)</i> function in Netscript. See the Netscript documentation for more details. " +
"This function will give you an exact value for a server's security. <br><br>" +
"Whenever a server is hacked manually or through a script, its security level increases by a small amount. This will " +
"Whenever a server is hacked manually or through a script, its security level increases by a small amount. Calling " +
"the grow() command in a script will also increase security level of the target server. These actions will " +
"make it harder for you to hack the server, and decrease the amount of money you can steal. You can lower a " +
"server's security level in a script using the <i>weaken(server)</i> function in Netscript. See the Netscript " +
"documentation for more details",
@ -305,7 +307,8 @@ CONSTANTS = {
"<i>hack(hostname/ip)</i><br>Core function that is used to try and hack servers to steal money and gain hacking experience. The argument passed in must be a string with " +
"either the IP or hostname of the server you want to hack. The runtime for this command depends on your hacking level and the target server's security level. " +
" A script can hack a server from anywhere. It does not need to be running on the same server to hack that server. " +
"For example, you can create a script that hacks the 'foodnstuff' server and run it on your home computer. <br>" +
"For example, you can create a script that hacks the 'foodnstuff' server and run that script on any server in the game. Calling hack() on " +
"a server will raise that server's security level by " + this.ServerFortifyAmount + ".<br>" +
"Examples: hack('foodnstuff'); or hack('148.192.0.12');<br><br>" +
"<i>sleep(n)</i><br>Suspends the script for n milliseconds. <br>Example: sleep(5000);<br><br>" +
"<i>grow(hostname/ip)</i><br>Use your hacking skills to increase the amount of money available on a server. The argument passed in " +
@ -314,10 +317,12 @@ CONSTANTS = {
"is determined by the server's growth rate and varies between servers. Generally, higher-level servers have higher growth rates. <br><br> " +
"Like hack(), grow() can be called on any server, regardless of where the script is running. " +
"The grow() command requires root access to the target server, but there is no required hacking level to run the command. " +
"It grants 1 hacking exp when it completes. Works offline at a slower rate. <br> Example: grow('foodnstuff');<br><br>" +
"It grants 0.5 hacking exp when it completes. It also raises the security level of the target server by " + (2 * this.ServerFortifyAmount) + ". " +
"Works offline at a slower rate. <br> Example: grow('foodnstuff');<br><br>" +
"<i>weaken(hostname/ip)</i><br>Use your hacking skills to attack a server's security, lowering the server's security level. The argument passed " +
"in must be a string with either the IP or hostname of the target server. The runtime for this command depends on your " +
"hacking level and the target server's security level. <br><br> Like hack() and grow(), weaken() can be called on " +
"hacking level and the target server's security level. This function lowers the security level of the target server by " +
this.ServerWeakenAmount + ".<br><br> Like hack() and grow(), weaken() can be called on " +
"any server, regardless of where the script is running. This command requires root access to the target server, but " +
"there is no required hacking level to run the command. Grants 3 hacking exp when it completes. Works offline at a slower rate<br> Example: weaken('foodnstuff');<br><br>" +
"<i>print(x)</i> <br> Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command )<br><br>" +
@ -532,17 +537,24 @@ CONSTANTS = {
"such as a variable assignment, a function call, a binary operator, getting a variable's value, etc. used to take up to several seconds, " +
"now each one should only take 750 milliseconds). <br> " +
"-Percentage money stolen when hacking lowered to compensate for faster script speeds<br>" +
"-Slightly lowered the runtime of weaken()<br>" +
"-Lowered base growth rate by 25%(which affects amount of money gained from grow())<br>" +
"-Hacking experience granted by grow() halved<b>" +
"-Weaken() is now 10% faster, but only grants 3 base hacking exp upon completion instead of 5 <br>" +
"-Weaken() is now ~11% faster, but only grants 3 base hacking exp upon completion instead of 5 <br>" +
"-Rebalancing of script RAM costs. Base RAM Cost for a script increased from 1GB to 1.5GB. Loops, hack(), grow() " +
"and weaken() all cost slightly less RAM than before <br>" +
"-Added getServerRequiredHackingLevel(server) Netscript command. <br>" +
"-Added fileExists(file, [server]) Netscript command, which is used to check if a script/program exists on a " +
"specified server<br>" +
"-Added isRunning(script, [server]) Netscript command, which is used to check if a script is running on the specified server<br>" +
"-Added killall Terminal command. Kills all running scripts on the current machine<br> " +
"-Added kill() and killall() Netscript commands. Used to kill scripts on specified machines. See Netscript documentation<br>" +
"-Re-designed 'Active Scripts' tab<br>" +
"-Hacknet Node base production rate lowered from 1.6 to 1.55 ($/second)<br>" +
"-Increased monetary cost of RAM (Upgrading home computer and purchasing servers will now be more expensive)<br>" +
"-NEW GROWTH MECHANICS - The rate of growth on a server now depends on a server's security level. A higher security level " +
"will result in lower growth on a server when using the grow() command. Furthermore, calling grow() on a server raises that " +
"server's security level by " + (2 * this.ServerFortifyAmount) + ". For reference, if a server has a security level of 10 " +
"it will have approximately the same growth rate as before. <br>" +
"-Server growth no longer happens naturally<br>" +
"v0.19.7<br>" +
"-Added changelog to Options menu<br>" +
"-Bug fix with autocompletion (wasn't working properly for capitalized filenames/programs<br><br>" +

View File

@ -814,7 +814,7 @@ displayFactionAugmentations = function(factionName) {
pElem.innerHTML = "UNLOCKED - $" + formatNumber(aug.baseCost * faction.augmentationPriceMult, 2);
} else {
aElem.setAttribute("class", "a-link-button-inactive");
pElem.innerHTML = "LOCKED (Requires " + formatNumber(req, 4) + " faction reputation) - $" + formatNumber(aug.baseCost * faction.augmentationPriceMult, 2);
pElem.innerHTML = "LOCKED (Requires " + formatNumber(req, 1) + " faction reputation) - $" + formatNumber(aug.baseCost * faction.augmentationPriceMult, 2);
pElem.style.color = "red";
}
aElem.style.display = "inline";

View File

@ -754,6 +754,7 @@ function evaluateHacknetNode(exp, workerScript) {
reject(makeRuntimeRejectMsg(workerScript, "Invalid argument passed into upgradeLevel()"));
return;
}
arg = Math.round(arg);
var res = nodeObj.purchaseLevelUpgrade(arg);
if (res) {
workerScript.scriptRef.log("Upgraded " + nodeObj.name + " " + arg + " times to level " + nodeObj.level);

View File

@ -151,6 +151,7 @@ function netscriptGrow(exp, workerScript) {
+ formatNumber(growthPercentage*100 - 100, 6) + "%");
var expGain = 0.5 * Player.hacking_exp_mult;
workerScript.scriptRef.log("Gained " + expGain + " hacking experience");
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
return Promise.resolve(growthPercentage);
});
@ -197,6 +198,7 @@ function netscriptWeaken(exp, workerScript) {
workerScript.scriptRef.log("Gained 3 hacking experience");
var expGain = 3 * Player.hacking_exp_mult;
workerScript.scriptRef.log("Gained " + expGain + " hacking experience");
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
return Promise.resolve(CONSTANTS.ServerWeakenAmount);
});

View File

@ -133,12 +133,12 @@ function runScriptsLoop() {
//Free RAM
AllServers[ip].ramUsed -= workerScripts[i].ramUsage;
//Delete script from Active Scripts
deleteActiveScriptsItem(workerScripts[i]);
//Delete script from workerScripts
workerScripts.splice(i, 1);
//Delete script from Active Scripts
Engine.deleteActiveScriptsItem(i);
}
}
@ -171,7 +171,7 @@ function addWorkerScript(script, server) {
s.ramUsage = script.ramUsage;
//Add the WorkerScript to the Active Scripts list
Engine.addActiveScriptsItem(s);
addActiveScriptsItem(s);
//Add the WorkerScript
workerScripts.push(s);

View File

@ -675,52 +675,29 @@ initForeignServers = function() {
}
}
//Server growth
processServerGrowth = function(numCycles) {
//Server growth processed once every 450 game cycles
var numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
for (var ip in AllServers) {
if (AllServers.hasOwnProperty(ip)) {
var server = AllServers[ip];
//Get the number of server growth cycles that will be applied based on the
//server's serverGrowth property
var serverGrowthPercentage = server.serverGrowth / 100;
var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage;
//Apply serverGrowth for the calculated number of growth cycles
var serverGrowth = Math.pow(CONSTANTS.ServerGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult) ;
if (serverGrowth < 1) {
console.log("WARN: serverGrowth calculated to be less than 1");
serverGrowth = 1;
}
//console.log("serverGrowth ratio: " + serverGrowth);
server.moneyAvailable *= serverGrowth;
}
}
console.log("Server growth processed for " + numServerGrowthCycles + " cycles");
}
//Applied server growth for a single server. Returns the percentage growth
processSingleServerGrowth = function(server, numCycles) {
//Server growth processed once every 450 game cycles
var numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
//Get the number of server growth cycles that will be applied based on the
//server's serverGrowth property
//Get adjusted growth rate, which accounts for server security
var growthRate = CONSTANTS.ServerBaseGrowthRate;
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
console.log("Adjusted growth rate: " + adjGrowthRate);
//Calculate adjusted server growth rate based on parameters
var serverGrowthPercentage = server.serverGrowth / 100;
var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage;
//Apply serverGrowth for the calculated number of growth cycles
var serverGrowth = Math.pow(CONSTANTS.ServerGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult) ;
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult) ;
if (serverGrowth < 1) {
console.log("WARN: serverGrowth calculated to be less than 1");
serverGrowth = 1;
}
server.moneyAvailable *= serverGrowth;
server.fortify(2 * CONSTANTS.ServerFortifyAmount);
return serverGrowth;
}

View File

@ -11,6 +11,7 @@ purchaseServer = function(ram, cost) {
var newServ = new Server();
var hostname = document.getElementById("purchase-server-box-input").value;
hostname = hostname.replace(/\s\s+/g, '');
if (hostname == "") {
dialogBoxCreate("You must enter a hostname for your new server!");
return;

View File

@ -412,14 +412,14 @@ var Terminal = {
//Replace all extra whitespace in command with a single space
command = command.replace(/\s\s+/g, ' ');
//Terminal history
if (Terminal.commandHistory[Terminal.commandHistory.length-1] != command) {
Terminal.commandHistory.push(command);
if (Terminal.commandHistory.length > 50) {
Terminal.commandHistory.splice(0, 1);
}
Terminal.commandHistoryIndex = Terminal.commandHistory.length;
}
Terminal.commandHistoryIndex = Terminal.commandHistory.length;
//Process any aliases
command = substituteAliases(command);

View File

@ -116,6 +116,7 @@ var Engine = {
loadActiveScriptsContent: function() {
Engine.hideAllContent();
Engine.Display.activeScriptsContent.style.visibility = "visible";
setActiveScriptsClickHandlers();
Engine.currentPage = Engine.Page.ActiveScripts;
},
@ -334,100 +335,6 @@ var Engine = {
}
},
/* Functions used to update information on the Active Scripts page */
ActiveScriptsList: null,
//Creates and adds the <li> object for a given workerScript
addActiveScriptsItem: function(workerscript) {
var item = document.createElement("li");
Engine.createActiveScriptsText(workerscript, item);
//Add the li element onto the list
if (Engine.ActiveScriptsList == null) {
Engine.ActiveScriptsList = document.getElementById("active-scripts-list");
}
Engine.ActiveScriptsList.appendChild(item);
},
deleteActiveScriptsItem: function(i) {
var list = Engine.ActiveScriptsList.querySelectorAll('#active-scripts-list li');
if (i >= list.length) {
throw new Error("Trying to delete an out-of-range Active Scripts item");
}
var li = list[i];
li.parentNode.removeChild(li);
},
//Update the ActiveScriptsItems array
updateActiveScriptsItems: function() {
var total = 0;
for (var i = 0; i < workerScripts.length; ++i) {
total += Engine.updateActiveScriptsItemContent(i, workerScripts[i]);
}
document.getElementById("active-scripts-total-prod").innerHTML =
"Total online production rate: $" + formatNumber(total, 2) + " / second";
},
//Updates the content of the given item in the Active Scripts list
updateActiveScriptsItemContent: function(i, workerscript) {
var list = Engine.ActiveScriptsList.getElementsByTagName("li");
if (i >= list.length) {
throw new Error("Trying to update an out-of-range Active Scripts Item");
}
var item = list[i];
//Clear the item
while (item.firstChild) {
item.removeChild(item.firstChild);
}
//Add the updated text back. Returns the total online production rate
return Engine.createActiveScriptsText(workerscript, item);
},
createActiveScriptsText: function(workerscript, item) {
//Script name
var scriptName = document.createElement("h2");
scriptName.appendChild(document.createTextNode(workerscript.name));
item.appendChild(scriptName);
var itemText = document.createElement("p");
//Server ip/hostname
var hostname = workerscript.getServer().hostname;
var serverIpHostname = "Server: " + hostname + "(" + workerscript.serverIp + ")";
//Online
var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2);
var onlineTotalExpEarned = (Array(26).join(" ") + formatNumber(workerscript.scriptRef.onlineExpGained, 2) + " hacking exp").replace( / /g, "&nbsp;");
var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime;
var onlineMpsText = "Online production rate: $" + formatNumber(onlineMps, 2) + "/second";
var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime;
var onlineEpsText = (Array(25).join(" ") + formatNumber(onlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;");
//Offline
var offlineTotalMoneyMade = "Total offline production: $" + formatNumber(workerscript.scriptRef.offlineMoneyMade, 2);
var offlineTotalExpEarned = (Array(27).join(" ") + formatNumber(workerscript.scriptRef.offlineExpGained, 2) + " hacking exp").replace( / /g, "&nbsp;");
var offlineMps = workerscript.scriptRef.offlineMoneyMade / workerscript.scriptRef.offlineRunningTime;
var offlineMpsText = "Offline production rate: $" + formatNumber(offlineMps, 2) + "/second";
var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime;
var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;");
itemText.innerHTML = serverIpHostname + "<br>" + onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" +
onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" +
offlineMpsText + "<br>" + offlineEpsText + "<br>";
item.appendChild(itemText);
//Return total online production rate
return onlineMps;
},
displayFactionsInfo: function() {
var factionsList = document.getElementById("factions-list");
@ -599,8 +506,7 @@ var Engine = {
updateSkillLevelsCounter: 10, //Only update skill levels every 2 seconds. Might improve performance
updateDisplays: 3, //Update displays such as Active Scripts display and character display
createProgramNotifications: 10, //Checks whether any programs can be created and notifies
serverGrowth: 450, //Process server growth every minute and a half
checkFactionInvitations: 250, //Check whether you qualify for any faction invitations every 5 minutes
checkFactionInvitations: 250, //Check whether you qualify for any faction invitations every 5 minutes
passiveFactionGrowth: 600,
messages: 300,
},
@ -629,7 +535,7 @@ var Engine = {
if (Engine.Counters.updateDisplays <= 0) {
Engine.displayCharacterOverviewInfo();
if (Engine.currentPage == Engine.Page.ActiveScripts) {
Engine.updateActiveScriptsItems();
updateActiveScriptsItems();
} else if (Engine.currentPage == Engine.Page.CharacterInfo) {
Engine.displayCharacterInfo();
} else if (Engine.currentPage == Engine.Page.HacknetNodes) {
@ -654,12 +560,6 @@ var Engine = {
Engine.Counters.createProgramNotifications = 10;
}
if (Engine.Counters.serverGrowth <= 0) {
var numCycles = Math.floor((450 - Engine.Counters.serverGrowth));
processServerGrowth(numCycles);
Engine.Counters.serverGrowth = 450;
}
if (Engine.Counters.checkFactionInvitations <= 0) {
var invitedFactions = Player.checkForFactionInvitations();
if (invitedFactions.length > 0) {
@ -747,7 +647,6 @@ var Engine = {
var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed);
/* Process offline progress */
processServerGrowth(numCyclesOffline); //Should be done before offline production for scripts
var offlineProductionFromScripts = loadAllRunningScripts(); //This also takes care of offline production for those scripts
if (Player.isWorking) {
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");

View File

@ -36,7 +36,7 @@ purchaseRamForHomeBoxCreate = function() {
//Calculate cost
//Have cost increase by some percentage each time RAM has been upgraded
var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome;
var mult = Math.pow(1.36, numUpgrades);
var mult = Math.pow(1.40, numUpgrades);
cost = cost * mult;
purchaseRamForHomeBoxSetText("Would you like to purchase additional RAM for your home computer? <br><br>" +