This commit is contained in:
danielyxie 2018-02-14 22:26:43 -06:00
parent dc26d831d6
commit f82d216e10
16 changed files with 2498 additions and 2266 deletions

@ -609,61 +609,6 @@ div.faction-clear {
padding: 6px;
}
.gang-member-header {
background-color: #444;
font-size: 20px;
color: white;
margin: 6px 6px 0px 6px;
padding: 6px;
cursor: pointer;
width: 80%;
text-align: left;
border: none;
outline: none;
}
.gang-member-header.active,
.gang-member-header:hover {
background-color: #555;
}
.gang-member-header.active:hover {
background-color: #666;
}
.gang-member-header:after {
content: '\02795'; /* "plus" sign (+) */
font-size: 13px;
color: white;
float: right;
margin-left: 5px;
}
.gang-member-header.active:after {
content: "\2796"; /* "minus" sign (-) */
font-size: 13px;
color: white;
float: right;
margin-left: 5px;
}
.gang-member-panel {
margin: 0px 6px 6px 6px;
padding: 0px 6px 6px 6px;
width: 75%;
margin-left: 5%;
display: none;
background-color: #555;
overflow:auto;
}
.gang-member-panel div,
.gang-member-panel ul,
.gang-member-panel p,
.gang-member-panel ul > li {
background-color: #555;
}
#gang-management-subpage > p {
padding: 4px;
}

@ -1,6 +1,3 @@
/** This removes all padding and margins as well as
setting a default font size and family for the page **/
:root{
--my-font-color: #66ff33;
--my-background-color: #000000;

2404
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

@ -248,6 +248,26 @@ exec
exec("foo.script", "foodnstuff", 5, 1, "test");
spawn
^^^^^
.. js:function:: spawn(script, numThreads, [args...])
:param string script: Filename of script to execute
:param number numThreads: Number of threads to spawn new script with. Will be rounded to nearest integer
:param args...:
Additional arguments to pass into the new script that is being run.
Terminates the current script, and then after a delay of about 20 seconds it will execute the newly-specified script.
The purpose of this function is to execute a new script without being constrained by the RAM usage of the current one.
This function can only be used to run scripts on the local server.
Because this function immediately terminates the script, it does not have a return value.
The following example will execute the script 'foo.script' with 10 threads and the arguments 'foodnstuff' and 90::
spawn('foo.script', 10, 'foodnstuff', 90);
kill
^^^^

@ -162,6 +162,25 @@ isBusy
Returns a boolean indicating whether or not the player is currently performing an 'action'. These actions include
working for a company/faction, studying at a univeristy, working out at a gym, creating a program, or committing a crime.
stopAction
----------
.. js:function:: stopAction()
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to run this function.
This function is used to end whatever 'action' the player is currently performing. The player
will receive whatever money/experience/etc. he has earned from that action.
The actions that can be stopped with this function are:
* Studying at a university
* Working for a company/faction
* Creating a program
* Committing a Crime
This function will return true if the player's action was ended. It will return false if the player was not
performing an action when this function was called.
upgradeHomeRam
--------------

@ -135,14 +135,22 @@
</fieldset>
<fieldset>
<label for="script-editor-option-showinvisibles">Show Invisibles</label></td>
<label for="script-editor-option-showinvisibles">Show Invisibles</label>
<input type="checkbox" name="script-editor-option-showinvisibles" id="script-editor-option-showinvisibles">
</fieldset>
<fieldset>
<label for="script-editor-option-usesofttab">Use Soft Tab</label></td>
<label for="script-editor-option-usesofttab">Use Soft Tab</label>
<input type="checkbox" name="script-editor-option-usesofttab" id="script-editor-option-usesofttab" checked>
</fieldset>
<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>
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset>
</div> <!-- End script editor options panel -->
</div>

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.34.3",
Version: "0.34.4",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -49,6 +49,7 @@ let CONSTANTS = {
ScriptPortProgramRamCost: 0.05,
ScriptRunRamCost: 1.0,
ScriptExecRamCost: 1.3,
ScriptSpawnRamCost: 2.0,
ScriptScpRamCost: 0.6,
ScriptKillRamCost: 0.5, //Kill and killall
ScriptHasRootAccessRamCost: 0.05,
@ -502,7 +503,15 @@ let CONSTANTS = {
"The following example will try to run the script 'foo.script' on the 'foodnstuff' server with 5 threads. It will also pass the number 1 and the string 'test' in as arguments " +
"to the script.<br><br>" +
"exec('foo.script', 'foodnstuff', 5, 1, 'test');<br><br>" +
"<i><u>kill(script, hostname/ip, [args...])</u></i><br> Kills the script on the target server specified by the script's name and arguments. Remember that " +
"<i><u>spawn(script, numThreads, [args...])</u></i><br>Terminates the current script, and then after a delay of about 20 seconds " +
"it will execute the newly specified script. The purpose of this function is to execute a new script without being constrained " +
"by the RAM usage of the current one. This function can only be used to run scripts on the local server.<br><br>" +
"The first argument must be a string with the name of the script. The second argument must be an integer specifying the number " +
"of threads to run the script with. Any additional arguments will specify arguments to pass into the 'newly-spawned' script." +
"Because this function immediately terminates the script, it does not have a return value.<br><br>" +
"The following example will execute the script 'foo.script' with 10 threads and the arguments 'foodnstuff' and 90:<br><br>" +
"spawn('foo.script', 10, 'foodnstuff', 90);<br><br>" +
"<i><u>kill(script, hostname/ip, [args...])</u></i><br>Kills the script on the target server specified by the script's name and arguments. Remember that " +
"scripts are uniquely identified by both their name and arguments. For example, if 'foo.script' is run with the argument 1, then this is not the " +
"same as 'foo.script' run with the argument 2, even though they have the same code. <br><br>" +
"The first argument must be a string with the name of the script. The name is case-sensitive. " +
@ -902,6 +911,13 @@ let CONSTANTS = {
"function.<br><br>Returns a boolean indicating whether or not the player is currently performing an 'action'. " +
"These actions include working for a company/faction, studying at a univeristy, working out at a gym, " +
"creating a program, or committing a crime.<br><br>" +
"<i><u>stopAction()</u></i><br>If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to " +
"run this function.<br><br>This function is used to end whatever 'action' the player is currently performing. The player " +
"will receive whatever money/experience/etc. he has earned from that action. The actions that can be stopped with this function " +
"are:<br><br> " +
"-Studying at a university<br>-Working for a company/faction<br>-Creating a program<br>-Committing a Crime<br><br> " +
"This function will return true if the player's action was ended. It will return false if the player was not " +
"performing an action when this function was called.<br><br>" +
"<i><u>upgradeHomeRam()</u></i><br>" +
"If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.<br><br>" +
"This function will upgrade amount of RAM on the player's home computer. The cost is the same as if you were to do it manually.<br><br>" +
@ -1113,39 +1129,20 @@ let CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>",
LatestUpdate:
"v0.34.2<br>" +
"-Corporation Management Changes:<br>" +
"---Added advertising mechanics<br>" +
"---Added Industry-specific purchases<br>" +
"---Re-designed employee management UI<br>" +
"---Rebalancing: Made many upgrades/purchases cheaper. Receive more money from investors in early stage. Company valuation is higher after going public<br>" +
"---Multiple bug fixes<br>" +
"-Added rm() Netscript function<br>" +
"-Updated the way script RAM usage is calculated. Now, a function only increases RAM usage the first time it is called. i.e. even if you call hack() multiple times in a script, it only counts against RAM usage once. The same change applies for while/for loops and if conditionals.<br>" +
"-The RAM cost of the following were increased:<br>" +
"---If statements: increased by 0.05GB<br>" +
"---run() and exec(): increased by 0.2GB<br>" +
"---scp(): increased by 0.1GB<br>" +
"---purchaseServer(): increased by 0.25GB<br>" +
"-Note: You may need to re-save all of your scripts in order to re-calculate their RAM usages. Otherwise, it should automatically be re-calculated when you reset/prestige<br>" +
"-The cost to upgrade your home computer's RAM has been increased (both the base cost and the exponential upgrade multiplier)<br>" +
"-The cost of purchasing a server was increased by 10% (it is now $55k per RAM)<br>" +
"-Bug fix: (Hopefully) removed an exploit where you could avoid RAM usage for Netscript function calls by assigning functions to a variable (foo = hack(); foo('helios');)<br>" +
"-Bug fix: (Hopefully) removed an exploit where you could run arbitrary Javascript code using the constructor() method<br>" +
"-Thanks to Github user mateon1 and Reddit users havoc_mayhem and spaceglace for notifying me of the above exploits<br>" +
"-The fileExists() Netscript function now works on text files (.txt). Thanks to Github user devoidfury for this<br><br>" +
"v0.34.3<br>" +
"-Minor balance changes to Corporations: <br>" +
"---Upgrades are generally cheaper and/or have more powerful effects.<br>" +
"---You will receive more funding while your are a private company.<br>" +
"---Product demand decreases at a slower rate.<br>" +
"---Production multiplier for Industries (receives for owning real estate/hardware/robots/etc.) is slightly higher<br>" +
"-Accessing the hacknetnodes array in Netscript now costs 4.0GB of RAM (only counts against RAM usage once)<br>" +
"-Bug Fix: Corporation oustanding shares should now be numeric rather than a string<br>" +
"-Bug Fix: Corporation production now properly calculated for industries that dont produce materials.<br>" +
"-Bug Fix: Gangs should now properly reset when switching BitNodes<br>" +
"-Bug Fix: Corporation UI should now properly reset when you go public<br>"
"v0.34.4<br>" +
"-Added several new features to Gang UI to make it easier to manage your Gang.<br>" +
"-Changed the Gang Member upgrade mechanic. Now, rather than only being able to have " +
"one weapon/armor/vehicle/etc., you can purchase all the upgrades for each Gang member " +
"and their multipliers will stack. To balance this out, the effects (AKA multipliers) of each Gang member upgrade " +
"were reduced.<br>" +
"-Added a new script editor option: Max Error Count. This affects how many approximate lines the script editor will " +
"process (JSHint) for common errors. Increase this option can affect performance<br>" +
"-Game theme colors (set using 'theme' Terminal command) are now saved when re-opening the game<br>" +
"-'download' Terminal command now works on scripts<br>" +
"-Added stopAction() Singularity function and the spawn() Netscript function<br>" +
"-The 'Purchase Augmentations' UI screen will now tell you if you need a certain prerequisite for Augmentations.<br>" +
"-Augmentations with prerequisites can now be purchased as long as their prerequisites are puchased (" +
"before, you had to actually install the prerequisites before being able to purchase)<br>"
}
export {CONSTANTS};

@ -846,7 +846,12 @@ function displayFactionAugmentations(factionName) {
var pElem = document.createElement("p");
aElem.setAttribute("href", "#");
var req = aug.baseRepRequirement * faction.augmentationRepRequirementMult;
if (aug.name != AugmentationNames.NeuroFluxGovernor && (aug.owned || owned)) {
var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) {
aElem.setAttribute("class", "a-link-button-inactive");
pElem.innerHTML = "LOCKED (Requires " + aug.prereqs.join(",") + " as prerequisite(s))";
pElem.style.color = "red";
} else if (aug.name != AugmentationNames.NeuroFluxGovernor && (aug.owned || owned)) {
aElem.setAttribute("class", "a-link-button-inactive");
pElem.innerHTML = "ALREADY OWNED";
} else if (faction.playerReputation >= req) {
@ -901,57 +906,38 @@ function purchaseAugmentationBoxCreate(aug, fac) {
formatNumber(aug.baseCost * fac.augmentationPriceMult, 2) + "?");
}
//Returns a boolean indicating whether the player has the prerequisites for the
//specified Augmentation
function hasAugmentationPrereqs(aug) {
var hasPrereqs = true;
if (aug.prereqs && aug.prereqs.length > 0) {
for (var i = 0; i < aug.prereqs.length; ++i) {
var prereqAug = Augmentations[aug.prereqs[i]];
if (prereqAug == null) {
console.log("ERROR: Invalid prereq Augmentation: " + aug.prereqs[i]);
continue;
}
if (prereqAug.owned === false) {
hasPrereqs = false;
//Check if the aug is purchased
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
if (Player.queuedAugmentations[j].name === prereqAug.name) {
hasPrereqs = true;
break;
}
}
}
}
}
return hasPrereqs;
}
function purchaseAugmentation(aug, fac, sing=false) {
if (aug.name == AugmentationNames.Targeting2 &&
Augmentations[AugmentationNames.Targeting1].owned == false) {
var txt = "You must first install Augmented Targeting I before you can upgrade it to Augmented Targeting II";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.Targeting3 &&
Augmentations[AugmentationNames.Targeting2].owned == false) {
var txt = "You must first install Augmented Targeting II before you can upgrade it to Augmented Targeting III";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.CombatRib2 &&
Augmentations[AugmentationNames.CombatRib1].owned == false) {
var txt = "You must first install Combat Rib I before you can upgrade it to Combat Rib II";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.CombatRib3 &&
Augmentations[AugmentationNames.CombatRib2].owned == false) {
var txt = "You must first install Combat Rib II before you can upgrade it to Combat Rib III";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.GrapheneBionicSpine &&
Augmentations[AugmentationNames.BionicSpine].owned == false) {
var txt = "You must first install a Bionic Spine before you can upgrade it to a Graphene Bionic Spine";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.GrapheneBionicLegs &&
Augmentations[AugmentationNames.BionicLegs].owned == false) {
var txt = "You must first install Bionic Legs before you can upgrade it to Graphene Bionic Legs";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.ENMCoreV2 &&
Augmentations[AugmentationNames.ENMCore].owned == false) {
var txt = "You must first install Embedded Netburner Module Core Implant before you can upgrade it to V2";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.ENMCoreV3 &&
Augmentations[AugmentationNames.ENMCoreV2].owned == false) {
var txt = "You must first install Embedded Netburner Module Core V2 Upgrade before you can upgrade it to V3";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if ((aug.name == AugmentationNames.ENMCore ||
aug.name == AugmentationNames.ENMAnalyzeEngine ||
aug.name == AugmentationNames.ENMDMA) &&
Augmentations[AugmentationNames.ENM].owned == false) {
var txt = "You must first install the Embedded Netburner Module before installing any upgrades to it";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if ((aug.name == AugmentationNames.PCDNIOptimizer ||
aug.name == AugmentationNames.PCDNINeuralNetwork) &&
Augmentations[AugmentationNames.PCDNI].owned == false) {
var txt = "You must first install the Pc Direct-Neural Interface before installing this upgrade";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.GrapheneBrachiBlades &&
Augmentations[AugmentationNames.BrachiBlades].owned == false) {
var txt = "You must first install the Brachi Blades augmentation before installing this upgrade";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (aug.name == AugmentationNames.GrapheneBionicArms &&
Augmentations[AugmentationNames.BionicArms].owned == false) {
var txt = "You must first install the Bionic Arms augmentation before installing this upgrade";
var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) {
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
"purchase this one.";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (Player.money.gte(aug.baseCost * fac.augmentationPriceMult)) {
if (Player.firstAugPurchased === false) {
@ -974,7 +960,8 @@ function purchaseAugmentation(aug, fac, sing=false) {
var nextLevel = getNextNeurofluxLevel();
--nextLevel;
var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
aug.setRequirements(500 * mult, 750000 * mult);
aug.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
aug.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) {
aug.baseCost *= CONSTANTS.MultipleAugMultiplier;

@ -8,7 +8,8 @@ import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js";
import {getRandomInt, createElement,
removeChildrenFromElement,
createAccordionElement} from "../utils/HelperFunctions.js";
createAccordionElement, createPopup,
removeElementById, removeElement} from "../utils/HelperFunctions.js";
import numeral from "../utils/numeral.min.js";
import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
@ -21,13 +22,14 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
//Switch between territory and management screen with 1 and 2
$(document).keydown(function(event) {
if (Engine.currentPage == Engine.Page.Gang && !yesNoBoxOpen) {
if (gangMemberFilter != null && gangMemberFilter === document.activeElement) {return;}
if (event.keyCode === 49) {
if(document.getElementById("gang-territory-subpage").style.display === "block") {
document.getElementById("gang-management-subpage-button").click();
if(gangTerritorySubpage.style.display === "block") {
managementButton.click();
}
} else if (event.keyCode === 50) {
if (document.getElementById("gang-management-subpage").style.display === "block") {
document.getElementById("gang-territory-subpage-button").click();
if (gangManagementSubpage.style.display === "block") {
territoryButton.click();
}
}
}
@ -35,15 +37,16 @@ $(document).keydown(function(event) {
//Delete upgrade box when clicking outside
$(document).mousedown(function(event) {
var boxId = "gang-member-upgrade-popup-box";
var contentId = "gang-member-upgrade-popup-box-content";
if (gangMemberUpgradeBoxOpened) {
if ( $(event.target).closest("#gang-purchase-upgrade-container").get(0) == null ) {
if ( $(event.target).closest("#" + contentId).get(0) == null ) {
//Delete the box
var container = document.getElementById("gang-purchase-upgrade-container");
while(container.firstChild) {
container.removeChild(container.firstChild);
}
container.parentNode.removeChild(container);
removeElement(gangMemberUpgradeBox);
gangMemberUpgradeBox = null;
gangMemberUpgradeBoxContent = null;
gangMemberUpgradeBoxOpened = false;
gangMemberUpgradeBoxElements = null;
}
}
});
@ -310,12 +313,6 @@ function GangMember(name) {
this.task = GangMemberTasks["Unassigned"]; //GangMemberTask object
this.city = Player.city;
//Name of upgrade only
this.weaponUpgrade = null;
this.armorUpgrade = null;
this.vehicleUpgrade = null;
this.hackingUpgrade = null;
this.hack = 1;
this.str = 1;
this.def = 1;
@ -363,7 +360,7 @@ GangMember.prototype.assignToTask = function(taskName) {
if (GangMemberTasks.hasOwnProperty(taskName)) {
this.task = GangMemberTasks[taskName];
} else {
console.log("ERROR: Invalid task " + taskName);
this.task = GangMemberTasks["Unassigned"];
this.task = null;
}
}
@ -490,7 +487,7 @@ Reviver.constructors.GangMemberTask = GangMemberTask;
//TODO Human trafficking and an equivalent hacking crime
let GangMemberTasks = {
"Unassigned" : new GangMemebrTask(
"Unassigned" : new GangMemberTask(
"Unassigned",
"This gang member is currently idle"),
"Ransomware" : new GangMemberTask(
@ -617,10 +614,11 @@ let GangMemberTasks = {
}
function GangMemberUpgrade(name="", desc="", cost=0) {
function GangMemberUpgrade(name="", desc="", cost=0, type="w") {
this.name = name;
this.desc = desc;
this.cost = cost;
this.type = type; //w, a, v, r
}
//Passes in a GangMember object
@ -641,7 +639,7 @@ GangMemberUpgrade.prototype.apply = function(member) {
member.dex_mult *= 1.15;
member.agi_mult *= 1.15;
break;
case "P90":
case "P90C":
member.str_mult *= 1.2;
member.def_mult *= 1.2;
member.agi_mult *= 1.1;
@ -674,7 +672,7 @@ GangMemberUpgrade.prototype.apply = function(member) {
member.agi_mult *= 1.25;
break;
case "Graphene Plating Armor":
member.def_mult *= 5;
member.def_mult *= 1.5;
break;
case "Ford Flex V20":
member.agi_mult *= 1.1;
@ -707,49 +705,6 @@ GangMemberUpgrade.prototype.apply = function(member) {
}
}
//Purchases for given member
GangMemberUpgrade.prototype.purchase = function(memberObj) {
if (Player.money.lt(this.cost)) {
dialogBoxCreate("You do not have enough money to purchase this upgrade");
return;
}
Player.loseMoney(this.cost);
switch (this.type) {
case "w":
if (memberObj.weaponUpgrade instanceof GangMemberUpgrade) {
memberObj.weaponUpgrade.apply(memberObj, true); //Unapply old upgrade
}
this.apply(memberObj, false);
memberObj.weaponUpgrade = this;
break;
case "a":
if (memberObj.armorUpgrade instanceof GangMemberUpgrade) {
memberObj.armorUpgrade.apply(memberObj, true); //Unapply old upgrade
}
this.apply(memberObj, false);
memberObj.armorUpgrade = this;
break;
case "v":
if (memberObj.vehicleUpgrade instanceof GangMemberUpgrade) {
memberObj.vehicleUpgrade.apply(memberObj, true); //Unapply old upgrade
}
this.apply(memberObj, false);
memberObj.vehicleUpgrade = this;
break;
case "r":
if (memberObj.hackingUpgrade instanceof GangMemberUpgrade) {
memberObj.hackingUpgrade.apply(memberObj, true); //Unapply old upgrade
}
this.apply(memberObj, false);
memberObj.hackingUpgrade = this;
break;
default:
console.log("ERROR: GangMemberUpgrade has invalid type: " + this.type);
break;
}
createGangMemberUpgradeBox(memberObj);
}
GangMemberUpgrade.prototype.toJSON = function() {
return Generic_toJSON("GangMemberUpgrade", this);
}
@ -762,166 +717,203 @@ Reviver.constructors.GangMemberUpgrade = GangMemberUpgrade;
let GangMemberUpgrades = {
"Baseball Bat" : new GangMemberUpgrade("Baseball Bat",
"Increases strength and defense by 5%", 1e6),
"Increases strength and defense by 5%", 1e6, "w"),
"Katana" : new GangMemberUpgrade("Katana",
"Increases strength, defense, and dexterity by 10%", 12e6),
"Increases strength, defense, and dexterity by 10%", 12e6, "w"),
"Glock 18C" : new GangMemberUpgrade("Glock 18C",
"Increases strength, defense, dexterity, and agility by 15%", 25e6),
"P90" : new GangMemberUpgrade("P90C",
"Increases strength and defense by 20%. Increases agility by 10%", 50e6),
"Increases strength, defense, dexterity, and agility by 15%", 25e6, "w"),
"P90C" : new GangMemberUpgrade("P90C",
"Increases strength and defense by 20%. Increases agility by 10%", 50e6, "w"),
"Steyr AUG" : new GangMemberUpgrade("Steyr AUG",
"Increases strength and defense by 25%", 60e6),
"Increases strength and defense by 25%", 60e6, "w"),
"AK-47" : new GangMemberUpgrade("AK-47",
"Increases strength and defense by 50%", 100e6),
"Increases strength and defense by 50%", 100e6, "w"),
"M15A10 Assault Rifle" : new GangMemberUpgrade("M15A10 Assault Rifle",
"Increases strength and defense by 60%", 150e6),
"Increases strength and defense by 60%", 150e6, "w"),
"AWM Sniper Rifle" : new GangMemberUpgrade("AWM Sniper Rifle",
"Increases strength, dexterity, and agility by 50%", 225e6),
"Increases strength, dexterity, and agility by 50%", 225e6, "w"),
"Bulletproof Vest" : new GangMemberUpgrade("Bulletproof Vest",
"Increases defense by 5%", 2e6),
"Increases defense by 5%", 2e6, "a"),
"Full Body Armor" : new GangMemberUpgrade("Full Body Armor",
"Increases defense by 10%", 5e6),
"Increases defense by 10%", 5e6, "a"),
"Liquid Body Armor" : new GangMemberUpgrade("Liquid Body Armor",
"Increases defense and agility by 25%", 25e6),
"Increases defense and agility by 25%", 25e6, "a"),
"Graphene Plating Armor" : new GangMemberUpgrade("Graphene Plating Armor",
"Increases defense by 50%", 40e6),
"Increases defense by 50%", 40e6, "a"),
"Ford Flex V20" : new GangMemberUpgrade("Ford Flex V20",
"Increases agility and charisma by 10%", 3e6),
"Increases agility and charisma by 10%", 3e6, "v"),
"ATX1070 Superbike" : new GangMemberUpgrade("ATX1070 Superbike",
"Increases agility and charisma by 15%", 9e6),
"Increases agility and charisma by 15%", 9e6, "v"),
"Mercedes-Benz S9001" : new GangMemberUpgrade("Mercedes-Benz S9001",
"Increases agility and charisma by 20%", 18e6),
"Increases agility and charisma by 20%", 18e6, "v"),
"White Ferrari" : new GangMemberUpgrade("White Ferrari",
"Increases agility and charisma by 25%", 30e6),
"Increases agility and charisma by 25%", 30e6, "v"),
"NUKE Rootkit" : new GangMemberUpgrade("NUKE Rootkit",
"Increases hacking by 10%", 5e6),
"Increases hacking by 10%", 5e6, "r"),
"Soulstealer Rootkit" : new GangMemberUpgrade("Soulstealer Rootkit",
"Increases hacking by 20%", 15e6),
"Increases hacking by 20%", 15e6, "r"),
"Demon Rootkit" : new GangMemberUpgrade("Demon Rootkit",
"Increases hacking by 30%", 50e6),
"Increases hacking by 30%", 50e6, "r"),
}
//Create a pop-up box that lets player purchase upgrades
let gangMemberUpgradeBoxOpened = false;
function createGangMemberUpgradeBox(memberObj) {
console.log("Creating gang member upgrade box for " + memberObj.name);
var container = document.getElementById("gang-purchase-upgrade-container");
if (container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
function createGangMemberUpgradeBox(initialFilter="") {
var boxId = "gang-member-upgrade-popup-box";
if (gangMemberUpgradeBoxOpened) {
//Already opened, refreshing
if (gangMemberUpgradeBoxElements == null || gangMemberUpgradeBox == null || gangMemberUpgradeBoxContent == null) {
console.log("ERROR: Refreshing Gang member upgrade box throws error because required elements are null");
return;
}
for (var i = 1; i < gangMemberUpgradeBoxElements.length; ++i) {
removeElement(gangMemberUpgradeBoxElements[i]);
}
gangMemberUpgradeBoxElements = [gangMemberUpgradeBoxFilter];
var filter = gangMemberUpgradeBoxFilter.value.toString();
for (var i = 0; i < Player.gang.members.length; ++i) {
if (Player.gang.members[i].name.indexOf(filter) > -1 || Player.gang.members[i].task.name.indexOf(filter) > -1) {
var newPanel = createGangMemberUpgradePanel(Player.gang.members[i]);
gangMemberUpgradeBoxContent.appendChild(newPanel);
gangMemberUpgradeBoxElements.push(newPanel);
}
}
} else {
var container = document.createElement("div");
container.setAttribute("id", "gang-purchase-upgrade-container");
document.getElementById("entire-game-container").appendChild(container);
container.setAttribute("class", "dialog-box-container");
container.style.display = "block";
//New popup
gangMemberUpgradeBoxFilter = createElement("input", {
type:"text", placeholder:"Filter gang members",
value:initialFilter,
onkeyup:()=>{
var filterValue = gangMemberUpgradeBoxFilter.value.toString();
createGangMemberUpgradeBox(filterValue);
}
});
gangMemberUpgradeBoxElements = [gangMemberUpgradeBoxFilter];
var filter = gangMemberUpgradeBoxFilter.value.toString();
for (var i = 0; i < Player.gang.members.length; ++i) {
if (Player.gang.members[i].name.indexOf(filter) > -1 || Player.gang.members[i].task.name.indexOf(filter) > -1) {
gangMemberUpgradeBoxElements.push(createGangMemberUpgradePanel(Player.gang.members[i]));
}
}
gangMemberUpgradeBox = createPopup(boxId, gangMemberUpgradeBoxElements);
gangMemberUpgradeBoxContent = document.getElementById(boxId + "-content");
gangMemberUpgradeBoxOpened = true;
}
var content = document.createElement("div");
content.setAttribute("class", "dialog-box-content");
content.setAttribute("id", "gang-purchase-upgrade-content");
container.appendChild(content);
var intro = document.createElement("p");
content.appendChild(intro);
intro.innerHTML =
memberObj.name + "<br><br>" +
"A gang member can be upgraded with a weapon, armor, a vehicle, and a hacking rootkit. " +
"For each of these pieces of equipment, a gang member can only have one at a time (i.e " +
"a member cannot have two weapons or two vehicles). Purchasing an upgrade will automatically " +
"replace the member's existing upgrade, if he/she is equipped with one. The existing upgrade " +
"will be lost and will have to be re-purchased if you want to switch back.<br><br>";
//Weapons
var weaponTxt = document.createElement("p");
weaponTxt.style.display = "block";
content.appendChild(weaponTxt);
if (memberObj.weaponUpgrade instanceof GangMemberUpgrade) {
weaponTxt.innerHTML = "Weapons (Current Equip: " + memberObj.weaponUpgrade.name + ")";
} else {
weaponTxt.innerHTML = "Weapons (Current Equip: NONE)";
}
var weaponNames = ["Baseball Bat", "Katana", "Glock 18C", "P90", "Steyr AUG",
"AK-47", "M15A10 Assault Rifle", "AWM Sniper Rifle"];
createGangMemberUpgradeButtons(memberObj, weaponNames, memberObj.weaponUpgrade, content);
content.appendChild(document.createElement("br"));
var armorTxt = document.createElement("p");
armorTxt.style.display = "block";
content.appendChild(armorTxt);
if (memberObj.armorUpgrade instanceof GangMemberUpgrade) {
armorTxt.innerHTML = "Armor (Current Equip: " + memberObj.armorUpgrade.name + ")";
} else {
armorTxt.innerHTML = "Armor (Current Equip: NONE)";
}
var armorNames = ["Bulletproof Vest", "Full Body Armor", "Liquid Body Armor",
"Graphene Plating Armor"];
createGangMemberUpgradeButtons(memberObj, armorNames, memberObj.armorUpgrade, content);
var vehicleTxt = document.createElement("p");
vehicleTxt.style.display = "block";
content.appendChild(vehicleTxt);
if (memberObj.vehicleUpgrade instanceof GangMemberUpgrade) {
vehicleTxt.innerHTML = "Vehicles (Current Equip: " + memberObj.vehicleUpgrade.name + ")";
} else {
vehicleTxt.innerHTML = "Vehicles (Current Equip: NONE)";
}
var vehicleNames = ["Ford Flex V20", "ATX1070 Superbike", "Mercedes-Benz S9001",
"White Ferrari"];
createGangMemberUpgradeButtons(memberObj, vehicleNames, memberObj.vehicleUpgrade, content);
var rootkitTxt = document.createElement("p");
rootkitTxt.style.display = "block";
content.appendChild(rootkitTxt);
if (memberObj.hackingUpgrade instanceof GangMemberUpgrade) {
rootkitTxt.innerHTML = "Rootkits (Current Equip: " + memberObj.hackingUpgrade.name + ")";
} else {
rootkitTxt.innerHTML = "Rootkits (Current Equip: NONE)";
}
var rootkitNames = ["NUKE Rootkit", "Soulstealer Rootkit", "Demon Rootkit"];
createGangMemberUpgradeButtons(memberObj, rootkitNames, memberObj.hackingUpgrade, content);
gangMemberUpgradeBoxOpened = true;
}
function createGangMemberUpgradeButtons(memberObj, upgNames, memberUpgrade, content) {
for (var i = 0; i < upgNames.length; ++i) {
(function() {
var upgrade = GangMemberUpgrades[upgNames[i]];
if (upgrade == null) {
console.log("ERROR: Could not find GangMemberUpgrade object for" + upgNames[i]);
return; //Return inside closure
//Create upgrade panels for each individual Gang Member
function createGangMemberUpgradePanel(memberObj) {
var container = createElement("div", {
border:"1px solid white",
});
var header = createElement("h1", {
innerText:memberObj.name + " (" + memberObj.task.name + ")"
});
container.appendChild(header);
var text = createElement("pre", {
fontSize:"14px", display: "inline-block", width:"20%",
innerText:
"Hack: " + memberObj.hack + " (x" + formatNumber(memberObj.hack_mult, 2) + ")\n" +
"Str: " + memberObj.str + " (x" + formatNumber(memberObj.str_mult, 2) + ")\n" +
"Def: " + memberObj.def + " (x" + formatNumber(memberObj.def_mult, 2) + ")\n" +
"Dex: " + memberObj.dex + " (x" + formatNumber(memberObj.dex_mult, 2) + ")\n" +
"Agi: " + memberObj.agi + " (x" + formatNumber(memberObj.agi_mult, 2) + ")\n" +
"Cha: " + memberObj.cha + " (x" + formatNumber(memberObj.cha_mult, 2) + ")\n",
});
//Already purchased upgrades
var ownedUpgradesElements = [];
for (var i = 0; i < memberObj.upgrades.length; ++i) {
var upg = GangMemberUpgrades[memberObj.upgrades[i]];
if (upg == null) {
console.log("ERR: Could not find this upgrade: " + memberObj.upgrades[i]);
continue;
}
//Skip the currently owned upgrade
if (memberUpgrade instanceof GangMemberUpgrade &&
memberUpgrade.name == upgrade.name) {return;}
//Create button
var btn = document.createElement("a");
btn.innerHTML = upgrade.name + " - $" + numeral(upgrade.cost).format('(0.00a)');
if (Player.money.gte(upgrade.cost)) {
btn.setAttribute("class", "popup-box-button tooltip")
} else {
btn.setAttribute("class", "popup-box-button-inactive tooltip");
}
btn.style.cssFloat = "none";
btn.style.display = "block";
btn.style.margin = "8px";
btn.style.width = "40%";
//Tooltip for upgrade
var tooltip = document.createElement("span");
tooltip.setAttribute("class", "tooltiptext");
tooltip.innerHTML = upgrade.desc;
btn.appendChild(tooltip);
content.appendChild(btn);
btn.addEventListener("click", function() {
upgrade.purchase(memberObj);
var e = createElement("div", {
border:"1px solid white", innerText:memberObj.upgrades[i],
margin:"1px", padding:"1px", tooltip:upg.desc, fontSize:"12px",
});
}()); // Immediate invocation
ownedUpgradesElements.push(e);
}
var ownedUpgrades = createElement("div", {
display:"inline-block", marginLeft:"6px", width:"75%", innerText:"Purchased Upgrades:",
});
for (var i = 0; i < ownedUpgradesElements.length; ++i) {
ownedUpgrades.appendChild(ownedUpgradesElements[i]);
}
container.appendChild(text);
container.appendChild(ownedUpgrades);
container.appendChild(createElement("br", {}));
//Upgrade buttons. Only show upgrades that can be afforded
var weaponUpgrades = [], armorUpgrades = [], vehicleUpgrades = [], rootkitUpgrades = [];
for (var upgName in GangMemberUpgrades) {
if (GangMemberUpgrades.hasOwnProperty(upgName)) {
var upg = GangMemberUpgrades[upgName];
if (Player.money.lt(upg.cost) || memberObj.upgrades.includes(upgName)) {continue;}
switch (upg.type) {
case "w":
weaponUpgrades.push(upg);
break;
case "a":
armorUpgrades.push(upg);
break;
case "v":
vehicleUpgrades.push(upg);
break;
case "r":
rootkitUpgrades.push(upg);
break;
default:
console.log("ERROR: Invalid Gang Member Upgrade Type: " + upg.type);
}
}
}
var weaponDiv = createElement("div", {width:"20%", display:"inline-block",});
var armorDiv = createElement("div", {width:"20%", display:"inline-block",});
var vehicleDiv = createElement("div", {width:"20%", display:"inline-block",});
var rootkitDiv = createElement("div", {width:"20%", display:"inline-block",});
var upgrades = [weaponUpgrades, armorUpgrades, vehicleUpgrades, rootkitUpgrades];
var divs = [weaponDiv, armorDiv, vehicleDiv, rootkitDiv];
for (var i = 0; i < upgrades.length; ++i) {
var upgradeArray = upgrades[i];
var div = divs[i];
for (var j = 0; j < upgradeArray.length; ++j) {
var upg = upgradeArray[j];
(function (upg, div, memberObj) {
div.appendChild(createElement("a", {
innerText:upg.name + " - " + numeral(upg.cost).format("$0.000a"),
class:"a-link-button", margin:"2px", padding:"2px", display:"block",
fontSize:"12px",
tooltip:upg.desc,
clickListener:()=>{
if (Player.money.lt(upg.cost)) {return false;}
Player.loseMoney(upg.cost);
memberObj.upgrades.push(upg.name);
upg.apply(memberObj);
var initFilterValue = gangMemberUpgradeBoxFilter.value.toString();
createGangMemberUpgradeBox(initFilterValue);
return false;
}
}));
})(upg, div, memberObj);
}
}
container.appendChild(weaponDiv);
container.appendChild(armorDiv);
container.appendChild(vehicleDiv);
container.appendChild(rootkitDiv);
return container;
}
//Gang DOM elements
@ -935,8 +927,13 @@ let gangManagementSubpage = null, gangTerritorySubpage = null;
let gangDesc = null, gangInfo = null,
gangRecruitMemberButton = null, gangRecruitRequirementText = null,
gangExpandAllButton = null, gangCollapseAllButton, gangMemberFilter = null,
gangManageEquipmentButton = null,
gangMemberList = null;
//Gang Equipment Upgrade Elements
let gangMemberUpgradeBox = null, gangMemberUpgradeBoxContent = null,
gangMemberUpgradeBoxFilter = null, gangMemberUpgradeBoxElements = null;
//Gang Territory Elements
let gangTerritoryDescText = null, gangTerritoryInfoText = null;
@ -1051,7 +1048,7 @@ function displayGangContent() {
return false;
}
});
gangManagementSubpage.appendChild(recruitGangMemberBtn);
gangManagementSubpage.appendChild(gangRecruitMemberButton);
//Text for how much reputation is required for recruiting next memberList
gangRecruitRequirementText = createElement("p", {color:"red", id:"gang-recruit-requirement-text"});
@ -1060,38 +1057,50 @@ function displayGangContent() {
//Gang Member List management buttons (Expand/Collapse All, select a single member)
gangManagementSubpage.appendChild(createElement("br", {}));
gangExpandAllButton = createElement("a", {
class:"a-link-button", display:"inline-block", margin:"4px", padding:"2px",
class:"a-link-button", display:"inline-block",
innerHTML:"Expand All",
clickListener:()=>{
var allHeaders = gangManagementSubpage.getElementsByClassName("accordion-header");
allHeaders.forEach((hdr)=>{
for (var i = 0; i < allHeaders.length; ++i) {
var hdr = allHeaders[i];
if (!hdr.classList.contains("active")) {
hdr.click();
}
})
}
return false;
}
});
gangCollapseAllButton = createElement("a", {
class:"a-link-button", display:"inline-block", margin:"4px", padding:"2px",
class:"a-link-button", display:"inline-block",
innerHTML:"Collapse All",
clickListener:()=>{
var allHeaders = gangManagementSubpage.getElementsByClassName("accordion-header");
allHeaders.forEach((hdr)=>{
for (var i = 0; i < allHeaders.length; ++i) {
var hdr = allHeaders[i];
if (hdr.classList.contains("active")) {
hdr.click();
}
})
}
return false;
}
});
gangMemberFilter = createElement("input", {
type:"text", placeholder:"Filter gang members",
type:"text", placeholder:"Filter gang members", margin:"5px", padding:"5px",
onkeyup:()=>{
displayGangMemberList();
}
});
gangManageEquipmentButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerHTML:"Manage Equipment",
clickListener:()=>{
createGangMemberUpgradeBox();
}
});
gangManagementSubpage.appendChild(gangExpandAllButton);
gangManagementSubpage.appendChild(gangCollapseAllButton);
gangManagementSubpage.appendChild(gangMemberFilter);
gangManagementSubpage.appendChild(gangManageEquipmentButton);
//Gang Member list
gangMemberList = createElement("ul", {id:"gang-member-list"});
@ -1125,7 +1134,7 @@ function displayGangContent() {
territoryBorder.appendChild(gangTerritoryInfoText);
gangTerritorySubpage.appendChild(territoryBorder);
gangContainer.appendChild(territorySubpage);
gangContainer.appendChild(gangTerritorySubpage);
gangContainer.appendChild(gangManagementSubpage);
document.getElementById("entire-game-container").appendChild(gangContainer);
}
@ -1135,9 +1144,10 @@ function displayGangContent() {
function displayGangMemberList() {
removeChildrenFromElement(gangMemberList);
var members = Player.gang.members;
var filter = gangMemberFilter.value.toString();
for (var i = 0; i < members.length; ++i) {
if (members[i].name.indexOf(filter) > -1) {
if (members[i].name.indexOf(filter) > -1 || members[i].task.name.indexOf(filter) > -1) {
createGangMemberDisplayElement(members[i]);
}
}
@ -1152,19 +1162,19 @@ function updateGangContent() {
gangTerritoryInfoText.innerHTML = "";
for (var gangname in AllGangs) {
if (AllGangs.hasOwnProperty(gangname)) {
var gangInfo = AllGangs[gangname];
var gangTerritoryInfo = AllGangs[gangname];
if (gangname == Player.gang.facName) {
gangTerritoryInfoText.innerHTML += ("<b>" + gangname + "</b><br>(Power: " + formatNumber(gangInfo.power, 6) + "): " +
formatNumber(100*gangInfo.territory, 2) + "%<br><br>");
gangTerritoryInfoText.innerHTML += ("<b>" + gangname + "</b><br>(Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " +
formatNumber(100*gangTerritoryInfo.territory, 2) + "%<br><br>");
} else {
gangTerritoryInfoText.innerHTML += (gangname + "<br>(Power: " + formatNumber(gangInfo.power, 6) + "): " +
formatNumber(100*gangInfo.territory, 2) + "%<br><br>");
gangTerritoryInfoText.innerHTML += (gangname + "<br>(Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " +
formatNumber(100*gangTerritoryInfo.territory, 2) + "%<br><br>");
}
}
}
} else {
//Update information for overall gang
if (gangInfo) {
if (gangInfo instanceof Element) {
var faction = Factions[Player.gang.facName];
var rep;
if (!(faction instanceof Faction)) {
@ -1174,7 +1184,7 @@ function updateGangContent() {
}
removeChildrenFromElement(gangInfo);
gangInfo.appendChild(createElement("p", { //Respect
display:"block",
display:"inline-block",
innerText:"Respect: " + formatNumber(Player.gang.respect, 6) +
" (" + formatNumber(5*Player.gang.respectGainRate, 6) + " / sec)",
tooltip:"Represents the amount of respect your gang has from other gangs and criminal " +
@ -1182,38 +1192,47 @@ function updateGangContent() {
"your gang members will earn, and also determines how much " +
"reputation you are earning with your gang's corresponding Faction."
}));
gangInfo.appendChild(createElement("br", {}));
gangInfo.appendChild(createElement("p", { //Wanted level
display:"block",
display:"inline-block",
innerText:"Wanted Level: " + formatNumber(Player.gang.wanted, 6) +
" (" + formatNumber(5*Player.gang.wantedGainRate, 6) + " / sec)",
tooltip:"Represents how much the gang is wanted by law enforcement. The higher " +
"your gang's wanted level, the harder it will be for your gang members " +
"to make money and earn respect. Note that the minimum wanted level is 1."
}));
gangInfo.appendChild(createElement("br", {}));
var wantedPenalty = (Player.gang.respect) / (Player.gang.respect + Player.gang.wanted);
wantedPenalty = (1 - wantedPenalty) * 100;
gangInfo.appendChild(createElement("p", { //Wanted Level multiplier
display:"block",
display:"inline-block",
innerText:"Wanted Level Penalty: -" + formatNumber(wantedPenalty, 2) + "%",
tooltip:"Penalty for respect and money gain rates due to Wanted Level"
}));
gangInfo.appendChild(createElement("br", {}));
gangInfo.appendChild(createElement("p", { //Money gain rate
display:"block",
display:"inline-block",
innerText:"Money gain rate: $" + formatNumber(5*Player.gang.moneyGainRate, 2) +
" / sec",
}));
gangInfo.appendChild(createElement("br", {}));
var territoryMult = AllGangs[Player.gang.facName].territory;
gangInfo.appendChild(createElement("p", { //Territory multiplier
display:"block",
innerText:"Territory: " + formatNumber(territoryMult * 100, 3),
display:"inline-block",
innerText:"Territory: " + formatNumber(territoryMult * 100, 3) + "%",
tooltip:"The percentage of total territory your Gang controls"
}));
gangInfo.appendChild(createElement("br", {}));
gangInfo.appendChild(createElement("p", { //Faction reputation
display:"block",
display:"inline-block",
innerText:"Faction reputation: " + formatNumber(rep, 3)
}));
gangInfo.appendChild(createElement("br", {}));
} else {
console.log("ERROR: gang-info DOM element DNE");
}
@ -1252,29 +1271,6 @@ function updateGangContent() {
}
}
/*
function setGangMemberClickHandlers() {
//Server panel click handlers
var gangMemberHdrs = document.getElementsByClassName("gang-member-header");
if (gangMemberHdrs == null) {
console.log("ERROR: Could not find Gang Member Headers");
return;
}
for (let i = 0; i < gangMemberHdrs.length; ++i) {
gangMemberHdrs[i].onclick = function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
}
}
*/
//Takes in a GangMember object
function createGangMemberDisplayElement(memberObj) {
if (!gangContentCreated || !Player.inGang()) {return;}
@ -1285,20 +1281,8 @@ function createGangMemberDisplayElement(memberObj) {
hdrText:name,
});
var li = accordion[0];
var hdr = accordion[2];
var gangMemberDiv = accordion[3];
/*
var li = document.createElement("li");
var hdr = document.createElement("button");
hdr.setAttribute("class", "gang-member-header");
hdr.setAttribute("id", name + "-gang-member-hdr");
hdr.innerHTML = name;
//Div for entire panel
var gangMemberDiv = document.createElement("div");
gangMemberDiv.setAttribute("class", "gang-member-panel");
*/
var hdr = accordion[1];
var gangMemberDiv = accordion[2];
//Gang member content divided into 3 panels:
//Stats Panel
@ -1310,22 +1294,6 @@ function createGangMemberDisplayElement(memberObj) {
id:name + "gang-member-stats-text", display:"inline"
});
/*
var statsDiv = document.createElement("div");
statsDiv.setAttribute("id", );
statsDiv.setAttribute("class", "gang-member-info-div");
var statsP = document.createElement("p");
statsP.setAttribute("id", name + "gang-member-stats-text");
statsP.style.display = "inline";
var upgradeButton = document.createElement("a");
upgradeButton.setAttribute("id", name + "gang-member-upgrade-btn");
upgradeButton.setAttribute("class", "popup-box-button");
upgradeButton.style.cssFloat = "left";
upgradeButton.innerHTML = "Purchase Upgrades";
upgradeButton.addEventListener("click", function() {
createGangMemberUpgradeBox(memberObj);
});
*/
statsDiv.appendChild(statsP);
//statsDiv.appendChild(upgradeButton);
@ -1338,15 +1306,7 @@ function createGangMemberDisplayElement(memberObj) {
color:"white", backgroundColor:"black",
id:name + "gang-member-task-selector"
});
/*
var taskDiv = document.createElement("div");
taskDiv.setAttribute("id", name + "gang-member-task");
taskDiv.setAttribute("class", "gang-member-info-div");
var taskSelector = document.createElement("select");
taskSelector.style.color = "white";
taskSelector.style.backgroundColor = "black";
taskSelector.setAttribute("id", name + "gang-member-task-selector");
*/
var tasks = null;
if (Player.gang.isHackingGang) {
tasks = ["---", "Ransomware", "Phishing", "Identity Theft", "DDoS Attacks",
@ -1384,8 +1344,6 @@ function createGangMemberDisplayElement(memberObj) {
}
var gainInfo = createElement("p", {id:name + "gang-member-gain-info"});
/*var gainInfo = document.createElement("p"); //Wanted, respect, reputation, and money gain
gainInfo.setAttribute("id", name + "gang-member-gain-info");*/
taskDiv.appendChild(taskSelector);
taskDiv.appendChild(gainInfo);
@ -1394,18 +1352,8 @@ function createGangMemberDisplayElement(memberObj) {
id:name + "gang-member-task-desc", class:"gang-member-info-div",
width:"30%", display:"inline"
});
/*
var taskDescDiv = document.createElement("div");
taskDescDiv.setAttribute("id", name + "gang-member-task-desc");
taskDescDiv.setAttribute("class", "gang-member-info-div");
*/
var taskDescP = createElement("p", {id: name + "gang-member-task-description", display:"inline"});
/*
var taskDescP = document.createElement("p");
taskDescP.setAttribute("id", name + "gang-member-task-description");
taskDescP.style.display = "inline";
*/
taskDescDiv.appendChild(taskDescP);
statsDiv.style.width = "30%";
@ -1418,12 +1366,8 @@ function createGangMemberDisplayElement(memberObj) {
gangMemberDiv.appendChild(taskDiv);
gangMemberDiv.appendChild(taskDescDiv);
//li.appendChild(hdr);
//li.appendChild(gangMemberDiv);
document.getElementById("gang-member-list").appendChild(li);
gangMemberList.appendChild(li);
setGangMemberTaskDescription(memberObj, taskName); //Initialize description
setGangMemberClickHandlers(); //Reset click handlers
updateGangMemberDisplayElement(memberObj);
}

@ -9,7 +9,7 @@ let TerminalHelpText =
"clear Clear all text on the terminal <br>" +
"cls See 'clear' command <br>" +
"connect [ip/hostname] Connects to a remote server<br>" +
"download [text file] Downloads a text (.txt) file to your computer<br>" +
"download [script/text file] Downloads a script or text file to your computer<br>" +
"free Check the machine's memory (RAM) usage<br>" +
"hack Hack the current machine<br>" +
"help [command] Display this help text, or the help text for a command<br>" +
@ -86,9 +86,8 @@ let HelpTexts = {
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument " +
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To " +
"see which servers can be connected to, use the 'scan' command.",
download: "download [text file]<br>" +
"Downloads a text file to your computer (like your real life computer). Only works on text files, " +
"which are the ones with a .txt extension.",
download: "download [script/text file]<br>" +
"Downloads a script or text file to your computer (like your real life computer).",
free: "free<br>" +
"Display's the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as " +
"how much of it is being used.",

@ -559,6 +559,24 @@ function NetscriptFunctions(workerScript) {
}
return runScriptFromScript(server, scriptname, argsForNewScript, workerScript, threads);
},
spawn : function(scriptname, threads) {
if (workerScript.checkingRam) {
if (workerScript.loadedFns.spawn) {
return 0;
} else {
workerScript.loadedFns.spawn = true;
return CONSTANTS.ScriptSpawnRamCost;
}
}
if (scriptname == null || threads == 1) {
throw makeRuntimeRejectMsg(workerScript, "Invalid scriptname or numThreads argument passed to spawn()");
}
setTimeout(()=>{
NetscriptFunctions(workerScript).run.apply(this, arguments);
}, 20000);
workerScript.scriptRef.log("spawn() will execute " + scriptname + " in 20 seconds");
NetscriptFunctions(workerScript).exit();
},
kill : function(filename,ip) {
if (workerScript.checkingRam) {
if (workerScript.loadedFns.kill) {
@ -2398,6 +2416,24 @@ function NetscriptFunctions(workerScript) {
}
return Player.isWorking;
},
stopAction : function() {
if (workerScript.checkingRam) {
if (workerScript.loadedFns.stopAction) {
return 0;
} else {
workerScript.loadedFns.stopAction = true;
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 10;}
return ramCost;
}
}
if (Player.isWorking) {
var txt = Player.singularityStopWork();
workerScript.scriptRef.log(txt);
return true;
}
return false;
},
upgradeHomeRam() {
if (workerScript.checkingRam) {
if (workerScript.loadedFns.upgradeHomeRam) {

@ -128,6 +128,15 @@ function scriptEditorInit() {
editor.getSession().setUseSoftTabs(softTabChkBox.checked);
};
//Jshint Maxerr
var maxerr = document.getElementById("script-editor-option-maxerr");
var maxerrLabel = document.getElementById("script-editor-option-maxerror-value-label");
maxerrLabel.innerHTML = maxerr.value;
maxerr.onchange = function() {
editor.getSession().$worker.send("changeOptions", [{maxerr:maxerr.value}]);
maxerrLabel.innerHTML = maxerr.value;
}
//Configure some of the VIM keybindings
ace.config.loadModule('ace/keyboard/vim', function(module) {
var VimApi = module.CodeMirror.Vim;
@ -367,6 +376,25 @@ function calculateRamUsage(codeCopy) {
return ramUsage;
}
Script.prototype.download = function() {
var filename = this.filename;
var file = new Blob([this.code], {type: 'text/plain'});
if (window.navigator.msSaveOrOpenBlob) {// IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
} else { // Others
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = this.filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
Script.prototype.toJSON = function() {
return Generic_toJSON("Script", this);
}

@ -8,6 +8,9 @@ let Settings = {
SuppressMessages: false,
SuppressFactionInvites: false,
AutosaveInterval: 60,
ThemeHighlightColor: "#ffffff",
ThemeFontColor: "#66ff33",
ThemeBackgroundColor: "#000000",
}
function loadSettings(saveString) {
@ -81,6 +84,19 @@ function setSettingsLabels() {
document.getElementById("settingsSuppressFactionInvites").onclick = function() {
Settings.SuppressFactionInvites = this.checked;
};
//Theme
if (Settings.ThemeHighlightColor == null || Settings.ThemeFontColor == null || Settings.ThemeBackgroundColor == null) {
console.log("ERROR: Cannot find Theme Settings");
return;
}
if (/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(Settings.ThemeHighlightColor) &&
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(Settings.ThemeFontColor) &&
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(Settings.ThemeBackgroundColor)) {
document.body.style.setProperty('--my-highlight-color', Settings.ThemeHighlightColor);
document.body.style.setProperty('--my-font-color', Settings.ThemeFontColor);
document.body.style.setProperty('--my-background-color', Settings.ThemeBackgroundColor);
}
}
export {Settings, initSettings, setSettingsLabels, loadSettings};

@ -23,6 +23,7 @@ import {findRunningScript, RunningScript,
AllServersMap, Script} from "./Script.js";
import {AllServers, GetServerByHostname,
getServer, Server} from "./Server.js";
import {Settings} from "./Settings.js";
import {SpecialServerIps,
SpecialServerNames} from "./SpecialServerIps.js";
import {TextFile, getTextFile,
@ -401,6 +402,9 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
for (var i = 0; i < currServ.textFiles.length; ++i) {
allPos.push(currServ.textFiles[i].fn);
}
for (var i = 0; i < currServ.scripts.length; ++i) {
allPos.push(currServ.scripts[i].filename);
}
}
return allPos;
}
@ -828,12 +832,19 @@ let Terminal = {
return;
}
var fn = commandArray[1];
var txtFile = getTextFile(fn, s);
if (txtFile !== null) {
txtFile.download();
} else {
post("Error: " + fn + " does not exist");
if (fn.endsWith(".script")) {
for (var i = 0; i < s.scripts.length; ++i) {
if (s.scripts[i].filename === fn) {
return s.scripts[i].download();
}
}
} else if (fn.endsWith(".txt")) {
var txtFile = getTextFile(fn, s);
if (txtFile !== null) {
return txtFile.download();
}
}
post("Error: " + fn + " does not exist");
break;
case "free":
Terminal.executeFreeCommand(commandArray);
@ -1055,7 +1066,7 @@ let Terminal = {
} else {
var executableName = commandArray[1];
//Music player!
//Secret Music player!
if (executableName === "musicplayer") {
post('<iframe src="https://open.spotify.com/embed/user/danielyxie/playlist/1ORnnL6YNvXOracUaUV2kh" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>', false);
return;
@ -1231,38 +1242,44 @@ let Terminal = {
case "theme":
//todo support theme saving
var args = commandArray[1] ? commandArray[1].split(" ") : [];
if(args.length != 1 && args.length != 3) {
if (args.length != 1 && args.length != 3) {
post("Incorrect number of arguments.");
post("Usage: theme [default|muted|solarized] | #[background color hex] #[text color hex] #[highlight color hex]");
}else if(args.length == 1){
} else if(args.length == 1){
var themeName = args[0];
if(themeName == "default"){
if (themeName == "default"){
document.body.style.setProperty('--my-highlight-color',"#ffffff");
document.body.style.setProperty('--my-font-color',"#66ff33");
document.body.style.setProperty('--my-background-color',"#000000");
}else if(themeName == "muted"){
} else if (themeName == "muted"){
document.body.style.setProperty('--my-highlight-color',"#ffffff");
document.body.style.setProperty('--my-font-color',"#66ff33");
document.body.style.setProperty('--my-background-color',"#252527");
}else if(themeName == "solarized"){
} else if (themeName == "solarized"){
document.body.style.setProperty('--my-highlight-color',"#6c71c4");
document.body.style.setProperty('--my-font-color',"#839496");
document.body.style.setProperty('--my-background-color',"#002b36");
}else{
post("Theme not found");
} else {
return post("Theme not found");
}
}else{
Settings.ThemeHighlightColor = document.body.style.getPropertyValue("--my-highlight-color");
Settings.ThemeFontColor = document.body.style.getPropertyValue("--my-font-color");
Settings.ThemeBackgroundColor = document.body.style.getPropertyValue("--my-background-color");
} else {
var inputBackgroundHex = args[0];
var inputTextHex = args[1];
var inputHighlightHex = args[2];
if(/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputBackgroundHex) &&
if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputBackgroundHex) &&
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputTextHex) &&
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputHighlightHex)){
document.body.style.setProperty('--my-highlight-color',inputHighlightHex);
document.body.style.setProperty('--my-font-color',inputTextHex);
document.body.style.setProperty('--my-background-color',inputBackgroundHex);
}else{
post("Invalid Hex Input for theme");
Settings.ThemeHighlightColor = document.body.style.getPropertyValue("--my-highlight-color");
Settings.ThemeFontColor = document.body.style.getPropertyValue("--my-font-color");
Settings.ThemeBackgroundColor = document.body.style.getPropertyValue("--my-background-color");
} else {
return post("Invalid Hex Input for theme");
}
}
break;

@ -126,6 +126,7 @@ function createPopup(id, elems) {
}),
content = createElement("div", {
class:"popup-box-content",
id:id + "-content",
});
for (var i = 0; i < elems.length; ++i) {
@ -133,6 +134,7 @@ function createPopup(id, elems) {
}
container.appendChild(content);
document.getElementById("entire-game-container").appendChild(container);
return container;
}
//Creates both the header and panel element of an accordion and sets the click handler