diff --git a/netscript.js b/netscript.js index 529088b7f..2118a5a3c 100644 --- a/netscript.js +++ b/netscript.js @@ -101,7 +101,14 @@ let NetscriptFunctions = "upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" + "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|" + "getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" + "getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" + diff --git a/src/BitNode.js b/src/BitNode.js index 6c8a79801..2d309becf 100644 --- a/src/BitNode.js +++ b/src/BitNode.js @@ -28,7 +28,9 @@ function initBitNodes() { "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 " + "factions quickly rose to the top of the modern world.

" + - "In this BitNode:

The maximum amount of money available on a server is significantly decreased
" + + "In this BitNode:

" + + "Your hacking level is reduced by 25%
" + + "The growth rate and maximum amount of money available on servers is significantly decreased
" + "The amount of money gained from crimes and Infiltration is tripled
" + "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 " + @@ -214,6 +216,8 @@ function initBitNodeMultipliers() { case 1: //Source Genesis (every multiplier is 1) break; case 2: //Rise of the Underworld + BitNodeMultipliers.HackingLevelMultiplier = 0.75; + BitNodeMultipliers.ServerGrowthRate = 0.75; BitNodeMultipliers.ServerMaxMoney = 0.2; BitNodeMultipliers.ServerStartingMoney = 0.4; BitNodeMultipliers.CrimeMoney = 3; diff --git a/src/Constants.js b/src/Constants.js index 80f299c88..5defbf59a 100644 --- a/src/Constants.js +++ b/src/Constants.js @@ -506,15 +506,18 @@ let CONSTANTS = { v0.41.0 * WARNING: In NetscriptJS, defining a function called print() is no longer possible * Gang Mechanic Changes (BitNode-2): + *** Added a Gang Netscript API *** 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 + *** Maximum number of increased Gang Members increased from 20 to 40 *** 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 *** 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 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 diff --git a/src/Gang.js b/src/Gang.js index 988384838..48f723504 100644 --- a/src/Gang.js +++ b/src/Gang.js @@ -1,11 +1,6 @@ /* 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 balance point to keep them from running out of control */ @@ -39,7 +34,7 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate, // Constants const GangRespectToReputationRatio = 2; // Respect is divided by this to get rep gain -const MaximumGangMembers = 50; +const MaximumGangMembers = 40; const GangRecruitCostMultiplier = 2; const CyclesPerTerritoryAndPowerUpdate = 100; 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; } -Gang.prototype.power() = function() { +Gang.prototype.getPower = function() { return AllGangs[this.facName].power; } @@ -275,9 +270,9 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) { AllGangs[name].power += this.calculatePower(); } else { // 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 *= 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 { /** * res is an object with the following format: @@ -459,21 +454,42 @@ Gang.prototype.ascendMember = function(memberObj) { */ 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(); + if (workerScript == null) { + 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("
")); + } else { + workerScript.log(`Ascended Gang member ${memberObj.name}`); + } + if (routing.isOn(Page.Gang)) { + this.displayGangMemberList(); + } } catch(e) { - exceptionAlert(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' Gang.prototype.getAllTaskNames = function() { let tasks = []; @@ -496,6 +512,15 @@ Gang.prototype.getAllTaskNames = function() { 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() { return Generic_toJSON("Gang", this); } @@ -567,8 +592,10 @@ GangMember.prototype.calculatePower = function() { GangMember.prototype.assignToTask = function(taskName) { if (GangMemberTasks.hasOwnProperty(taskName)) { this.task = GangMemberTasks[taskName]; + return true; } else { this.task = GangMemberTasks["Unassigned"]; + return false; } } @@ -734,11 +761,14 @@ GangMember.prototype.getAscensionResults = function() { } GangMember.prototype.buyUpgrade = function(upg, player, gang) { - if (!(upg instanceof GangMemberUpgrade)) { - throw new Error(`Invalid 'upg' argument passed into GangMember.buyUpgrade`); + if (typeof upg === 'string') { + upg = GangMemberUpgrades[upg]; } - if (player.money.lt(upg.cost)) { return false; } - player.loseMoney(upg.cost); + if (!(upg instanceof GangMemberUpgrade)) { + return false; + } + if (player.money.lt(upg.getCost(gang))) { return false; } + player.loseMoney(upg.getCost(gang)); if (upg.type === "g") { this.augmentations.push(upg.name); } else { @@ -749,6 +779,7 @@ GangMember.prototype.buyUpgrade = function(upg, player, gang) { var initFilterValue = UIElems.gangMemberUpgradeBoxFilter.value.toString(); gang.createGangMemberUpgradeBox(player, initFilterValue); } + return true; } GangMember.prototype.toJSON = function() { @@ -822,6 +853,11 @@ function GangMemberUpgrade(name="", cost=0, type="w", mults={}) { this.createDescription(); } +GangMemberUpgrade.prototype.getCost = function(gang) { + const discount = gang.getDiscount(); + return this.cost / discount; +} + GangMemberUpgrade.prototype.createDescription = function() { const lines = ["Increases:"]; if (this.mults.str != null) { @@ -887,10 +923,10 @@ Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") { return; } - for (var i = 1; i < UIElems.gangMemberUpgradeBoxElements.length; ++i) { + for (var i = 2; i < UIElems.gangMemberUpgradeBoxElements.length; ++i) { removeElement(UIElems.gangMemberUpgradeBoxElements[i]); } - UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter]; + UIElems.gangMemberUpgradeBoxElements = [UIElems.gangMemberUpgradeBoxFilter, UIElems.gangMemberUpgradeBoxDiscount]; var filter = UIElems.gangMemberUpgradeBoxFilter.value.toString(); 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(); for (var i = 0; i < this.members.length; ++i) { @@ -984,7 +1027,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) { for (let upgName in GangMemberUpgrades) { if (GangMemberUpgrades.hasOwnProperty(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; } switch (upg.type) { case "w": @@ -1030,10 +1073,10 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) { let div = divs[i]; for (let j = 0; j < upgradeArray.length; ++j) { let upg = upgradeArray[j]; - (function (upg, div, memberObj, i) { + (function (upg, div, memberObj, i, gang) { let createElementParams = { - innerText:upg.name + " - " + numeralWrapper.format(upg.cost, "$0.000a"), - class:"a-link-button", margin:"2px", padding:"2px", display:"block", + innerText: upg.name + " - " + numeralWrapper.format(upg.getCost(gang), "$0.000a"), + class: "a-link-button", margin:"2px", padding:"2px", display:"block", fontSize:"11px", clickListener:()=>{ memberObj.buyUpgrade(upg, player, gangObj); @@ -1048,7 +1091,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) { createElementParams.tooltip = upg.desc; } div.appendChild(createElement("a", createElementParams)); - })(upg, div, this, i); + })(upg, div, this, i, gangObj); } } @@ -1089,6 +1132,7 @@ const UIElems = { gangMemberUpgradeBox: null, gangMemberUpgradeBoxContent: null, gangMemberUpgradeBoxFilter: null, + gangMemberUpgradeBoxDiscount: null, gangMemberUpgradeBoxElements: null, // Gang Territory Elements @@ -1190,7 +1234,7 @@ Gang.prototype.displayGangContent = function(player) { UIElems.gangManagementSubpage.appendChild(UIElems.gangInfo); UIElems.gangRecruitMemberButton = createElement("a", { - id:"gang-management-recruit-member-btn", class:"a-link-button-inactive", + id: "gang-management-recruit-member-btn", class:"a-link-button-inactive", innerHTML:"Recruit Gang Member", display:"inline-block", margin:"10px", clickListener:()=>{ const popupId = "recruit-gang-member-popup"; @@ -1224,8 +1268,10 @@ Gang.prototype.displayGangContent = function(player) { // have a gang member with the same name if (!this.recruitMember(name)) { dialogBoxCreate("You already have a gang member with this name!"); + return false; } + removeElementById(popupId); return false; }, innerText: "Recruit Gang Member", @@ -1428,11 +1474,19 @@ Gang.prototype.displayGangMemberList = function() { Gang.prototype.updateGangContent = function() { 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") { // Territory Warfare Clash Chance UIElems.gangTerritoryWarfareClashChance.innerText = `Territory Clash Chance: ${numeralWrapper.format(this.territoryClashChance, '0.000%')}`; + // Engaged in Territory Warfare checkbox + UIElems.gangTerritoryWarfareCheckbox.checked = this.territoryWarfareEngaged; + // Update territory information UIElems.gangTerritoryInfoText.innerHTML = ""; for (var gangname in AllGangs) { @@ -1590,12 +1644,12 @@ Gang.prototype.createGangMemberDisplayElement = function(memberObj) { const statsDiv = createElement("div", { class: "gang-member-info-div", 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)`, - `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)`, - `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)`, - `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)`, - `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)`, - `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("
"), + 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")} 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")} 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")} 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")} 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")} Eq, x${numeralWrapper.format(memberObj.cha_asc_mult, "0,0.00")} Asc)`].join("
"), }); UIElems.gangMemberPanels[name]["statsDiv"] = statsDiv; const statsP = createElement("pre", { @@ -1742,12 +1796,12 @@ Gang.prototype.updateGangMemberDisplayElement = function(memberObj) { const statsDiv = panel["statsDiv"]; if (statsDiv) { 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)`, - `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)`, - `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)`, - `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)`, - `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)`, - `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("
"); + [`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")} 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")} 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")} 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")} 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")} Eq, x${numeralWrapper.format(memberObj.cha_asc_mult, "0,0.00")} Asc)`].join("
"); } } diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index bcbd74ef6..712c437c0 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -3593,16 +3593,29 @@ function NetscriptFunctions(workerScript) { agility: member.agi, agilityEquipMult: member.agi_mult, agilityAscensionMult: member.agi_asc_mult, + augmentation: member.augmentations.slice(), charisma: member.cha, + charismaEquipMult: member.cha_mult, + charismaAscensionMult: member.cha_asc_mult, defense: member.def, + defenseEquipMult: member.def_mult, + defenseAscensionMult: member.def_asc_mult, dexterity: member.dex, + dexterityEquipMult: member.dex_mult, + dexterityAscensionMult: member.dex_asc_mult, + equipment: member.upgrades.slice(), 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, } } } + workerScript.log(`Invalid argument passed to gang.getMemberInformation(). No gang member could be found with name ${name}`); return {}; // Member could not be found } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberInformation", e)); @@ -3616,12 +3629,12 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "canRecruitMember"); try { - + return Player.gang.canRecruitMember(); } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("canRecruitMember", e)); } }, - recruitMember : function() { + recruitMember : function(name) { if (workerScript.checkingRam) { return updateStaticRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2); } @@ -3629,7 +3642,7 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "recruitMember"); try { - + return Player.gang.recruitMember(name); } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("recruitMember", e)); } @@ -3642,12 +3655,14 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "getTaskNames"); try { - + const tasks = Player.gang.getAllTaskNames(); + tasks.unshift("Unassigned"); + return tasks; } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getTaskNames", e)); } }, - setMemberTask : function() { + setMemberTask : function(memberName, taskName) { if (workerScript.checkingRam) { return updateStaticRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2); } @@ -3655,7 +3670,14 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "setMemberTask"); 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) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setMemberTask", e)); } @@ -3668,12 +3690,12 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "getEquipmentNames"); try { - + return Player.gang.getAllUpgradeNames(); } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentNames", e)); } }, - getEquipmentCost : function() { + getEquipmentCost : function(equipName) { if (workerScript.checkingRam) { return updateStaticRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2); } @@ -3681,12 +3703,12 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "getEquipmentCost"); try { - + return Player.gang.getUpgradeCost(equipName); } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentCost", e)); } }, - purchaseEquipment : function() { + purchaseEquipment : function(memberName, equipName) { if (workerScript.checkingRam) { return updateStaticRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost / 2); } @@ -3694,11 +3716,38 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "purchaseEquipment"); 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) { 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) { if (workerScript.checkingRam) { return updateStaticRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2); @@ -3707,7 +3756,11 @@ function NetscriptFunctions(workerScript) { nsGang.checkGangApiAccess(workerScript, "setTerritoryWarfare"); try { - + if (engage) { + Player.gang.territoryWarfareEngaged = true; + } else { + Player.gang.territoryWarfareEngaged = false; + } } catch(e) { throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e)); } diff --git a/src/NetscriptGang.js b/src/NetscriptGang.js index 4ab5c005a..638bba084 100644 --- a/src/NetscriptGang.js +++ b/src/NetscriptGang.js @@ -2,16 +2,14 @@ import {Player} from "./Player"; import {Gang} from "./Gang"; import {makeRuntimeRejectMsg} from "./NetscriptEvaluator"; -function unknownGangApiExceptionMessage(functionName, err) { +export function unknownGangApiExceptionMessage(functionName, 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 hasAccess = Player.gang instanceof Gang; if (!hasAccess) { throw makeRuntimeRejectMsg(workerScript, accessDenied); } } - -export {unknownBladeburnerActionErrorMessage, unknownBladeburnerExceptionMessage, checkBladeburnerAccess};