diff --git a/css/buttons.scss b/css/buttons.scss
index 7539c33ce..27fb845a9 100644
--- a/css/buttons.scss
+++ b/css/buttons.scss
@@ -99,9 +99,10 @@ button {
background-color: #000;
&:hover,
- &:focus {
+ &:active {
color: #fff;
text-decoration: none;
cursor: pointer;
}
+ /* TODO focus selector? */
}
diff --git a/css/gang.scss b/css/gang.scss
index 7c07ca6f4..c043de5ff 100644
--- a/css/gang.scss
+++ b/css/gang.scss
@@ -9,6 +9,10 @@
position: fixed;
padding: 6px;
+ p, pre {
+ font-size: $defaultFontSize * 0.9375;
+ }
+
select {
background-color: black;
color: white;
@@ -25,3 +29,20 @@
float: left;
width: 30%;
}
+
+/**
+ * Showing owned upgrades in the Equipment Box
+ */
+
+.gang-owned-upgrades-div {
+ display: inline-block;
+ margin-left: 6px;
+ width: 75%;
+}
+
+.gang-owned-upgrade {
+ border: 1px solid white;
+ font-size: 12px;
+ margin: 1px;
+ padding: 1px;
+}
diff --git a/css/styles.scss b/css/styles.scss
index 940620a18..1dfb98033 100644
--- a/css/styles.scss
+++ b/css/styles.scss
@@ -114,6 +114,29 @@ a:visited {
position: absolute;
z-index: 99;
}
+
+ /* Positioned to left of element rather than right */
+ .tooltiptextleft {
+ visibility: hidden;
+ width: 300px;
+ background-color: var(--my-background-color);
+ border: 2px solid var(--my-highlight-color);
+ color: #fff;
+ text-align: center;
+ padding: 4px;
+ top: 50%;
+ left: 50%;
+ transform: translate(-100%, -100%);
+
+ /* Backwards compatibility */
+ -webkit-transform: translate(-100%, -100%);
+ -moz-transform: translate(-100%, -100%);
+ -o-transform: translate(-100%, -100%);
+ -ms-transform: translate(-100%, -100%);
+
+ position: absolute;
+ z-index: 99;
+ }
}
/* Same thing as a normal tooltip except its a bit higher */
@@ -132,23 +155,6 @@ a:visited {
z-index: 99;
}
-/* Similar to a normal tooltip except its positioned on the left of the element
- rather than the right to avoid exceeding the elements normal width */
-.tooltip .tooltiptextleft {
- visibility: hidden;
- width: 300px;
- background-color: var(--my-background-color);
- border: 2px solid var(--my-highlight-color);
- color: #fff;
- text-align: center;
- padding: 4px;
- left: 40%;
- bottom: -10%;
-
- position: absolute;
- z-index: 99;
-}
-
.tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft {
@@ -157,14 +163,14 @@ a:visited {
/* help tip. Question mark that opens popup with info/details */
.help-tip {
- content: '?';
- padding: 1px;
- margin-top: 5px;
- margin-left: 3px;
- color: #fff;
+ background-color: black;
border: 1px solid #fff;
border-radius: 5px;
+ color: #fff;
+ content: '?';
display: inline-block;
+ margin-left: 3px;
+ padding: 1px;
}
.help-tip-big {
@@ -413,7 +419,7 @@ a:visited {
&:after {
content: '\02795'; /* "plus" sign (+) */
- font-size: $defaultFontSize * 0.8125;
+ font-size: $defaultFontSize * 0.875;
float: right;
color: transparent;
text-shadow: 0 0 0 #fff;
@@ -480,3 +486,7 @@ a:visited {
.charisma-purple {
color: $my-stat-cha-color;
}
+
+.smallfont {
+ font-size: $defaultFontSize * 0.8125;
+}
diff --git a/src/Bladeburner.js b/src/Bladeburner.js
index e1bfba2c3..73d214196 100644
--- a/src/Bladeburner.js
+++ b/src/Bladeburner.js
@@ -1768,8 +1768,9 @@ Bladeburner.prototype.createOverviewContent = function() {
});
DomElems.overviewStaminaHelpTip = createElement("div", {
- innerText:"?", class:"help-tip",
- clickListener:()=>{
+ class:"help-tip",
+ innerText:"?",
+ clickListener: ()=> {
dialogBoxCreate("Performing actions will use up your stamina.
" +
"Your max stamina is determined primarily by your agility stat.
" +
"Your stamina gain rate is determined by both your agility and your " +
@@ -1781,7 +1782,7 @@ Bladeburner.prototype.createOverviewContent = function() {
"your success rate would be multipled by 85% (100 - 15).
" +
"Your max stamina and stamina gain rate can also be increased by " +
"training, or through skills and Augmentation upgrades.");
- }
+ },
});
DomElems.overviewGen1 = createElement("p", {
@@ -1831,7 +1832,7 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText: "Bonus time: ",
display: "inline-block",
tooltip: "You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by browser). " +
- "Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed."
+ "Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed."
});
DomElems.overviewSkillPoints = createElement("p", {display:"block"});
diff --git a/src/Constants.js b/src/Constants.js
index ad92f504f..26a1f04de 100644
--- a/src/Constants.js
+++ b/src/Constants.js
@@ -500,6 +500,14 @@ let CONSTANTS = {
LatestUpdate:
`
v0.41.0
+ * Gang Mechanic Changes (BitNode-2):
+ *** Added new 'ascension' mechanic for Gang Members
+ *** The first three gang members are now 'free' (can be recruited instantly)
+ *** Maximum number of increased Gang Members increased from 20 to 50
+ *** Changed the formula for calculating respect needed to recruit the next gang member
+ *** Added a new category of upgrades for Gang Members: Augmentations
+ *** Non-Augmentation Gang member upgrades are now significantly weaker
+ *** Reputation for your Gang faction can no longer be gained through Infiltration
* b1t_flum3.exe now takes significantly less time to create
* Bug Fix: Fixed a bug that sometimes caused a blank black screen when destroying/resetting/switching BitNodes
* Bug Fix: Netscript calls that throw errors will now no longer cause the 'concurrent calls' error if they are caught in the script. i.e. try/catch should now work properly in scripts
diff --git a/src/Gang.js b/src/Gang.js
index d0a733779..e0e9dbe1b 100644
--- a/src/Gang.js
+++ b/src/Gang.js
@@ -39,23 +39,23 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
// Constants
-const GangRespectToReputationRatio = 2; //Respect is divided by this to get rep gain
-const MaximumGangMembers = 47;
+const GangRespectToReputationRatio = 2; // Respect is divided by this to get rep gain
+const MaximumGangMembers = 50;
const GangRecruitCostMultiplier = 2;
const GangTerritoryUpdateTimer = 150;
-const AscensionMultiplierRatio = 10 / 100; //Portion upgrade multiplier is kept after ascending
+const AscensionMultiplierRatio = 10 / 100; // Portion of upgrade multiplier that is kept after ascending
// Switch between territory and management screen with 1 and 2
$(document).keydown(function(event) {
- if (routing.isOn(Page.Gang) && !yesNoBoxOpen) {
- if (gangMemberFilter != null && gangMemberFilter === document.activeElement) {return;}
- if (event.keyCode === 49) {
- if(gangTerritorySubpage.style.display === "block") {
- managementButton.click();
+ if (routing.isOn(Page.Gang) && event.altKey) {
+ if (UIElems.gangMemberFilter != null && UIElems.gangMemberFilter === document.activeElement) {return;}
+ if (event.keyCode === KEY["1"]) {
+ if(UIElems.gangTerritorySubpage.style.display === "block") {
+ UIElems.managementButton.click();
}
- } else if (event.keyCode === 50) {
- if (gangManagementSubpage.style.display === "block") {
- territoryButton.click();
+ } else if (event.keyCode === KEY["2"]) {
+ if (UIElems.gangManagementSubpage.style.display === "block") {
+ UIElems.territoryButton.click();
}
}
}
@@ -65,21 +65,21 @@ $(document).keydown(function(event) {
$(document).mousedown(function(event) {
var boxId = "gang-member-upgrade-popup-box";
var contentId = "gang-member-upgrade-popup-box-content";
- if (gangMemberUpgradeBoxOpened) {
+ if (UIElems.gangMemberUpgradeBoxOpened) {
if ( $(event.target).closest("#" + contentId).get(0) == null ) {
//Delete the box
- removeElement(gangMemberUpgradeBox);
- gangMemberUpgradeBox = null;
- gangMemberUpgradeBoxContent = null;
- gangMemberUpgradeBoxOpened = false;
- gangMemberUpgradeBoxElements = null;
+ removeElement(UIElems.gangMemberUpgradeBox);
+ UIElems.gangMemberUpgradeBox = null;
+ UIElems.gangMemberUpgradeBoxContent = null;
+ UIElems.gangMemberUpgradeBoxOpened = false;
+ UIElems.gangMemberUpgradeBoxElements = null;
}
}
});
let GangNames = ["Slum Snakes", "Tetrads", "The Syndicate", "The Dark Army", "Speakers for the Dead",
"NiteSec", "The Black Hand"];
-let AllGangs = {
+export let AllGangs = {
"Slum Snakes" : {
power: 1,
territory: 1/7,
@@ -110,7 +110,7 @@ let AllGangs = {
},
}
-function resetGangs() {
+export function resetGangs() {
AllGangs = {
"Slum Snakes" : {
power: 1,
@@ -143,7 +143,7 @@ function resetGangs() {
}
}
-function loadAllGangs(saveString) {
+export function loadAllGangs(saveString) {
AllGangs = JSON.parse(saveString, Reviver);
}
@@ -204,7 +204,7 @@ function processAllGangTerritory(numCycles=1) {
/* faction - Name of corresponding faction
hacking - Boolean indicating whether its a hacking gang or not
*/
-function Gang(facName, hacking=false) {
+export function Gang(facName, hacking=false) {
this.facName = facName;
this.members = []; //Array of GangMembers
this.wanted = 1;
@@ -223,20 +223,30 @@ function Gang(facName, hacking=false) {
}
Gang.prototype.process = function(numCycles=1) {
- this.processGains(numCycles);
- this.processExperienceGains(numCycles);
- processAllGangPowerGains(numCycles);
- processAllGangTerritory(numCycles);
+ const CyclesPerSecond = 1000 / Engine._idleSpeed;
+
+ if (isNaN(numCycles)) {
+ console.error(`NaN passed into Gang.process(): ${numCycles}`);
+ }
+ this.storedCycles += numCycles;
+
+ // Only process if there are at least 3 seconds, and at most 10 seconds
+ if (this.storedCycles < 3 * CyclesPerSecond);
+ const cycles = Math.min(this.storedCycles, 10 * CyclesPerSecond);
+
+ try {
+ this.processGains(cycles);
+ this.processExperienceGains(cycles);
+ processAllGangPowerGains(cycles);
+ processAllGangTerritory(cycles);
+ this.storedCycles -= cycles;
+ } catch(e) {
+ exceptionAlert(`Exception caught when processing Gang: ${e}`);
+ }
+
}
Gang.prototype.processGains = function(numCycles=1) {
- this.storedCycles += numCycles;
- if (isNaN(this.storedCycles)) {
- console.log("ERROR: Gang's storedCylces is NaN");
- this.storedCycles = 0;
- }
- if (this.storedCycles < 25) { return; } //Only process every 5 seconds at least
-
//Get gains per cycle
var moneyGains = 0, respectGains = 0, wantedLevelGains = 0;
for (var i = 0; i < this.members.length; ++i) {
@@ -249,10 +259,10 @@ Gang.prototype.processGains = function(numCycles=1) {
this.moneyGainRate = moneyGains;
if (typeof respectGains === "number") {
- var gain = respectGains * this.storedCycles;
- this.respect += (gain);
+ const gain = respectGains * numCycles;
+ this.respect += gain;
// Faction reputation gains is respect gain divided by some constant
- var fac = Factions[this.facName];
+ const fac = Factions[this.facName];
if (!(fac instanceof Faction)) {
dialogBoxCreate("ERROR: Could not get Faction associates with your gang. This is a bug, please report to game dev");
} else {
@@ -262,17 +272,17 @@ Gang.prototype.processGains = function(numCycles=1) {
// Keep track of respect gained per member
for (let i = 0; i < this.members.length; ++i) {
- this.members[i].recordEarnedRespect(this.storedCycles);
+ this.members[i].recordEarnedRespect(numCycles);
}
} else {
console.warn("respectGains calculated to be NaN");
}
if (typeof wantedLevelGains === "number") {
if (this.wanted === 1 && wantedLevelGains < 0) {
- //Do nothing
+ // At minimum wanted, do nothing
} else {
const oldWanted = this.wanted;
- let newWanted = + (wantedLevelGains * this.storedCycles);
+ let newWanted = oldWanted + (wantedLevelGains * numCycles);
// Prevent overflow
if (wantedLevelGains <= 0 && newWanted > oldWanted) {
@@ -286,12 +296,10 @@ Gang.prototype.processGains = function(numCycles=1) {
console.warn("ERROR: wantedLevelGains is NaN");
}
if (typeof moneyGains === "number") {
- Player.gainMoney(moneyGains * this.storedCycles);
+ Player.gainMoney(moneyGains * numCycles);
} else {
console.warn("ERROR: respectGains is NaN");
}
-
- this.storedCycles = 0;
}
Gang.prototype.canRecruitMember = function() {
@@ -338,8 +346,25 @@ Gang.prototype.killMember = function(memberObj) {
Gang.prototype.ascendMember = function(memberObj) {
try {
- //Member.ascend() returns the amount of respect to deduct
- this.respect = Math.min(1, this.respect - memberObj.ascend());
+ /**
+ * res is an object with the following format:
+ * {
+ * respect: Amount of respect to deduct
+ * hack/str/def/dex/agi/cha: Ascension multipliers gained for each stat
+ * }
+ */
+ const res = memberObj.ascend();
+ this.respect = Math.max(1, this.respect - res.respect);
+ dialogBoxCreate([`You ascended ${memberObj.name}!`,
+ `Your gang lost ${numeralWrapper.format(res.respect, "0.000a")} respect`,
+ `${memberObj.name} gained the following stat multipliers for ascending:`,
+ `Hacking: ${res.hack}`,
+ `Strength: ${res.str}`,
+ `Defense: ${res.def}`,
+ `Dexterity: ${res.dex}`,
+ `Agility: ${res.agi}`,
+ `Charisma: ${res.cha}`].join(" "));
+ this.displayGangMemberList();
} catch(e) {
exceptionAlert(e);
}
@@ -501,6 +526,57 @@ GangMember.prototype.recordEarnedRespect = function(numCycles=1) {
}
GangMember.prototype.ascend = function() {
+ const res = this.getAscensionResults();
+ const hackAscMult = res.hack;
+ const strAscMult = res.str;
+ const defAscMult = res.def;
+ const dexAscMult = res.dex;
+ const agiAscMult = res.agi;
+ const chaAscMult = res.cha;
+ this.hack_asc_mult += hackAscMult;
+ this.str_asc_mult += strAscMult;
+ this.def_asc_mult += defAscMult;
+ this.dex_asc_mult += dexAscMult;
+ this.agi_asc_mult += agiAscMult;
+ this.cha_asc_mult += chaAscMult;
+
+ // Remove upgrades. Then re-calculate multipliers and stats
+ this.upgrades.length = 0;
+ this.hack_mult = 1;
+ this.str_mult = 1;
+ this.def_mult = 1;
+ this.dex_mult = 1;
+ this.agi_mult = 1;
+ this.cha_mult = 1;
+ for (let i = 0; i < this.augmentations.length; ++i) {
+ let aug = GangMemberUpgrades[this.augmentations[i]];
+ aug.apply(this);
+ }
+
+ // Clear exp and recalculate stats
+ this.hack_exp = 0;
+ this.str_exp = 0;
+ this.def_exp = 0;
+ this.dex_exp = 0;
+ this.agi_exp = 0;
+ this.cha_exp = 0;
+ this.updateSkillLevels();
+
+ const respectToDeduct = this.earnedRespect;
+ this.earnedRespect = 0;
+ return {
+ respect: respectToDeduct,
+ hack: hackAscMult,
+ str: strAscMult,
+ def: defAscMult,
+ dex: dexAscMult,
+ agi: agiAscMult,
+ cha: chaAscMult,
+ };
+}
+
+// Returns the multipliers that would be gained from ascension
+GangMember.prototype.getAscensionResults = function() {
// Calculate ascension bonus to stat multipliers.
// This is based on the current number of multipliers from Non-Augmentation upgrades
// + Ascension Bonus = N% of current bonus from Augmentations
@@ -520,32 +596,15 @@ GangMember.prototype.ascend = function() {
if (upg.mults.cha != null) { cha *= upg.mults.cha; }
}
- // Get just the bonus multiplier part, and then record
- --hack; --str; --def; --dex; --agi; --cha;
- this.hack_asc_mult += (hack * AscensionMultiplierRatio);
- this.str_asc_mult += (str * AscensionMultiplierRatio);
- this.def_asc_mult += (def * AscensionMultiplierRatio);
- this.dex_asc_mult += (dex * AscensionMultiplierRatio);
- this.agi_asc_mult += (agi * AscensionMultiplierRatio);
- this.cha_asc_mult += (cha * AscensionMultiplierRatio);
-
- // Remove upgrades. Then re-calculate multipliers and stats
- this.upgrades.length = 0;
- this.hack_mult = 1;
- this.str_mult = 1;
- this.def_mult = 1;
- this.dex_mult = 1;
- this.agi_mult = 1;
- this.cha_mult = 1;
- for (let i = 0; i < this.augmentations.length; ++i) {
- let aug = GangMemberUpgrades[this.augmentations[i]];
- aug.apply(this);
+ // Subtract 1 because we're only interested in the actual "bonus" part
+ return {
+ hack: (Math.max(0, hack - 1) * AscensionMultiplierRatio),
+ str: (Math.max(0, str - 1) * AscensionMultiplierRatio),
+ def: (Math.max(0, def - 1) * AscensionMultiplierRatio),
+ dex: (Math.max(0, dex - 1) * AscensionMultiplierRatio),
+ agi: (Math.max(0, agi - 1) * AscensionMultiplierRatio),
+ cha: (Math.max(0, cha - 1) * AscensionMultiplierRatio),
}
- this.updateSkillLevels();
-
- const respectToDeduct = this.earnedRespect;
- this.earnedRespect = 0;
- return respectToDeduct;
}
GangMember.prototype.toJSON = function() {
@@ -639,7 +698,7 @@ GangMemberUpgrade.prototype.createDescription = function() {
if (this.mults.hack != null) {
lines.push(`* Hacking by ${Math.round((this.mults.hack - 1) * 100)}%`);
}
- this.desc = lines.join("\n");
+ this.desc = lines.join(" ");
}
//Passes in a GangMember object
@@ -674,98 +733,99 @@ gangMemberUpgradesMetadata.forEach((e) => {
addGangMemberUpgrade(e.name, e.cost, e.upgType, e.mults);
});
-//Create a pop-up box that lets player purchase upgrades
-let gangMemberUpgradeBoxOpened = false;
-function createGangMemberUpgradeBox(initialFilter="") {
- var boxId = "gang-member-upgrade-popup-box";
- if (gangMemberUpgradeBoxOpened) {
+// Create a pop-up box that lets player purchase upgrades
+Gang.prototype.createGangMemberUpgradeBox = function(initialFilter="") {
+ const boxId = "gang-member-upgrade-popup-box";
+ if (UIElems.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");
+ if (UIElems.gangMemberUpgradeBoxElements == null || UIElems.gangMemberUpgradeBox == null || UIElems.gangMemberUpgradeBoxContent == null) {
+ console.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]);
+ for (var i = 1; i < UIElems.gangMemberUpgradeBoxElements.length; ++i) {
+ removeElement(UIElems.gangMemberUpgradeBoxElements[i]);
}
- gangMemberUpgradeBoxElements = [gangMemberUpgradeBoxFilter];
+ UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter];
- var filter = gangMemberUpgradeBoxFilter.value.toString();
+ var filter = UIElems.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);
+ var newPanel = Player.gang.members[i].createGangMemberUpgradePanel(this);
+ UIElems.gangMemberUpgradeBoxContent.appendChild(newPanel);
+ UIElems.gangMemberUpgradeBoxElements.push(newPanel);
}
}
} else {
//New popup
- gangMemberUpgradeBoxFilter = createElement("input", {
+ UIElems.gangMemberUpgradeBoxFilter = createElement("input", {
type:"text", placeholder:"Filter gang members",
value:initialFilter,
onkeyup:()=>{
- var filterValue = gangMemberUpgradeBoxFilter.value.toString();
- createGangMemberUpgradeBox(filterValue);
+ var filterValue = UIElems.gangMemberUpgradeBoxFilter.value.toString();
+ this.createGangMemberUpgradeBox(filterValue);
}
});
- gangMemberUpgradeBoxElements = [gangMemberUpgradeBoxFilter];
+ UIElems.gangMemberUpgradeBoxElements = [UIElems.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]));
+ var filter = UIElems.gangMemberUpgradeBoxFilter.value.toString();
+ for (var i = 0; i < this.members.length; ++i) {
+ if (this.members[i].name.indexOf(filter) > -1 || this.members[i].task.name.indexOf(filter) > -1) {
+ UIElems.gangMemberUpgradeBoxElements.push(this.members[i].createGangMemberUpgradePanel(this));
}
}
- gangMemberUpgradeBox = createPopup(boxId, gangMemberUpgradeBoxElements);
- gangMemberUpgradeBoxContent = document.getElementById(boxId + "-content");
- gangMemberUpgradeBoxOpened = true;
+ UIElems.gangMemberUpgradeBox = createPopup(boxId, UIElems.gangMemberUpgradeBoxElements);
+ UIElems.gangMemberUpgradeBoxContent = document.getElementById(boxId + "-content");
+ UIElems.gangMemberUpgradeBoxOpened = true;
}
}
//Create upgrade panels for each individual Gang Member
-function createGangMemberUpgradePanel(memberObj) {
+GangMember.prototype.createGangMemberUpgradePanel = function(gangObj) {
var container = createElement("div", {
border:"1px solid white",
});
var header = createElement("h1", {
- innerText:memberObj.name + " (" + memberObj.task.name + ")"
+ innerText: this.name + " (" + this.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",
+ "Hack: " + this.hack + " (x" + formatNumber(this.hack_mult, 2) + ")\n" +
+ "Str: " + this.str + " (x" + formatNumber(this.str_mult, 2) + ")\n" +
+ "Def: " + this.def + " (x" + formatNumber(this.def_mult, 2) + ")\n" +
+ "Dex: " + this.dex + " (x" + formatNumber(this.dex_mult, 2) + ")\n" +
+ "Agi: " + this.agi + " (x" + formatNumber(this.agi_mult, 2) + ")\n" +
+ "Cha: " + this.cha + " (x" + formatNumber(this.cha_mult, 2) + ")\n",
});
//Already purchased upgrades
- var ownedUpgradesElements = [];
- for (var i = 0; i < memberObj.upgrades.length; ++i) {
- var upg = GangMemberUpgrades[memberObj.upgrades[i]];
+ const ownedUpgradesElements = [];
+ function pushOwnedUpgrade(upgName) {
+ const upg = GangMemberUpgrades[upgName];
if (upg == null) {
- console.log("ERR: Could not find this upgrade: " + memberObj.upgrades[i]);
- continue;
+ console.error(`Could not find GangMemberUpgrade object for name ${upgName}`);
+ return;
}
- var e = createElement("div", {
- border:"1px solid white", innerText:memberObj.upgrades[i],
- margin:"1px", padding:"1px", tooltip:upg.desc, fontSize:"12px",
- });
- ownedUpgradesElements.push(e);
+ ownedUpgradesElements.push(createElement("div", {
+ class: "gang-owned-upgrade",
+ innerText: upgName,
+ tooltip: upg.desc,
+ }));
}
+ for (const upgName of this.upgrades) { pushOwnedUpgrade(upgName); }
+ for (const upgName of this.augmentations) { pushOwnedUpgrade(upgName); }
+
var ownedUpgrades = createElement("div", {
- display:"inline-block", marginLeft:"6px", width:"75%", innerText:"Purchased Upgrades:",
+ class: "gang-owned-upgrades-div",
+ innerText: "Purchased Upgrades:",
});
- for (var i = 0; i < ownedUpgradesElements.length; ++i) {
- ownedUpgrades.appendChild(ownedUpgradesElements[i]);
- }
+ for (const elem of ownedUpgradesElements) { ownedUpgrades.appendChild(elem); }
container.appendChild(text);
container.appendChild(ownedUpgrades);
container.appendChild(createElement("br", {}));
@@ -780,7 +840,8 @@ function createGangMemberUpgradePanel(memberObj) {
for (let upgName in GangMemberUpgrades) {
if (GangMemberUpgrades.hasOwnProperty(upgName)) {
let upg = GangMemberUpgrades[upgName];
- if (Player.money.lt(upg.cost) || memberObj.upgrades.includes(upgName)) {continue;}
+ if (Player.money.lt(upg.cost)) { continue; }
+ if (this.upgrades.includes(upgName) || this.augmentations.includes(upgName)) { continue; }
switch (upg.type) {
case "w":
weaponUpgrades.push(upg);
@@ -796,31 +857,40 @@ function createGangMemberUpgradePanel(memberObj) {
break;
case "g":
augUpgrades.push(upg);
+ break;
default:
console.error(`ERROR: Invalid Gang Member Upgrade Type: ${upg.type}`);
}
}
}
- const weaponDiv = createElement("div", {width: "16%", display: "inline-block"});
- const armorDiv = createElement("div", {width: "16%", display: "inline-block"});
- const vehicleDiv = createElement("div", {width: "16%", display: "inline-block"});
- const rootkitDiv = createElement("div", {width: "16%", display: "inline-block"});
- const augDiv = createElement("div", {width: "16%", display: "inline-block"});
+ // Create separate columns for each upgrade type
+ const weaponDiv = createElement("div", {width: "20%", display: "inline-block"});
+ const armorDiv = createElement("div", {width: "20%", display: "inline-block"});
+ const vehicleDiv = createElement("div", {width: "20%", display: "inline-block"});
+ const rootkitDiv = createElement("div", {width: "20%", display: "inline-block"});
+ const augDiv = createElement("div", {width: "20%", display: "inline-block"});
+
+ // Add a title/labe for each column
+ weaponDiv.appendChild(createElement("h2", {innerText: "Weapons"}));
+ armorDiv.appendChild(createElement("h2", {innerText: "Armor"}));
+ vehicleDiv.appendChild(createElement("h2", {innerText: "Vehicles"}));
+ rootkitDiv.appendChild(createElement("h2", {innerText: "Rootkits"}));
+ augDiv.appendChild(createElement("h2", {innerText: "Augmentations"}));
+
+ // Add buttons to purchase each upgrade
const upgrades = [weaponUpgrades, armorUpgrades, vehicleUpgrades, rootkitUpgrades, augUpgrades];
const divs = [weaponDiv, armorDiv, vehicleDiv, rootkitDiv, augDiv];
-
for (let i = 0; i < upgrades.length; ++i) {
let upgradeArray = upgrades[i];
let div = divs[i];
for (let j = 0; j < upgradeArray.length; ++j) {
let upg = upgradeArray[j];
- (function (upg, div, memberObj) {
- div.appendChild(createElement("a", {
+ (function (upg, div, memberObj, i) {
+ let createElementParams = {
innerText:upg.name + " - " + numeralWrapper.format(upg.cost, "$0.000a"),
class:"a-link-button", margin:"2px", padding:"2px", display:"block",
fontSize:"11px",
- tooltip:upg.desc,
clickListener:()=>{
if (Player.money.lt(upg.cost)) { return false; }
Player.loseMoney(upg.cost);
@@ -830,12 +900,20 @@ function createGangMemberUpgradePanel(memberObj) {
memberObj.upgrades.push(upg.name);
}
upg.apply(memberObj);
- var initFilterValue = gangMemberUpgradeBoxFilter.value.toString();
- createGangMemberUpgradeBox(initFilterValue);
+ var initFilterValue = UIElems.gangMemberUpgradeBoxFilter.value.toString();
+ gangObj.createGangMemberUpgradeBox(initFilterValue);
return false;
}
- }));
- })(upg, div, memberObj);
+ }
+
+ // For the last two divs, tooltip should be on the left
+ if (i >= 3) {
+ createElementParams.tooltipleft = upg.desc;
+ } else {
+ createElementParams.tooltip = upg.desc;
+ }
+ div.appendChild(createElement("a", createElementParams));
+ })(upg, div, this, i);
}
}
@@ -843,47 +921,63 @@ function createGangMemberUpgradePanel(memberObj) {
container.appendChild(armorDiv);
container.appendChild(vehicleDiv);
container.appendChild(rootkitDiv);
+ container.appendChild(augDiv);
return container;
}
-//Gang DOM elements
-let gangContentCreated = false,
- gangContainer = null, managementButton = null, territoryButton = null;
+// Gang UI Dom Elements
+const UIElems = {
+ // Main elems
+ gangContentCreated: false,
+ gangContainer: null,
+ managementButton: null,
+ territoryButton: null,
-//Subpages
-let gangManagementSubpage = null, gangTerritorySubpage = null;
+ // Subpages
+ gangManagementSubpage: null,
+ gangTerritorySubpage: null,
-//Gang Management Elements
-let gangDesc = null, gangInfo = null,
- gangRecruitMemberButton = null, gangRecruitRequirementText = null,
- gangExpandAllButton = null, gangCollapseAllButton, gangMemberFilter = null,
- gangManageEquipmentButton = null,
- gangMemberList = null;
+ // Gang Management Subpage Elements
+ gangDesc: null,
+ gangInfo: null,
+ gangRecruitMemberButton: null,
+ gangRecruitRequirementText: null,
+ gangExpandAllButton: null,
+ gangCollapseAllButton: null,
+ gangMemberFilter: null,
+ gangManageEquipmentButton: null,
+ gangMemberList: null,
+ gangMemberPanels: null,
-//Gang Equipment Upgrade Elements
-let gangMemberUpgradeBox = null, gangMemberUpgradeBoxContent = null,
- gangMemberUpgradeBoxFilter = null, gangMemberUpgradeBoxElements = null;
+ // Gang Equipment Upgrade Elements
+ gangMemberUpgradeBoxOpened: false,
+ gangMemberUpgradeBox: null,
+ gangMemberUpgradeBoxContent: null,
+ gangMemberUpgradeBoxFilter: null,
+ gangMemberUpgradeBoxElements: null,
-//Gang Territory Elements
-let gangTerritoryDescText = null, gangTerritoryInfoText = null;
+ // Gang Territory Elements
+ gangTerritoryDescText: null,
+ gangTerritoryInfoText: null,
+}
-function displayGangContent() {
- if (!gangContentCreated || gangContainer == null) {
- gangContentCreated = true;
+Gang.prototype.displayGangContent = function() {
+ if (!UIElems.gangContentCreated || UIElems.gangContainer == null) {
+ UIElems.gangContentCreated = true;
//Create gang container
- gangContainer = createElement("div", {
+ UIElems.gangContainer = createElement("div", {
id:"gang-container", class:"generic-menupage-container",
});
//Get variables
- var facName = Player.gang.facName,
- members = Player.gang.members,
- wanted = Player.gang.wanted,
- respect = Player.gang.respect;
+ var facName = this.facName,
+ members = this.members,
+ wanted = this.wanted,
+ respect = this.respect;
//Back button
- gangContainer.appendChild(createElement("a", {
+ UIElems.gangContainer.appendChild(createElement("a", {
class:"a-link-button", display:"inline-block", innerText:"Back",
clickListener:()=>{
Engine.loadFactionContent();
@@ -893,49 +987,49 @@ function displayGangContent() {
}));
//Buttons to switch between panels
- managementButton = createElement("a", {
+ UIElems.managementButton = createElement("a", {
id:"gang-management-subpage-button", class:"a-link-button-inactive",
- display:"inline-block", innerHTML: "Gang Management (1)",
+ display:"inline-block", innerHTML: "Gang Management (Alt+1)",
clickListener:()=>{
- gangManagementSubpage.style.display = "block";
- gangTerritorySubpage.style.display = "none";
- managementButton.classList.toggle("a-link-button-inactive");
- managementButton.classList.toggle("a-link-button");
- territoryButton.classList.toggle("a-link-button-inactive");
- territoryButton.classList.toggle("a-link-button");
- updateGangContent();
+ UIElems.gangManagementSubpage.style.display = "block";
+ UIElems.gangTerritorySubpage.style.display = "none";
+ UIElems.managementButton.classList.toggle("a-link-button-inactive");
+ UIElems.managementButton.classList.toggle("a-link-button");
+ UIElems.territoryButton.classList.toggle("a-link-button-inactive");
+ UIElems.territoryButton.classList.toggle("a-link-button");
+ this.updateGangContent();
return false;
}
})
- territoryButton = createElement("a", {
+ UIElems.territoryButton = createElement("a", {
id:"gang-territory-subpage-button", class:"a-link-button",
- display:"inline-block", innerHTML:"Gang Territory (2)",
- clickListener:()=>{
- gangManagementSubpage.style.display = "none";
- gangTerritorySubpage.style.display = "block";
- managementButton.classList.toggle("a-link-button-inactive");
- managementButton.classList.toggle("a-link-button");
- territoryButton.classList.toggle("a-link-button-inactive");
- territoryButton.classList.toggle("a-link-button");
- updateGangContent();
+ display:"inline-block", innerHTML:"Gang Territory (Alt+2)",
+ clickListener:() => {
+ UIElems.gangManagementSubpage.style.display = "none";
+ UIElems.gangTerritorySubpage.style.display = "block";
+ UIElems.managementButton.classList.toggle("a-link-button-inactive");
+ UIElems.managementButton.classList.toggle("a-link-button");
+ UIElems.territoryButton.classList.toggle("a-link-button-inactive");
+ UIElems.territoryButton.classList.toggle("a-link-button");
+ this.updateGangContent();
return false;
}
});
- gangContainer.appendChild(managementButton);
- gangContainer.appendChild(territoryButton);
+ UIElems.gangContainer.appendChild(UIElems.managementButton);
+ UIElems.gangContainer.appendChild(UIElems.territoryButton);
//Subpage for managing gang members
- gangManagementSubpage = createElement("div", {
+ UIElems.gangManagementSubpage = createElement("div", {
display:"block", id:"gang-management-subpage",
});
var lowerWantedTask = "";
- if (Player.gang.isHackingGang) {
+ if (this.isHackingGang) {
lowerWantedTask = "Ethical Hacking";
} else {
lowerWantedTask = "Vigilante Justice";
}
- gangDesc = createElement("p", {width:"70%",
+ UIElems.gangDesc = createElement("p", {width:"70%",
innerHTML:
"This page is used to manage your gang members and get an overview of your " +
"gang's stats.
" +
@@ -950,16 +1044,16 @@ function displayGangContent() {
"Furthermore, after installing Augmentations, you will " +
"automatically be a member of whatever Faction you created your gang with.
"
});
- gangManagementSubpage.appendChild(gangDesc);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangDesc);
- gangInfo = createElement("p", {id:"gang-info", width:"70%"});
- gangManagementSubpage.appendChild(gangInfo);
+ UIElems.gangInfo = createElement("p", {id:"gang-info", width:"70%"});
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangInfo);
- gangRecruitMemberButton = createElement("a", {
+ UIElems.gangRecruitMemberButton = createElement("a", {
id:"gang-management-recruit-member-btn", class:"a-link-button-inactive",
innerHTML:"Recruit Gang Member", display:"inline-block", margin:"10px",
clickListener:()=>{
- let popupId = "recruit-gang-member-popup";
+ const popupId = "recruit-gang-member-popup";
let yesBtn;
const txt = createElement("p", {
@@ -974,12 +1068,12 @@ function displayGangContent() {
type: "text",
});
yesBtn = createElement("a", {
- class: "a-link-button",
+ class: "std-button",
clickListener: () => {
let name = nameInput.value;
// Check for already-existing names
- let sameNames = Player.gang.members.filter((m) => {
+ let sameNames = this.members.filter((m) => {
return m.name === name;
});
if (sameNames.length >= 1) {
@@ -991,9 +1085,9 @@ function displayGangContent() {
dialogBoxCreate("You must enter a name for your Gang member!");
} else {
let member = new GangMember(name);
- Player.gang.members.push(member);
- createGangMemberDisplayElement(member);
- updateGangContent();
+ this.members.push(member);
+ this.createGangMemberDisplayElement(member);
+ this.updateGangContent();
removeElementById(popupId);
}
return false;
@@ -1001,7 +1095,7 @@ function displayGangContent() {
innerText: "Recruit Gang Member",
});
const noBtn = createElement("a", {
- class: "a-link-button",
+ class: "std-button",
clickListener: () => {
removeElementById(popupId);
return false;
@@ -1011,23 +1105,23 @@ function displayGangContent() {
createPopup(popupId, [txt, br, nameInput, yesBtn, noBtn]);
}
});
- gangManagementSubpage.appendChild(gangRecruitMemberButton);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangRecruitMemberButton);
// Text for how much reputation is required for recruiting next memberList
- gangRecruitRequirementText = createElement("p", {
+ UIElems.gangRecruitRequirementText = createElement("p", {
color:"red",
id: "gang-recruit-requirement-text",
margin: "10px",
});
- gangManagementSubpage.appendChild(gangRecruitRequirementText);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangRecruitRequirementText);
//Gang Member List management buttons (Expand/Collapse All, select a single member)
- gangManagementSubpage.appendChild(createElement("br", {}));
- gangExpandAllButton = createElement("a", {
+ UIElems.gangManagementSubpage.appendChild(createElement("br", {}));
+ UIElems.gangExpandAllButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerHTML:"Expand All",
clickListener:()=>{
- var allHeaders = gangManagementSubpage.getElementsByClassName("accordion-header");
+ var allHeaders = UIElems.gangManagementSubpage.getElementsByClassName("accordion-header");
for (var i = 0; i < allHeaders.length; ++i) {
var hdr = allHeaders[i];
if (!hdr.classList.contains("active")) {
@@ -1037,11 +1131,11 @@ function displayGangContent() {
return false;
}
});
- gangCollapseAllButton = createElement("a", {
+ UIElems.gangCollapseAllButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerHTML:"Collapse All",
clickListener:()=>{
- var allHeaders = gangManagementSubpage.getElementsByClassName("accordion-header");
+ var allHeaders = UIElems.gangManagementSubpage.getElementsByClassName("accordion-header");
for (var i = 0; i < allHeaders.length; ++i) {
var hdr = allHeaders[i];
if (hdr.classList.contains("active")) {
@@ -1051,36 +1145,36 @@ function displayGangContent() {
return false;
}
});
- gangMemberFilter = createElement("input", {
+ UIElems.gangMemberFilter = createElement("input", {
type:"text", placeholder:"Filter gang members", margin:"5px", padding:"5px",
onkeyup:()=>{
- displayGangMemberList();
+ this.displayGangMemberList();
}
});
- gangManageEquipmentButton = createElement("a", {
+ UIElems.gangManageEquipmentButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerHTML:"Manage Equipment",
- clickListener:()=>{
- createGangMemberUpgradeBox();
+ clickListener: () => {
+ this.createGangMemberUpgradeBox();
}
});
- gangManagementSubpage.appendChild(gangExpandAllButton);
- gangManagementSubpage.appendChild(gangCollapseAllButton);
- gangManagementSubpage.appendChild(gangMemberFilter);
- gangManagementSubpage.appendChild(gangManageEquipmentButton);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangExpandAllButton);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangCollapseAllButton);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberFilter);
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangManageEquipmentButton);
//Gang Member list
- gangMemberList = createElement("ul", {id:"gang-member-list"});
- displayGangMemberList();
- gangManagementSubpage.appendChild(gangMemberList);
+ UIElems.gangMemberList = createElement("ul", {id:"gang-member-list"});
+ this.displayGangMemberList();
+ UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberList);
//Subpage for seeing gang territory information
- gangTerritorySubpage = createElement("div", {
+ UIElems.gangTerritorySubpage = createElement("div", {
id:"gang-territory-subpage", display:"none"
});
//Info text for territory page
- gangTerritoryDescText = createElement("p", {
+ UIElems.gangTerritoryDescText = createElement("p", {
width:"70%",
innerHTML:"This page shows how much territory your Gang controls. This statistic is listed as a percentage, " +
"which represents how much of the total territory you control.
" +
@@ -1092,41 +1186,40 @@ function displayGangContent() {
"The amount of territory you have affects all aspects of your Gang members' production, including " +
"money, respect, and wanted level. It is very beneficial to have high territory control.
"
});
- gangTerritorySubpage.appendChild(gangTerritoryDescText);
+ UIElems.gangTerritorySubpage.appendChild(UIElems.gangTerritoryDescText);
var territoryBorder = createElement("fieldset", {width:"50%", display:"inline-block"});
- gangTerritoryInfoText = createElement("p", {id:"gang-territory-info"});
+ UIElems.gangTerritoryInfoText = createElement("p", {id:"gang-territory-info"});
- territoryBorder.appendChild(gangTerritoryInfoText);
- gangTerritorySubpage.appendChild(territoryBorder);
+ territoryBorder.appendChild(UIElems.gangTerritoryInfoText);
+ UIElems.gangTerritorySubpage.appendChild(territoryBorder);
- gangContainer.appendChild(gangTerritorySubpage);
- gangContainer.appendChild(gangManagementSubpage);
- document.getElementById("entire-game-container").appendChild(gangContainer);
+ UIElems.gangContainer.appendChild(UIElems.gangTerritorySubpage);
+ UIElems.gangContainer.appendChild(UIElems.gangManagementSubpage);
+ document.getElementById("entire-game-container").appendChild(UIElems.gangContainer);
}
- gangContainer.style.display = "block";
- updateGangContent();
+ UIElems.gangContainer.style.display = "block";
+ this.updateGangContent();
}
-function displayGangMemberList() {
- removeChildrenFromElement(gangMemberList);
- var members = Player.gang.members;
- var filter = gangMemberFilter.value.toString();
+Gang.prototype.displayGangMemberList = function() {
+ removeChildrenFromElement(UIElems.gangMemberList);
+ const members = this.members;
+ const filter = UIElems.gangMemberFilter.value.toString();
for (var i = 0; i < members.length; ++i) {
if (members[i].name.indexOf(filter) > -1 || members[i].task.name.indexOf(filter) > -1) {
- createGangMemberDisplayElement(members[i]);
+ this.createGangMemberDisplayElement(members[i]);
}
}
- //setGangMemberClickHandlers(); //Set buttons to toggle the gang member info panels
}
-function updateGangContent() {
- if (!gangContentCreated || !Player.inGang()) {return;}
+Gang.prototype.updateGangContent = function() {
+ if (!UIElems.gangContentCreated) { return; }
- if(gangTerritorySubpage.style.display === "block") {
+ if(UIElems.gangTerritorySubpage.style.display === "block") {
//Update territory information
- gangTerritoryInfoText.innerHTML = "";
+ UIElems.gangTerritoryInfoText.innerHTML = "";
for (var gangname in AllGangs) {
if (AllGangs.hasOwnProperty(gangname)) {
var gangTerritoryInfo = AllGangs[gangname];
@@ -1142,64 +1235,64 @@ function updateGangContent() {
displayNumber = formatNumber(territory, 2);
}
- if (gangname == Player.gang.facName) {
- gangTerritoryInfoText.innerHTML += ("" + gangname + " (Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " +
+ if (gangname == this.facName) {
+ UIElems.gangTerritoryInfoText.innerHTML += ("" + gangname + " (Power: " + formatNumber(gangTerritoryInfo.power, 6) + "): " +
displayNumber + "%