Finished Gang API. Rebalanced the way Gang territory works. Added discount feature for purchasing Gang member equipment

This commit is contained in:
danielyxie 2018-10-21 20:04:32 -05:00
parent e73ebe843f
commit 0cdfe590a7
6 changed files with 185 additions and 66 deletions

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

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

@ -506,15 +506,18 @@ let CONSTANTS = {
v0.41.0 v0.41.0
* WARNING: In NetscriptJS, defining a function called print() is no longer possible * WARNING: In NetscriptJS, defining a function called print() is no longer possible
* Gang Mechanic Changes (BitNode-2): * Gang Mechanic Changes (BitNode-2):
*** Added a Gang Netscript API
*** Added new 'ascension' mechanic for Gang Members *** Added new 'ascension' mechanic for Gang Members
*** The first three gang members are now 'free' (can be recruited instantly) *** The first three gang members are now 'free' (can be recruited instantly)
*** Maximum number of increased Gang Members increased from 20 to 50 *** Maximum number of increased Gang Members increased from 20 to 40
*** Changed the formula for calculating respect needed to recruit the next gang member *** Changed the formula for calculating respect needed to recruit the next gang member
*** Added a new category of upgrades for Gang Members: Augmentations *** Added a new category of upgrades for Gang Members: Augmentations
*** Non-Augmentation Gang member upgrades are now significantly weaker *** Non-Augmentation Gang member upgrades are now significantly weaker
*** Reputation for your Gang faction can no longer be gained through Infiltration *** Reputation for your Gang faction can no longer be gained through Infiltration
*** Re-worked the territory 'warfare' mechanic so that player can choose when to engage in it *** Re-worked the territory 'warfare' mechanic so that player can choose when to engage in it
*** Player's faction reputation multiplier no longer affects reputation gang from earning respect *** Gang Members can now be killed during territory 'warfare'
*** Changed BitNode-2 Multipliers to make hacking slightly less profitable
*** Gang Member Equipment + Upgrades now get cheaper as your gang grows in power and respect
* RAM Cost of accessing the global document object lowered from 100 GB to 25 GB * RAM Cost of accessing the global document object lowered from 100 GB to 25 GB
* RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4 * RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4
* b1t_flum3.exe now takes significantly less time to create * b1t_flum3.exe now takes significantly less time to create

@ -1,11 +1,6 @@
/* /*
gang member upgrades - they should be cheaper as the gang gets more respect/power gang member upgrades - they should be cheaper as the gang gets more respect/power
kopelli09/12/2018
Another gang-related idea (and perhaps I'm not seeing it in the code) - gangs can lose power. Seems odd that the player's power can drop by removing members, but the other gangs are forever gaining power...
Grub09/12/2018
Maybe add a % chance of other gangs clashing?
assign gangs a number of gang members and each clash kills a number of gang members based on each one's power
and they lose a proportionate number of members
Also add police clashes Also add police clashes
balance point to keep them from running out of control balance point to keep them from running out of control
*/ */
@ -39,7 +34,7 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
// Constants // Constants
const GangRespectToReputationRatio = 2; // Respect is divided by this to get rep gain const GangRespectToReputationRatio = 2; // Respect is divided by this to get rep gain
const MaximumGangMembers = 50; const MaximumGangMembers = 40;
const GangRecruitCostMultiplier = 2; const GangRecruitCostMultiplier = 2;
const CyclesPerTerritoryAndPowerUpdate = 100; const CyclesPerTerritoryAndPowerUpdate = 100;
const AscensionMultiplierRatio = 10 / 100; // Portion of upgrade multiplier that is kept after ascending const AscensionMultiplierRatio = 10 / 100; // Portion of upgrade multiplier that is kept after ascending
@ -176,7 +171,7 @@ export function Gang(facName, hacking=false) {
this.notifyMemberDeath = true; this.notifyMemberDeath = true;
} }
Gang.prototype.power() = function() { Gang.prototype.getPower = function() {
return AllGangs[this.facName].power; return AllGangs[this.facName].power;
} }
@ -275,9 +270,9 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
AllGangs[name].power += this.calculatePower(); AllGangs[name].power += this.calculatePower();
} else { } else {
// Adjust these parameters as necessary // Adjust these parameters as necessary
const additiveGain = Math.random() * AllGangs[name].territory; const additiveGain = 0.5 * Math.random() * AllGangs[name].territory;
AllGangs[name].power += (additiveGain); AllGangs[name].power += (additiveGain);
AllGangs[name].power *= 1.01; AllGangs[name].power *= 1.009;
} }
} }
} }
@ -448,7 +443,7 @@ Gang.prototype.killMember = function(memberObj) {
} }
} }
Gang.prototype.ascendMember = function(memberObj) { Gang.prototype.ascendMember = function(memberObj, workerScript) {
try { try {
/** /**
* res is an object with the following format: * res is an object with the following format:
@ -459,6 +454,7 @@ Gang.prototype.ascendMember = function(memberObj) {
*/ */
const res = memberObj.ascend(); const res = memberObj.ascend();
this.respect = Math.max(1, this.respect - res.respect); this.respect = Math.max(1, this.respect - res.respect);
if (workerScript == null) {
dialogBoxCreate([`You ascended ${memberObj.name}!`, dialogBoxCreate([`You ascended ${memberObj.name}!`,
`Your gang lost ${numeralWrapper.format(res.respect, "0.000a")} respect`, `Your gang lost ${numeralWrapper.format(res.respect, "0.000a")} respect`,
`${memberObj.name} gained the following stat multipliers for ascending:`, `${memberObj.name} gained the following stat multipliers for ascending:`,
@ -468,10 +464,30 @@ Gang.prototype.ascendMember = function(memberObj) {
`Dexterity: ${res.dex}`, `Dexterity: ${res.dex}`,
`Agility: ${res.agi}`, `Agility: ${res.agi}`,
`Charisma: ${res.cha}`].join("<br>")); `Charisma: ${res.cha}`].join("<br>"));
this.displayGangMemberList(); } else {
} catch(e) { workerScript.log(`Ascended Gang member ${memberObj.name}`);
exceptionAlert(e);
} }
if (routing.isOn(Page.Gang)) {
this.displayGangMemberList();
}
} catch(e) {
if (workerScript == null) {
exceptionAlert(e);
} else {
throw e; // Re-throw, will be caught in the Netscript Function
}
}
}
// Cost of upgrade gets cheaper as gang increases in respect + power
Gang.prototype.getDiscount = function() {
const power = this.getPower();
const respect = this.respect;
const respectLinearFac = 5e6;
const powerLinearFac = 1e6;
const discount = Math.pow(respect, 0.01) + respect / respectLinearFac + Math.pow(power, 0.01) + power / powerLinearFac - 1;
return Math.max(1, discount);
} }
// Returns only valid tasks for this gang. Excludes 'Unassigned' // Returns only valid tasks for this gang. Excludes 'Unassigned'
@ -496,6 +512,15 @@ Gang.prototype.getAllTaskNames = function() {
return tasks; return tasks;
} }
Gang.prototype.getAllUpgradeNames = function() {
return Object.keys(GangMemberUpgrades);
}
Gang.prototype.getUpgradeCost = function(upgName) {
if (GangMemberUpgrades[upgName] == null) { return Infinity; }
return GangMemberUpgrades[upgName].getCost(this);
}
Gang.prototype.toJSON = function() { Gang.prototype.toJSON = function() {
return Generic_toJSON("Gang", this); return Generic_toJSON("Gang", this);
} }
@ -567,8 +592,10 @@ GangMember.prototype.calculatePower = function() {
GangMember.prototype.assignToTask = function(taskName) { GangMember.prototype.assignToTask = function(taskName) {
if (GangMemberTasks.hasOwnProperty(taskName)) { if (GangMemberTasks.hasOwnProperty(taskName)) {
this.task = GangMemberTasks[taskName]; this.task = GangMemberTasks[taskName];
return true;
} else { } else {
this.task = GangMemberTasks["Unassigned"]; this.task = GangMemberTasks["Unassigned"];
return false;
} }
} }
@ -734,11 +761,14 @@ GangMember.prototype.getAscensionResults = function() {
} }
GangMember.prototype.buyUpgrade = function(upg, player, gang) { GangMember.prototype.buyUpgrade = function(upg, player, gang) {
if (!(upg instanceof GangMemberUpgrade)) { if (typeof upg === 'string') {
throw new Error(`Invalid 'upg' argument passed into GangMember.buyUpgrade`); upg = GangMemberUpgrades[upg];
} }
if (player.money.lt(upg.cost)) { return false; } if (!(upg instanceof GangMemberUpgrade)) {
player.loseMoney(upg.cost); return false;
}
if (player.money.lt(upg.getCost(gang))) { return false; }
player.loseMoney(upg.getCost(gang));
if (upg.type === "g") { if (upg.type === "g") {
this.augmentations.push(upg.name); this.augmentations.push(upg.name);
} else { } else {
@ -749,6 +779,7 @@ GangMember.prototype.buyUpgrade = function(upg, player, gang) {
var initFilterValue = UIElems.gangMemberUpgradeBoxFilter.value.toString(); var initFilterValue = UIElems.gangMemberUpgradeBoxFilter.value.toString();
gang.createGangMemberUpgradeBox(player, initFilterValue); gang.createGangMemberUpgradeBox(player, initFilterValue);
} }
return true;
} }
GangMember.prototype.toJSON = function() { GangMember.prototype.toJSON = function() {
@ -822,6 +853,11 @@ function GangMemberUpgrade(name="", cost=0, type="w", mults={}) {
this.createDescription(); this.createDescription();
} }
GangMemberUpgrade.prototype.getCost = function(gang) {
const discount = gang.getDiscount();
return this.cost / discount;
}
GangMemberUpgrade.prototype.createDescription = function() { GangMemberUpgrade.prototype.createDescription = function() {
const lines = ["Increases:"]; const lines = ["Increases:"];
if (this.mults.str != null) { if (this.mults.str != null) {
@ -887,10 +923,10 @@ Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
return; return;
} }
for (var i = 1; i < UIElems.gangMemberUpgradeBoxElements.length; ++i) { for (var i = 2; i < UIElems.gangMemberUpgradeBoxElements.length; ++i) {
removeElement(UIElems.gangMemberUpgradeBoxElements[i]); removeElement(UIElems.gangMemberUpgradeBoxElements[i]);
} }
UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter]; UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter, UIElems.gangMemberUpgradeBoxDiscount];
var filter = UIElems.gangMemberUpgradeBoxFilter.value.toString(); var filter = UIElems.gangMemberUpgradeBoxFilter.value.toString();
for (var i = 0; i < this.members.length; ++i) { for (var i = 0; i < this.members.length; ++i) {
@ -911,7 +947,14 @@ Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
} }
}); });
UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter]; UIElems.gangMemberUpgradeBoxDiscount = createElement("p", {
innerText: "Discount: -" + numeralWrapper.format(1 - 1 / this.getDiscount(), "0.00%"),
marginLeft: "6px",
tooltip: "You get a discount on equipment and upgrades based on your gang's " +
"respect and power. More respect and power leads to more discounts."
});
UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter, UIElems.gangMemberUpgradeBoxDiscount];
var filter = UIElems.gangMemberUpgradeBoxFilter.value.toString(); var filter = UIElems.gangMemberUpgradeBoxFilter.value.toString();
for (var i = 0; i < this.members.length; ++i) { for (var i = 0; i < this.members.length; ++i) {
@ -984,7 +1027,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
for (let upgName in GangMemberUpgrades) { for (let upgName in GangMemberUpgrades) {
if (GangMemberUpgrades.hasOwnProperty(upgName)) { if (GangMemberUpgrades.hasOwnProperty(upgName)) {
let upg = GangMemberUpgrades[upgName]; let upg = GangMemberUpgrades[upgName];
if (player.money.lt(upg.cost)) { continue; } if (player.money.lt(upg.getCost(gangObj))) { continue; }
if (this.upgrades.includes(upgName) || this.augmentations.includes(upgName)) { continue; } if (this.upgrades.includes(upgName) || this.augmentations.includes(upgName)) { continue; }
switch (upg.type) { switch (upg.type) {
case "w": case "w":
@ -1030,9 +1073,9 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
let div = divs[i]; let div = divs[i];
for (let j = 0; j < upgradeArray.length; ++j) { for (let j = 0; j < upgradeArray.length; ++j) {
let upg = upgradeArray[j]; let upg = upgradeArray[j];
(function (upg, div, memberObj, i) { (function (upg, div, memberObj, i, gang) {
let createElementParams = { let createElementParams = {
innerText:upg.name + " - " + numeralWrapper.format(upg.cost, "$0.000a"), innerText: upg.name + " - " + numeralWrapper.format(upg.getCost(gang), "$0.000a"),
class: "a-link-button", margin:"2px", padding:"2px", display:"block", class: "a-link-button", margin:"2px", padding:"2px", display:"block",
fontSize:"11px", fontSize:"11px",
clickListener:()=>{ clickListener:()=>{
@ -1048,7 +1091,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
createElementParams.tooltip = upg.desc; createElementParams.tooltip = upg.desc;
} }
div.appendChild(createElement("a", createElementParams)); div.appendChild(createElement("a", createElementParams));
})(upg, div, this, i); })(upg, div, this, i, gangObj);
} }
} }
@ -1089,6 +1132,7 @@ const UIElems = {
gangMemberUpgradeBox: null, gangMemberUpgradeBox: null,
gangMemberUpgradeBoxContent: null, gangMemberUpgradeBoxContent: null,
gangMemberUpgradeBoxFilter: null, gangMemberUpgradeBoxFilter: null,
gangMemberUpgradeBoxDiscount: null,
gangMemberUpgradeBoxElements: null, gangMemberUpgradeBoxElements: null,
// Gang Territory Elements // Gang Territory Elements
@ -1224,8 +1268,10 @@ Gang.prototype.displayGangContent = function(player) {
// have a gang member with the same name // have a gang member with the same name
if (!this.recruitMember(name)) { if (!this.recruitMember(name)) {
dialogBoxCreate("You already have a gang member with this name!"); dialogBoxCreate("You already have a gang member with this name!");
return false;
} }
removeElementById(popupId);
return false; return false;
}, },
innerText: "Recruit Gang Member", innerText: "Recruit Gang Member",
@ -1428,11 +1474,19 @@ Gang.prototype.displayGangMemberList = function() {
Gang.prototype.updateGangContent = function() { Gang.prototype.updateGangContent = function() {
if (!UIElems.gangContentCreated) { return; } if (!UIElems.gangContentCreated) { return; }
if (UIElems.gangMemberUpgradeBoxOpened) {
UIElems.gangMemberUpgradeBoxDiscount.childNodes[0].nodeValue =
"Discount: -" + numeralWrapper.format(1 - 1 / this.getDiscount(), "0.00%");
}
if (UIElems.gangTerritorySubpage.style.display === "block") { if (UIElems.gangTerritorySubpage.style.display === "block") {
// Territory Warfare Clash Chance // Territory Warfare Clash Chance
UIElems.gangTerritoryWarfareClashChance.innerText = UIElems.gangTerritoryWarfareClashChance.innerText =
`Territory Clash Chance: ${numeralWrapper.format(this.territoryClashChance, '0.000%')}`; `Territory Clash Chance: ${numeralWrapper.format(this.territoryClashChance, '0.000%')}`;
// Engaged in Territory Warfare checkbox
UIElems.gangTerritoryWarfareCheckbox.checked = this.territoryWarfareEngaged;
// Update territory information // Update territory information
UIElems.gangTerritoryInfoText.innerHTML = ""; UIElems.gangTerritoryInfoText.innerHTML = "";
for (var gangname in AllGangs) { for (var gangname in AllGangs) {
@ -1590,12 +1644,12 @@ Gang.prototype.createGangMemberDisplayElement = function(memberObj) {
const statsDiv = createElement("div", { const statsDiv = createElement("div", {
class: "gang-member-info-div", class: "gang-member-info-div",
id: name + "gang-member-stats", id: name + "gang-member-stats",
tooltipsmall: [`Hk: x${numeralWrapper.format(memberObj.hack_mult * memberObj.hack_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.hack_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.hack_asc_mult, "0,0.00")} Asc)`, tooltipsmall: [`Hk: x${numeralWrapper.format(memberObj.hack_mult * memberObj.hack_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.hack_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.hack_asc_mult, "0,0.00")} Asc)`,
`St: x${numeralWrapper.format(memberObj.str_mult * memberObj.str_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.str_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.str_asc_mult, "0,0.00")} Asc)`, `St: x${numeralWrapper.format(memberObj.str_mult * memberObj.str_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.str_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.str_asc_mult, "0,0.00")} Asc)`,
`Df: x${numeralWrapper.format(memberObj.def_mult * memberObj.def_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.def_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.def_asc_mult, "0,0.00")} Asc)`, `Df: x${numeralWrapper.format(memberObj.def_mult * memberObj.def_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.def_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.def_asc_mult, "0,0.00")} Asc)`,
`Dx: x${numeralWrapper.format(memberObj.dex_mult * memberObj.dex_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.dex_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.dex_asc_mult, "0,0.00")} Asc)`, `Dx: x${numeralWrapper.format(memberObj.dex_mult * memberObj.dex_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.dex_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.dex_asc_mult, "0,0.00")} Asc)`,
`Ag: x${numeralWrapper.format(memberObj.agi_mult * memberObj.agi_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.agi_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.agi_asc_mult, "0,0.00")} Asc)`, `Ag: x${numeralWrapper.format(memberObj.agi_mult * memberObj.agi_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.agi_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.agi_asc_mult, "0,0.00")} Asc)`,
`Ch: x${numeralWrapper.format(memberObj.cha_mult * memberObj.cha_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.cha_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.cha_asc_mult, "0,0.00")} Asc)`].join("<br>"), `Ch: x${numeralWrapper.format(memberObj.cha_mult * memberObj.cha_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.cha_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.cha_asc_mult, "0,0.00")} Asc)`].join("<br>"),
}); });
UIElems.gangMemberPanels[name]["statsDiv"] = statsDiv; UIElems.gangMemberPanels[name]["statsDiv"] = statsDiv;
const statsP = createElement("pre", { const statsP = createElement("pre", {
@ -1742,12 +1796,12 @@ Gang.prototype.updateGangMemberDisplayElement = function(memberObj) {
const statsDiv = panel["statsDiv"]; const statsDiv = panel["statsDiv"];
if (statsDiv) { if (statsDiv) {
statsDiv.firstChild.innerHTML = statsDiv.firstChild.innerHTML =
[`Hk: x${numeralWrapper.format(memberObj.hack_mult * memberObj.hack_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.hack_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.hack_asc_mult, "0,0.00")} Asc)`, [`Hk: x${numeralWrapper.format(memberObj.hack_mult * memberObj.hack_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.hack_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.hack_asc_mult, "0,0.00")} Asc)`,
`St: x${numeralWrapper.format(memberObj.str_mult * memberObj.str_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.str_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.str_asc_mult, "0,0.00")} Asc)`, `St: x${numeralWrapper.format(memberObj.str_mult * memberObj.str_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.str_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.str_asc_mult, "0,0.00")} Asc)`,
`Df: x${numeralWrapper.format(memberObj.def_mult * memberObj.def_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.def_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.def_asc_mult, "0,0.00")} Asc)`, `Df: x${numeralWrapper.format(memberObj.def_mult * memberObj.def_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.def_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.def_asc_mult, "0,0.00")} Asc)`,
`Dx: x${numeralWrapper.format(memberObj.dex_mult * memberObj.dex_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.dex_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.dex_asc_mult, "0,0.00")} Asc)`, `Dx: x${numeralWrapper.format(memberObj.dex_mult * memberObj.dex_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.dex_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.dex_asc_mult, "0,0.00")} Asc)`,
`Ag: x${numeralWrapper.format(memberObj.agi_mult * memberObj.agi_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.agi_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.agi_asc_mult, "0,0.00")} Asc)`, `Ag: x${numeralWrapper.format(memberObj.agi_mult * memberObj.agi_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.agi_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.agi_asc_mult, "0,0.00")} Asc)`,
`Ch: x${numeralWrapper.format(memberObj.cha_mult * memberObj.cha_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.cha_mult, "0,0.00")} Up, x${numeralWrapper.format(memberObj.cha_asc_mult, "0,0.00")} Asc)`].join("<br>"); `Ch: x${numeralWrapper.format(memberObj.cha_mult * memberObj.cha_asc_mult, "0,0.00")}(x${numeralWrapper.format(memberObj.cha_mult, "0,0.00")} Eq, x${numeralWrapper.format(memberObj.cha_asc_mult, "0,0.00")} Asc)`].join("<br>");
} }
} }

@ -3593,16 +3593,29 @@ function NetscriptFunctions(workerScript) {
agility: member.agi, agility: member.agi,
agilityEquipMult: member.agi_mult, agilityEquipMult: member.agi_mult,
agilityAscensionMult: member.agi_asc_mult, agilityAscensionMult: member.agi_asc_mult,
augmentation: member.augmentations.slice(),
charisma: member.cha, charisma: member.cha,
charismaEquipMult: member.cha_mult,
charismaAscensionMult: member.cha_asc_mult,
defense: member.def, defense: member.def,
defenseEquipMult: member.def_mult,
defenseAscensionMult: member.def_asc_mult,
dexterity: member.dex, dexterity: member.dex,
dexterityEquipMult: member.dex_mult,
dexterityAscensionMult: member.dex_asc_mult,
equipment: member.upgrades.slice(),
hacking: member.hack, hacking: member.hack,
strength: member.str hackingEquipMult: member.hack_mult,
hackingAscensionMult: member.hack_asc_mult,
strength: member.str,
strengthEquipMult: member.str_mult,
strengthAscensionMult: member.str_asc_mult,
task: member.task.name, task: member.task.name,
} }
} }
} }
workerScript.log(`Invalid argument passed to gang.getMemberInformation(). No gang member could be found with name ${name}`);
return {}; // Member could not be found return {}; // Member could not be found
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberInformation", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberInformation", e));
@ -3616,12 +3629,12 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "canRecruitMember"); nsGang.checkGangApiAccess(workerScript, "canRecruitMember");
try { try {
return Player.gang.canRecruitMember();
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("canRecruitMember", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("canRecruitMember", e));
} }
}, },
recruitMember : function() { recruitMember : function(name) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2); return updateStaticRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
} }
@ -3629,7 +3642,7 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "recruitMember"); nsGang.checkGangApiAccess(workerScript, "recruitMember");
try { try {
return Player.gang.recruitMember(name);
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("recruitMember", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("recruitMember", e));
} }
@ -3642,12 +3655,14 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "getTaskNames"); nsGang.checkGangApiAccess(workerScript, "getTaskNames");
try { try {
const tasks = Player.gang.getAllTaskNames();
tasks.unshift("Unassigned");
return tasks;
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getTaskNames", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getTaskNames", e));
} }
}, },
setMemberTask : function() { setMemberTask : function(memberName, taskName) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2); return updateStaticRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2);
} }
@ -3655,7 +3670,14 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "setMemberTask"); nsGang.checkGangApiAccess(workerScript, "setMemberTask");
try { try {
for (const member of Player.gang.members) {
if (member.name === memberName) {
return member.assignToTask(taskName);
}
}
workerScript.log(`Invalid argument passed to gang.setMemberTask(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setMemberTask", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setMemberTask", e));
} }
@ -3668,12 +3690,12 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "getEquipmentNames"); nsGang.checkGangApiAccess(workerScript, "getEquipmentNames");
try { try {
return Player.gang.getAllUpgradeNames();
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentNames", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentNames", e));
} }
}, },
getEquipmentCost : function() { getEquipmentCost : function(equipName) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2); return updateStaticRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2);
} }
@ -3681,12 +3703,12 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "getEquipmentCost"); nsGang.checkGangApiAccess(workerScript, "getEquipmentCost");
try { try {
return Player.gang.getUpgradeCost(equipName);
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentCost", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentCost", e));
} }
}, },
purchaseEquipment : function() { purchaseEquipment : function(memberName, equipName) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost / 2); return updateStaticRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost / 2);
} }
@ -3694,11 +3716,38 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "purchaseEquipment"); nsGang.checkGangApiAccess(workerScript, "purchaseEquipment");
try { try {
for (const member in Player.gang.members) {
if (member.name === memberName) {
return member.buyUpgrade(equipName, Player, Player.gang);
}
}
workerScript.log(`Invalid argument passed to gang.purchaseEquipment(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("purchaseEquipment", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("purchaseEquipment", e));
} }
}, },
ascendMember : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("ascendMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("ascendMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "ascendMember");
try {
for (const member in Player.gang.members) {
if (member.name === name) {
return Player.gang.ascendMember(member, workerScript);
}
}
workerScript.log(`Invalid argument passed to gang.ascendMember(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("ascendMember", e));
}
},
setTerritoryWarfare : function(engage) { setTerritoryWarfare : function(engage) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2); return updateStaticRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2);
@ -3707,7 +3756,11 @@ function NetscriptFunctions(workerScript) {
nsGang.checkGangApiAccess(workerScript, "setTerritoryWarfare"); nsGang.checkGangApiAccess(workerScript, "setTerritoryWarfare");
try { try {
if (engage) {
Player.gang.territoryWarfareEngaged = true;
} else {
Player.gang.territoryWarfareEngaged = false;
}
} catch(e) { } catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e)); throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e));
} }

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