UPDATED! 2.9GB BladeBurner Script v8 w COLOR HUD

UPDATED! 2.9GB BladeBurner Script v8 w COLOR HUD

Introduction


UPDATED! 2.9GB BladeBurner Script v8 w COLOR HUD image 1

UPDATED! 2.9GB BladeBurner Script v8 w COLOR HUD image 2

The latest update removes various redundant functions, and also uses nested loops to make the mission scanning process faster, and stop Black Op scanning of completed missions for quicker decision making. It also uses external script running code (adapted from the excellent Alain Bryden) to maintain a small 2.9 GB memory footprint - now you can start running Blade Ops from the start!

The Log Window is used as a small-sized HUD to see what's happening. This prevents you from having to scroll through the BladeBurner menu constantly, and you can minimise it and shift the log HUD to the side of the screen when not in use.

Let's go through the new COLOR status display now:

* For ease of viewing, Mission info is now grouped by color type for easy reference - ๐ŸŸจYellow for Contracts, ๐ŸŸฆBlue for Operations and ๐ŸŸชPurple for Black Ops (you can of course change the colors in the code).

* A new line called "Additional Mission Info" is for displaying misc. info for the current task (this removes the need for a dedicated space for status data, and frees up 1-2 lines)

Briefly the HUD shows:

* ๐Ÿ’˜Health as a percentage, ๐Ÿ“–skill points owned / points needed for next skill

* ๐Ÿ Current city, ๐Ÿ—กBladeBurner rank (need 400k to beat node) & ๐ŸฉธHealing Status

* ๐Ÿ”ฅChaos level / previous Chaos level, ๐Ÿ‘ฅPopulation count & ๐Ÿ’Community count

* Success settings for %% Missions and %b Black ops, Missions Left for #c Contracts and #o Operations

* Contract (c), Operations (o) & Black Op (b) success rates

* โ›—โ›—Spread Chance Setting, and c, o, b Mission Spread Chances

* ๐ŸšฉAdditional Mission Info (e.g. showing communities left in Raid ops etc)

* ๐ŸšถCurrent Action status line with description, comment, level and time needed

* Lastly the โ–‘๐ŸŒŸโ–‘ stars in the top bar mean we can scroll up to show Skills Bought Recently

Script Components


UPDATED! 2.9GB BladeBurner Script v8 w COLOR HUD image 19

Here is a quick overview of what the script does. Some notes first:

If you don't have certain Source Files (e.g. Singularity), you can actually comment out those sections. For the next update I will try to make it easier for beginner players who don't have SF from other BitNodes to turn these features ON/OFF.

Commented lines with "DEBUG" in them can be un-commented to allow you to see how certain things work. You can delete them if you want.

Mission titles are now hard-coded at the start to remove calls for get-mission-names to speed up the script. If they change in future, follow the instructions in the comments to update them

Rules for skill upgrading are my own preference- you can adjust to your own rulesets. I prefer to concentrate totally on skills to complete the node, and ignore skills which won't help you complete the last Daedalus mission (e.g. "Cloak" or "Short Circuit").

a. Settings

* Declare global variables and arrays

* CUSTOM SETTINGS are next. Mainly minimum mission success %'s, rest action and skill buying

b. canWork Function - see if we can work

* Check stamina and set auto-heal to ON. Healing will stop automatically when completed

* If stamina is fine or healing finished, then we 'can' work.

c. rest Function - while healing, do some stuff

* Check current city chaos and do Retirement or set Diplomacy to ON if needed

* Check if mission success % spreads are too wide, if so do Field Analysis

* If above are fine, do the designated rest function. This can be training, healing, a Singularity action like going to the Gym or Crime etc

d. work Function - do missions

* Loop through each city and update city info (pop, chaos, communities etc) AND get all the Contract, Operations and Black Op mission info too from that city. Mission chances in each city differ (normally those further from Sector-12 are tougher)

* Pick the best missions from each mission type

* Check Black Ops for a valid mission, if so do it and exit - This strips out the lowest ranked Black Ops missions in each city and puts them into an array for reducing.

* Do Raids or Stings if we can WITHOUT risking population level (this is a new addition to address comments that previously we were ignoring them). They will not let the population go below the minimum (set in settings section) and thus avoid screwing up success chances.

* Check Operations for a valid mission, if so do it and exit - We check Operations first because we prefer them over Contracts.

* Check Contracts for a valid mission, if so do it and exit

e. checkSkills Function - Buy skills

* If autobuying of skills is set, then autobuy a skill

* If manual buying is set, then buy according to the skills designated

* For any skill bought, dump it to the HUD (to see it scroll up the HUD). Random numbers are added to the end so that if you farm skill points and keep buying a skill, you can see them scroll.

f. MAIN ASYNC Function

* At start: Check if we have BN4.1 Singularity - this affects whether the script automatically stops user actions. You should thus aim to get The Blade's Simulacrum aug asap in order to be able to do other stuff

* Join BladeBurner faction if able, and set all missions to autolevel if set

* WHILE LOOP

____* Check if we can work via (canWork) function

____* If we can work, run work via (work) function

____* If we can't work, run rest via (rest) function

____* Display and update HUD

g. FUNCTIONS

* Sleep

* Get mission chance

* Get mission counts

* Get skill learnt level

* Center text for HUD

* Do Blade Action

* External script runner

* Text color class

Code Part 1: Settings

//=============================================================================== // BLADE v8: by Troff - ONLY 2.90GB RAM required - Sys code 4 // Tightened code for scanning missions and ops, improved Raids and Stings. // Minor improvements include removing or replacing non-essential functions // (to speed up script), COLOR HUD, display bug fixes & code optimising // You can turn ON lines marked DEBUG to get a further understanding or // for troubleshooting. Feel free to delete them (as they're not required) // #### Set default GLOBAL variables START (DO NOT CHANGE anything here) #### let stamina = 0; let skpts = 0; let skreq = 0; let blrank = 0; let healstatus = 0; // Are we healing? 0=no, 1=yes let healstatnam = "."; // Name of healing status let diplomacystatus = 0; // Are we are doing diplomacy? // Hard-coded Contracts names (for future changes, update with below function) // contracts = ns.bladeburner.getContractNames(); // var opdebug=contracts.toString(); ns.print(opdebug); // copy names from here let contracts = ["Tracking", "Bounty Hunter", "Retirement"]; // Hard-coded Ops (for future changes, update with below function) //operations = ns.bladeburner.getOperationNames(); //var opdebug=operations.toString(); ns.print(opdebug); // copy names from here let operations = ["Investigation", "Undercover Operation", "Sting Operation", "Raid", "Stealth Retirement Operation", "Assassination"]; // Hard-coded Black Ops (for future changes, update with below function) //const blackops=await runCom1(ns,'ns.bladeburner.getBlackOpNames()','getBlOps'); //var txdebug=blackops.toString(); ns.print(txdebug); // copy names from here let blackops = [ "Operation Typhoon", "Operation Zero", "Operation X", "Operation Titan", "Operation Ares", "Operation Archangel", "Operation Juggernaut","Operation Red Dragon", "Operation K", "Operation Deckard", "Operation Tyrell", "Operation Wallace", "Operation Shoulder of Orion","Operation Hyron","Operation Morpheus", "Operation Ion Storm", "Operation Annihilus", "Operation Ultron", "Operation Centurion", "Operation Vindictus", "Operation Daedalus" ]; let cityinfo = []; // Cities array to contain info let citynam1 = "Sector-12"; // Starting city name variable let citychos = 0; // Current city chaos let citychos2 = 0; // City chaos history buffer let citychos3 = 0; // More buffer for chaos history let citypopu = 0; // Current city p0pulation let citycomm = 0; // Current city communities let Cont = []; // Create array for Contracts Info let Oper = []; // Array for Operations Info let BlOp = []; // Create array for Black Ops Info let bestCon = []; // Create array for BEST C0ntract let bestOp = []; // Array for BEST Operation let bestBlackOp = []; // Create array for BEST Black Ops let concount = 0; // Contract number missions available let opcount = 0; // Operation number missions available let conspread = 0; // Contract spread chance (decimal) let opspread = 0; // Operation spread chance (decimal) let blspread = 0; // Black Ops spread chance (decimal) let conper0 = 0; // Lower limit contract chance let conper1 = 0; // High limit contract chance let opper0 = 0; // Lower limit operation chance let opper1 = 0; // High limit operation chance let blacper0 = 0; // Lower limit blackop chance let blacper1 = 0; // Higher limit blackop chance let blacstart = 0; // Used to skip completed blackop results let statuscity = ""; // Whether we changed citi for ra!ds/retirement let statusline = "None"; // Status line showing action done let skstat = false; // Default skill log status line let citylist=["Sector-12","Aevum","Volhaven","Chongqing","New Tokyo","Ishima"]; let cityCur = "Sector-12"; // Current citi residing in // Below are skills-bought notification flags and manual skill slots (5 slots) var sk = ["N/A", "N/A", "N/A", "N/A", "N/A"]; var sknam = ["x","x","x","x","x"]; let singularflag=false; // Auto-detect whether we using singularity (need BN 4.1) // #### Set default GLOBAL variables END #### //############## SETTINGS START ############################### // Change what you need here: let minsuccess = 0.94; //Minimum success chance for Contracts & Ops let minsucblac = 0.95; //Min. chance for BlackOps. (don't set it to 1.00) let minspread = 0.04; //Min. chance spread (if we need field analysis) let autolevelflag = true; //Sets mission auto-leveling (some might set this //false at start of a node - better leave true) let gymtime = 250333; //Time allocated for each spurt of training in gym (ms) let crimetime = 3033; //Time to crime (in ms) for Homicide let stammin = 50; //Minimum stamina to stop working (in percent %) let raidstingpop = 1000111; //Lowest p0pulation allowed for Sting and Ra!d ops //Note: Set maxchaos > chaoslow > maxchaosretire or weird stuff happens let maxchaos = 50; //Max chaos in a citi before we need to do diplomacy let chaoslow = 40; //Chaos level to stop diplomacy (don't set too low) let maxchaosretire = 20; //Chaos above which we allow Stealth Retirement ops //SHOW SKILL PURCHASES? - set to false to avoid skills bought line statuses var skstatus = true; //DEFAULT TASKS FOR REST (choose ONE only) //"Training" is a safe bet, as doesn't involve clashes / singularity actions //Category (restcat), Type (restype) & C0mment (restcom), add more if desired: var restcat="general"; var resttype="Training"; var restcom="Training (@rest)"; //var restcat="Gym"; var resttype="agility"; var restcom="GYM Agility (@rest)"; //var restcat="general"; var resttype="Recruitment"; var restcom="Recruit (@rest)"; //var restcat ="general"; var resttype ="Hyperbolic Regeneration Chamber"; var restcom = "Hy-Bol. Chamb. (@rest)"; //var restcat="Crime"; var resttype="homicide"; var restcom="CR>Homicide(@rest)"; //AUTO Skill Purchasing (if true it will make skill purchases automated) //(Shouldn't need MANUAL, as auto skill purchase is quite good by itself) var skautobuy = true; //MANUAL Skill Purchasing - use for fine-tuning, or farming hack skill etc //If auto skill buying above is turned off, this manages manual skill purchase //Re-order/c0mment each line of list below to set up manual buy preferences //Skills will auto-scale & auto-buy due to cost increases & order preferences sknam[0]="Blade\'s Intuition"; // Preferred 1st slot //sknam[1]="Digital Observer"; // slot 2: Add more if you like, sknam[2]="Overclock"; // slot 3: but also expand the sknam[3]="Reaper"; // slot 4: sknam[] default array sknam[4]="Evasive System"; // slot 5: above too. //########## SETTINGS END ###################################

Code Part 2: CanWork, Rest & Work

// CAN WE WORK? function ==================== export async function canWork(ns) { //Get ๐Ÿ’˜Stamina status in percent % const res = await runCom1(ns, 'ns.bladeburner.getStamina()', 'getStam'); stamina = 100 * (res[0] / res[1]); //ns.print("INFO Stamina % = " + stamina); //DEBUG (C0mment if not needed) //IF Stamina < Minimum stamina, set status to heal & change heal status icon if (stamina < stammin) { if (healstatus ==0) { //ns.print("INFO Heal Status: STARTED"); // DEBUG healstatnam = "๐ŸŸข"; } healstatus = 1; return false; // I.E. We can't work } // If we are in process of healing, do nothing if (stamina >= stammin && stamina <99 && healstatus == 1) { //ns.print("WARN Heal Status: ON"); // DEBUG healstatnam = "โœ…"; return false; } // If we are not healing BUT above minimum stamina, then do nothing if (stamina >= stammin && healstatus == 0) { //ns.print("WARN Heal Status: Off"); // DEBUG healstatnam = "โŒ"; return true; } // If we are healed enough, stop healing if (stamina >= 99 && healstatus == 1) { healstatus = 0; //ns.print("INFO Heal Status: STOPPED"); // DEBUG healstatnam = "๐Ÿ”ด"; return true; } ns.print("ERROR SOMETHING WENT WRONG"); // means something not working return false; } //REST function ===================== export async function rest(ns) { //@@@@@ CHECK CITI CHAOS LEVELS Start @@@@@ //ns.print("INFO ## City chaos = " + citychos ); // DEBUG //IF citi chaos is more than maximum allowed, turn Diplomacy ON if (citychos > maxchaos) { // Check Retirement chance in current city var idxtem = Oper.findIndex(x => x.opcitnam === cityCur && x.name === "Stealth Retirement Operation"); var retirecount= Oper[idxtem].counts; var retirechance= Oper[idxtem].chance; //ns.print(">REST Retire #:" + retirecount + " ๐Ÿ”ฎ:"+ns.nFormat( retirechance[0],"0.0%")+"/ "+retispread); // DEBUG // See if we can do Stealth Retirement instead to lower chaos if (retirechance[0] >= minsuccess && retirecount > 0 && cityinfo[idxtem].pop > raidstingpop) { statuscity = "[Retirement to lower Chaos]"; return await doAct(ns,"operation","Stealth Retirement Operation","Stlh Retire (rest)","y"); } // Otherwise do normal Diplomacy... if (diplomacystatus ==0) { statusline="Diplomacy: TURNED ON> 60s"; } diplomacystatus = 1; return await doAct(ns,"general", "Diplomacy", "Diplomacy ON","y"); } // If we are in process of Diplomancy, continue to do diplomacy if (citychos <=maxchaos && citychos > chaoslow && diplomacystatus == 1) { statusline="INFO Diplomacy Target:" + chaoslow +" >60s"; return await doAct(ns,"general", "Diplomacy", "Diplomacy...","y"); } // If we not doing diplomacy but below Chaos minimum, do nothing if (citychos <= maxchaos && diplomacystatus == 0) { //ns.print("INFO Diplomacy: Still off..."); // DEBUG } // If City Chaos is below minimum, stop Diplomacy-ing if (citychos <= chaoslow && diplomacystatus == 1) { diplomacystatus = 0; statusline="Diplomacy: FINISHED"; } //@@@@@ CHECK CITY CHAOS LEVELS End @@@@@ // If chance spread is too large, then set "rest action" to field analysis if (conspread > minspread || opspread > minspread || blspread > minspread) { var restCat = "general"; var resType = "Field Analysis"; var restCom = "Field An. (@rest)"; } // Do the REST task selected (transfer settings & capitalise letters) var miscat = restcat.charAt(0).toUpperCase() + restcat.substring(1); var mistype = resttype.charAt(0).toUpperCase() + resttype.substring(1); var miscom = restcom.charAt(0).toUpperCase() + restcom.substring(1); //###If Singularity action is GYM then do it ### if (miscat == "Gym"){ // Travel to Sector-12 await runCom1(ns, 'ns.travelToCity(ns.args[0])', 'goCity', ["Sector-12"]); var miscat = "Powerhouse Gym"; // Best Gym statusline = "๐Ÿšถ: " + miscom.substring(0,23); await runCom1(ns, 'ns.gymWorkout(ns.args[0],ns.args[1])', 'goGym', [miscat, mistype]); return gymtime ; // in 1000's; } //#####Singularity action - CRIME ###### if (miscat == "Crime"){ statusline = "๐Ÿšถ: " + miscom.substring(0,23); await runCom1(ns, 'ns.commitCrime(ns.args[0])', 'goCrime', [mistype]); return crimetime ; // in 1000's; } //Do the REST action and output to console return await doAct(ns,miscat, mistype, miscom.substring(0,23) ); } //============ REST FUNCTION END ============ //=============== WORK FUNCTION START ================ export async function work(ns) { var idxcon = 0; // Master index counter for Contracts array var idxop = 0; // Master index counter for Operations array var idxbl = 0; // Master index counter for Black Ops array BlOp = []; // Initialise Black Ops array (as it needs updating) // &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // &&&&&&&&&&& Check each city mission info START &&&&&&&&&&&& for(var cx=0; cx < citylist.length; cx++){ citynam1 = citylist[cx]; //Switch and travel to the city var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [citynam1]); // Get that city's population, chaos, number of communities info var tempop = await runCom1(ns, 'ns.bladeburner.getCityEstimatedPopulation(ns.args[0])', 'getPop', [citynam1]); var temchaos = await runCom1(ns, 'ns.bladeburner.getCityChaos(ns.args[0])', 'getChaos', [citynam1]); var temcomm = await runCom1(ns, 'ns.bladeburner.getCityCommunities(ns.args[0])', 'getComm', [citynam1]); // Map city info and put it into cities array let Tem = { idx1: cx, name: citylist[cx], pop: tempop, chaos: temchaos, comm: temcomm }; //cityinfo.push(Tem); cityinfo.splice(cx, 1, Tem); // Use Splice to insert & update, not push //ns.print(cityinfo[cx].idx1 ,". ", cityinfo[cx].name,", Pop:", ns.nFormat( cityinfo[cx].pop,"0.00a"),", ๐Ÿ”ฅ:", ns.nFormat( cityinfo[cx].chaos,"0"),", ๐Ÿ’:", cityinfo[cx].comm ); // List city info DEBUG ๐Ÿคทโ€โ™‚๏ธ Lists city info // ****** Extract City's Contract Mission Info START ****** for (let cj = 0; cj < contracts.length; cj++) { let ConTem = { idx1: idxcon, // Master array index idx2: cj, // Contract index city: cx, // City index concitnam: citylist[cx], // City name type: "Contract", // Mission Type name: contracts[cj], // Contract Name chance: await getChance("contract", contracts[cj], ns), // Success % counts: await getCounts("contract", contracts[cj], ns) // # Count }; //Cont.push(ConTem); // Push entry into Contract array Cont.splice(idxcon, 1, ConTem); // Insert at specific position in array //ns.print(Cont[idxcon].idx1 ,". ", citylist[cx]," > ",cj,". ",Cont[idxcon].name," %",Cont[idxcon].chance," #",Cont[idxcon].counts); // List contracts DEBUG idxcon = idxcon + 1; // Increment contracts index counter } // ****** Extract Contract Mission Info END ******

Code Part 3a: Work (Reduce/Black Ops)

// ****** Extract City's Operations Mission Info START ****** for (let oj = 0; oj < operations.length; oj++) { let OpTem = { idx1: idxop, // Master array index idx2: oj, // Operation index city: cx, // City index opcitnam: citylist[cx], // City name type: "Operation", // Mission Type name: operations[oj], // Contract Name chance: await getChance("operation", operations[oj], ns), counts: await getCounts("operation", operations[oj], ns) }; //Oper.push(OpTem); // Push entry into Operations array Oper.splice(idxop, 1, OpTem); // Insert at specific position in array //ns.print(Oper[idxop].idx1 ,". ", citylist[cx]," > ",oj,". ",Oper[idxop].name," %",Oper[idxop].chance," #",Oper[idxop].counts); // List operations DEBUG idxop = idxop + 1; // Increment contracts index counter } // ****** Extract City's Operations Mission Info END ****** // ****** Extract city BLACK OP data into BlackOps array START ***** var lowestrank = 450111; // Default Black Op rank to compare to for (let bj = blacstart; bj < blackops.length; bj++) { let BlacTem = { idx1: idxbl, // Master index in array idx2: bj, // Black Op list index city: cx, // City index blcitnam: citylist[cx], // City name type: "Blackop", // Mission type name: blackops[bj], // Black Op name chance: await getChance("blackop", blackops[], ns), counts: await runCom1(ns, 'ns.bladeburner.getActionCountRemaining(ns.args[0], ns.args[1])', 'getCounts', ["blackop", blackops[bj] ] ), rankok: await runCom1(ns, 'ns.bladeburner.getBlackOpRank(ns.args[0])', 'getBlOpRnk', [] ] ) }; // If available Black Op is equal or lower ranked, add it to array if (lowestrank >= BlacTem.rankok && BlacTem.counts == 1) { lowestrank = BlacTem.rankok; BlOp.push(BlacTem); // Add entry to Black Op array //ns.print(BlOp[idxbl].idx1,". ",BlOp[idxbl].blcitnam,": ",BlOp[idxbl].name," %",BlOp[idxbl].chance[0]," #",BlOp[idxbl].counts," k:",BlOp[idxbl].rankok); // List Black Ops info DEBUG idxbl = idxbl + 1; // Increment contracts index counter } // If blackop is completed, don't scan it in future (speeds up scanning) if (BlacTem.counts == 0 && idxbl < 21) { blacstart = blacstart + 1; } //ns.print("blacstart: ", blacstart); //DEBUG } //ns.print("WARN Lowest Rank of Black Op: ", lowestrank); //DEBUG // ****** Extract city Black Op data into BlackOps array END ***** } // &&&&&&&&&&&&& Check each city mission info END &&&&&&&&&&&& // &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //REDUCE CONTRACTS: If 1st one's chance is greater than the 2nd one (no 'or //equals' thus later cities will get priority) & has missions, choose it bestCon = Cont.reduce((a, b) => ( (a.chance[0] > b.chance[0] && a.counts > 0) ? a : b) ); //REDUCE OPERATIONS: If 1st one's chance is higher AND has missions left, //choose it OR the 2nd one is Sting/Raid/has no missions, choose 1st one //Note: We reject STINGS, RAIDS, STEALTH RETIREMENT first (for now) bestOp = Oper.reduce((a, b) => ( ( (a.chance[0] > b.chance[0] && a.counts>0) || (b.name == "Sting Operation" || b.name == "Raid" || b.name == "Stealth Retirement" || b.counts < 1 ) ) ? a : b) ); // If we've completed Node, insert fake sample into BlOp to continue script if (BlOp.length == 0) { var sample = {}; sample.idx1 = -1; sample.idx2 = -1; sample.city = 1; sample.blcitnam = "Sector-12"; sample.type = "Blackop"; sample.name = "Sample Name"; sample.chance = [0,0]; sample.counts = 0; sample.rankok = 0; BlOp.push(sample); } // REDUCE Black Ops: (If 1st one is in a nearer city, then select it. //Note: Ops difficulty increases in farther cities, so choose nearer ones //bestBlackOp = BlOp.reduce( (a, b) => ( a.chance[0] >= b.chance[0] && a.counts>0 && a.rankok <= b.rankok && a.idx2 < b.idx2 ) ? a : b ); // Previous version bestBlackOp = BlOp.reduce( (a, b) => ( a.idx1 < b.idx1 ) ? a : b ); //DEBUG - these 3 lines print out the best Contract, Operation & Black Op //ns.print("\n*Best ", bestCon.type.substring(0,8), " @",citylist[bestCon.city].substring(0,12), " #",bestCon.counts, "\n>> ", bestCon.name.substring(0,14), ": ", ns.nFormat( (bestCon.chance[0] * 100 ) ,"0.0"), "-", ns.nFormat( bestCon.chance[1]*100,"0.0"), "%" ); //ns.print("\n*Best ", bestOp.type.substring(0,9)," @",citylist[bestOp.city].substring(0,12), " #",bestOp.counts, "\n>> ", bestOp.name.substring(0,14), ":", ns.nFormat( (bestOp.chance[0] * 100 ) ,"0.0"), "-", ns.nFormat( bestOp.chance[1]*100,"0.0"), "%" ); //ns.print("INFO\n*Best ", bestBlackOp.type.substring(0,9)," @", citylist[bestBlackOp.city].substring(0,9), " #",bestBlackOp.counts, "\n>> ", bestBlackOp.name.substring(0,14), ":", ns.nFormat( (bestBlackOp.chance[0] * 100 ) ,"0.0"), "-", ns.nFormat( bestBlackOp.chance[1]*100,"0.0"), "%" ); //Extract chances, spreads & counts of best C0ntract, 0perations, bl@ck ops conper0 = bestCon.chance[0] * 100; // Lower limit contract chance conper1 = bestCon.chance[1] * 100; // High limit contract chance conspread = ns.nFormat((bestCon.chance[1]-bestCon.chance[0]), "0.000"); concount = bestCon.counts; opper0 = bestOp.chance[0] * 100; // Lower limit operation chance opper1 = bestOp.chance[1] * 100; // High limit operation chance opspread = ns.nFormat((bestOp.chance[1]-bestOp.chance[0]), "0.000"); opcount = bestOp.counts; blacper0 = bestBlackOp.chance[0] * 100; // Lower limit blackop chance % blacper1 = bestBlackOp.chance[1] * 100; // Higher limit blackop chance % blspread=ns.nFormat((bestBlackOp.chance[1]-bestBlackOp.chance[0]),"0.000"); var blcount = bestBlackOp.counts; // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // $$$$$$$$$$$$$$$$$$$ BLACK OPS CHECK $$$$$$$$$$$$$$$$$$$$$ var blackOpReqRank = bestBlackOp.rankok; // Get required rank for Black Op // If Black Op success is achievable & ranked enough & has missions, do it if (bestBlackOp.chance[0]>=minsucblac && blrank>=blackOpReqRank && blcount>0) { //Check spre@d and do field analysis if need be //Note: Optimally, we do analysis checks AFTER checking mission chances, so //we need separate analysis checks for EACH contract, op & black op parts //ns.print("blspread: ", blspread, " minspread: ", minspread); //DEBUG if (blspread > minspread) { // Show chance success statuscity = "๐ŸšฉBlack Op chance> " +ns.nFormat(bestBlackOp.chance[0]*100,"0.0") +"%"; return await doAct(ns,"general","Field Analysis","Field A. (Black Ops)"); } // Do the Black Op var skilnam = bestBlackOp.name; // Black Op name var skiltyp = bestBlackOp.type; // Black Op type cityCur = bestBlackOp.blcitnam; // Update status HUD city name var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', []); //Go to the city // Show city travelled to, and chance success statuscity="๐Ÿšฉ"+cityCur+">> BLACK OP: "+ns.nFormat(bestBlackOp.chance[0]*100,"0.0") +"%"; var comm = "B>" + skilnam.substring(0,22); comm = comm.replace('eration',''); // Shorten "Operation" to "Op" return await doAct(ns,skiltyp, skilnam, comm, "y"); // Do black op!!! }

Code Part 3b: Work (Raids/Stings)

//$$$$$$$ NEW RAID / STING Extra Check SECTION - START (new feature) $$$$$$ //The aim of this new section is to tap on the previously unused Raids // and Stings (since they had adverse chaos, pop and mission count // effects). This section will conduct raids and stings where necessary, // and where applicable will use Stealth Retirement to keep Chaos down. //As your increase stats & lower spre@ds for Contracts - Operation missions // in other cities slowly become available and open up for execution. // //This section will automatically stop/skip if Chaos levels of the city // get too high, or the p0pulation drops below a certain amount. Both // of these can be adjusted in the settings. //ns.print("๐Ÿšฉ Checking Raids/Stings..."); // DEBUG // $$$$$$ LOOP CITIES START $$$$$$ for raids/stings (ra!ds are higher priority) statuscity = "[No extra actions]"; // Reset change city status for (var ij=0; ij < citylist.length; ij++) { // Get info of the city citynam1 = cityinfo[ij].name ; // City we are checking var stiId = (ij * 6) + 2; // Index of St!ng in Operations array var raiId = (ij * 6) + 3; // Index of Raid in Operations array var retId = (ij * 6) + 4; // Index of Retirement in Ops array var assId = (ij * 6) + 5; // Index of Assassinate in Ops array var stingcount = Oper[stiId].counts; var stingchance = Oper[stiId].chance; var raidcount = Oper[raiId].counts; var raidchance = Oper[raiId].chance; var retirecount= Oper[retId].counts; var retirechance= Oper[retId].chance; var asscount = Oper[assId].counts; var asschance = Oper[assId].chance; var stingspread = ns.nFormat((stingchance[1]-stingchance[0]), "0.000"); var raidspread = ns.nFormat((raidchance[1]-raidchance[0]), "0.000"); var retispread = ns.nFormat((retirechance[1]-retirechance[0]), "0.000"); // DEBUG LINES to show city st!ng/raid/retirement mission info //ns.print("๐ŸšฉChecking City: " + citynam1 + "๐Ÿšฉ"); // DEBUG //ns.print(">STING #:" + stingcount + " ๐Ÿ”ฎ:"+ns.nFormat( stingchance[0],"0.0%")+" / "+stingspread); // DEBUG //ns.print(">Raid #:" + raidcount + " ๐Ÿ”ฎ:"+ns.nFormat( raidchance[0],"0.0%")+" / "+raidspread); // DEBUG //ns.print(">Retire #:" + retirecount + " ๐Ÿ”ฎ:"+ns.nFormat( retirechance[0],"0.0%")+"/ "+retispread); // DEBUG // Do Stealth Retiremnt (lowers chaos) if there's too much chaos. Check // count, success rate, pop, and less missions available than assassinate if (cityinfo[ij].chaos > maxchaosretire && retirecount > 0 && retirechance[0] >= minsuccess && asscount < retirecount && cityinfo[ij].pop > raidstingpop) { cityCur = citynam1; // Update status HUD city name var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', []); //Go to the city // Show city travelled to, and p0pulation citypopu = cityinfo[ij].pop; statuscity = "๐Ÿšฉ"+citynam1+" ๐Ÿ‘ฅ:"+ns.nFormat(citypopu,"0.0a"); return await doAct(ns,"operation","Stealth Retirement Operation","Stl Retire (new)","y"); } //Skip to next city if p0pulation too low (thus don't want Stings & Raids) if (cityinfo[ij].pop < raidstingpop ) { //ns.print("Pop ๐Ÿ‘ฅ: "+ns.nFormat(Cityinfo[ij].pop,"0.0a") + "< RaidstingPop?: "+ ns.nFormat(raidstingpop,"0.0a") + ">SKIPPED CITY"); //DEBUG continue; } //If any SPREADS for Sting, Raids and Retiremnt are too large, and the // chances are below the minimum success level, AND there are few // contract and operation missions left, then do Field Analysis. if ( (stingspread>minspread || raidspread>minspread || retispread>minspread) && (stingchance[0]>=minsuccess || raidchance[0]>=minsuccess || retirechance[0]>=minsuccess) && ( concount < 5 && opcount < 5 ) ) { cityCur = citynam1; var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [] ); //Go to the city // Show city went to, and spreads for s-Sting, R-R@id, r-Retiremnt statuscity = "๐Ÿšฉ"+citynam1.substring(0,7)+"โ›—โ›— s" + ns.nFormat((stingspread*100), "0.0") +"% R" +ns.nFormat((raidspread*100), "0.0") +"% r" + ns.nFormat((retispread*100), "0.0") +"%"; return await doAct(ns,"general", "Field Analysis", "Field Ana (new)"); } // Do ra!d if rules met (counts, success chance, chaos & communities) if ( raidcount>0 && raidchance[0] >= minsuccess && cityinfo[ij].chaos < maxchaos && cityinfo[ij].comm > 0 && raidcount > asscount ) { cityCur = citynam1; var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', []); //Go to the city // Show city travelled to, and communities left for R@id statuscity = "๐Ÿšฉ"+(ij+1) +"-" +citynam1.substring(0,9) +" "+ns.nFormat((raidchance[0]*100), "0.0") +"% ๐Ÿ’" + cityinfo[ij].comm; return await doAct(ns,"operation", "Raid", "RAID (new)","y"); } // Do Sting if conditions met(counts, success chance, retire chaos level, pop) if (stingcount >0 && stingchance[0] >=minsuccess && cityinfo[ij].chaos <maxchaosretire && cityinfo[ij].pop >raidstingpop){ cityCur = citynam1; var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', []); //Go to the city // Show city travelled to, and p0pulation citypopu = cityinfo[ij].pop; statuscity = "๐Ÿšฉ"+citynam1+" ๐Ÿ‘ฅ:"+ns.nFormat(citypopu,"0.0a") ; return await doAct(ns,"operation", "Sting Operation", "STING (new)","y"); } // DEBUG City Info, Sting counts, chance and spre@ds: //ns.print("๐Ÿ”ด " + ij + ". Going city: " + citynam1 ); // DEBUG //ns.print("๐Ÿšฉ City ๐Ÿ”ฅ: " +ns.nFormat(citychos, "0.00") ); //DEBUG Chaos //ns.print(">> MaxChaosRetire: "+ns.nFormat(maxchaosretire, "0.00") );//D //ns.print("๐Ÿšฉ City pop ๐Ÿ‘ฅ: "+ns.nFormat(citypopu,"0.000a"));//DEBUG //ns.print("@@ City commmunity ๐Ÿ’ is " + cityinfo[ij].comm ); // DEBUG } // %%% LOOP CITIES END %%% //$$$$$$$$$$$$$$$ RAID / STING SECTION Extra Check - END $$$$$$$$$$$$$$$$$$

Code Part 3c: Work (Ops/Cons)

// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // $$$$$$$$$$$$$$$$$$$ OPERATIONS CHECK $$$$$$$$$$$$$$$$$$$$$ // $$$$$$$ Check if city ch@os for best operation is too high START $$$$$$$ var opcitychos = ns.nFormat( cityinfo[bestOp.city].chaos,"0.0"); //ns.print("๐Ÿ”ฅOPS Chaos: ",bestOp.opcitnam," : ", opcitychos , " Max: ",maxchaos); // DEBUG if (opcitychos > maxchaos) { // Check Retirement chance in Best Operation city var rettem = (bestOp.city * 6) + 4; //Index of Ops best retirement mission var retirecount= Oper[rettem].counts; var retirechance= Oper[rettem].chance; //ns.print(rettem, ".DIPLOMACY Retire #:" + retirecount + " ๐Ÿ”ฎ:"+ns.nFormat( retirechance[0],"0.0%")+"/ "+retispread); // DEBUG if (retirechance[0] >= minsuccess && retirecount > 0) { var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [bestOp.opcitnam]); // go city statuscity = "๐Ÿšฉ"+ bestOp.opcitnam +" ๐Ÿ”ฅ:"+opcitychos; return await doAct(ns,"operation","Stealth Retirement Operation","Retire (Ops-work)","y"); } diplomacystatus = 1; // Otherwise do normal Diplomacy... var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [bestOp.opcitnam]); // go city statuscity = "๐Ÿšฉ"+ bestOp.opcitnam +" ๐Ÿ”ฅ:"+opcitychos; return await doAct(ns,"general", "Diplomacy", "Diplomacy ON (Op-work)"); } //$$$$$$$ Check if city chaos is too high for best operation END $$$$$$$$ // Since we prefer Operations as a higher priority, we check operations first // If b3st Op chance is better than contract's, or is above min. success rate if (bestOp.chance[0] >=bestCon.chance[0] || bestOp.chance[0] >minsuccess){ // Check operation spre@d & do field analysis if we over minimum spre@d if (opspread > minspread) { return await doAct(ns,"general", "Field Analysis", "Field An (Ops)","y");} //If chance is too low, then do training if (bestOp.chance[0] <= minsuccess) { return await doAct(ns,"general", "Training", "Training (Ops)"); } // Otherwise START the Operation! var skilnam = bestOp.name; var skiltyp = bestOp.type; var comm = "Op>"+ skilnam.substring(0,10); var skilcity = bestOp.opcitnam; cityCur = skilcity; statuscity = "๐Ÿšฉ"+ skilcity +": "+ ns.nFormat( opper0 ,"0.0") + "%"; var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [skilcity] ); return await doAct(ns,skiltyp, skilnam, comm, "y"); } // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // $$$$$$$$$$$$$$$$$$$$ CONTRACTS CHECK $$$$$$$$$$$$$$$$$$$$$ // $$$$$$ Check ch@os for best C0NTRACT city START $$$$$$ var concitychos = ns.nFormat( cityinfo[bestCon.city].chaos,"0.0"); //ns.print("๐Ÿ”ฅCON Chaos: ",bestCon.concitnam," : ", concitychos , " Max: ",maxchaos); // DEBUG // Check Retirement chance in Best C0ntract city if (concitychos > maxchaos) { var rettem2 = (bestCon.city * 6) + 4; ns.print(">DIPLOMACY Retire rettem2:" + rettem2); var retirecount= Oper[rettem2].counts; var retirechance= Oper[rettem2].chance; //ns.print(">DIPLOMACY Retire #:" + retirecount + " ๐Ÿ”ฎ:"+ns.nFormat( retirechance[0],"0.0%")+"/ "+retispread); // DEBUG if (retirechance[0] >= minsuccess && retirecount > 0) { var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [bestCon.concitnam]); // go city statuscity = "๐Ÿšฉ"+ bestOp.concitnam +" ๐Ÿ”ฅ:"+concitychos; return await doAct(ns,"operation","Stealth Retirement Operation","Retire (Con-work)","y"); } diplomacystatus = 1; // Otherwise do normal Diplomacy... var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [bestCon.concitnam]); // go city statuscity = "๐Ÿšฉ"+ bestOp.concitnam +" ๐Ÿ”ฅ:"+concitychos; return await doAct(ns,"general", "Diplomacy", "Diplomacy ON (Con-work)"); } // $$$$$$ Check ch@os for best C0NTRACT city END $$$$$$ // If Contract Spre@d is high then do Field Analysis if (conspread > minspread) { return await doAct(ns,"general","Field Analysis","Field An (Contract)"); } //If success chance is too low, then do training if (bestCon.chance[0] <= minsuccess) { return await doAct(ns,"general", "Training", "Training (Contract)"); } else { // Else if chance is ok then continue... // Do the contract (once all rules above fail) var skilnam = bestCon.name; var skiltyp = bestCon.type; var comm = "Con>" + skilnam.substring(0,11); var skilcity = bestCon.concitnam; cityCur = skilcity; // Update console statuscity = "๐Ÿšฉ"+ skilcity +": "+ ns.nFormat( conper0 ,"0.0") + "%"; var switchCityOk = await runCom1(ns, 'ns.bladeburner.switchCity(ns.args[0])', 'switchCity', [skilcity] ); // Go to that city return await doAct(ns,skiltyp, skilnam, comm, "y"); } } //=============== WORK FUNCTION END ================

Code Part 4: Buying Skills

//============= BUY SKILLS FUNCTION START ============== export async function checkSkills(ns) { skstat = false; // Default skill log status var breakout = false; // Default 'do we stop checking' variable skillbuying: // Label to BREAK out of while (true) { if (breakout === true) break skillbuying; //If told to stop buying skills, break //@@@@@@@@@@@ AUTO SKILL BUY START @@@@@@@@@@@@@@@@ //Set default skill to auto-buy, "skautonam" is currently chosen skill to buy //Feel free to set your own rulesets. Here, we focus on the skills that are //most needed to complete the node (ie. ignore stuff like Cloak) var skautonam="Blade\'s Intuition"; // Set default skill to buy if (skautobuy == true) { //ns.print("ERROR *Skill buying AUTO start");// DEBUG // Get retirement chance var contractchance = await getChance("contract", "Retirement", ns); // Get levels of skills most important to beating the node var lvlbladein = await getSkillLearn("Blade\'s Intuition", ns); var lvlreaper = await getSkillLearn("Reaper", ns); var lvlevasive = await getSkillLearn("Evasive System", ns); var lvldigital = await getSkillLearn("Digital Observer", ns); var lvloverc = await getSkillLearn("Overclock", ns); //await ns.print("Retire Con%: " + (contractchance[0]*100) +"%" );// DEBUG //await ns.print("Blade Intuition skill level: " +lvlbladein );// DEBUG //await ns.print(" Overclock skill level: " +lvloverc );// DEBUG //If retirement contract chance is maxed, we prefer Observer or Overclock if (contractchance[0] >= 1.00){ //If overclock skill higher (by extra), or overclock maxed, buy observer if (lvlbladein*2<lvloverc || lvldigital*2<lvloverc || lvloverc==90 ){ var skautonam="Digital Observer"; } else { var skautonam="Overclock"; } //If chosen skill higher than Blade's Intuition, choose Blade if ( lvldigital > lvlbladein || lvloverc > lvlbladein ) { var skautonam="Blade\'s Intuition"; } } // Spread & even out levels of "evasive" and "reaper" skills // Put 300% more emphasis on "evasive" due to stamina and speed gains var lvltem = await runCom1(ns, 'ns.bladeburner.getSkillLevel(ns.args[0])', 'getSkLev', [skautonam]); if ( lvlreaper * 3.0 < lvltem || lvlevasive < lvltem ) { if ( lvlreaper * 3.0 < lvlevasive ) { var skautonam="Reaper"; } else { var skautonam="Evasive System"; } } //Buy the skill //await ns.print("WARN CHOSEN skautonam: " +skautonam );// DEBUG var sksk = await runCom1(ns, 'ns.bladeburner.upgradeSkill(ns.args[0])','getUpSk',[skautonam]); if (sksk==true) { skstat = true; if (skstatus==true) { //print skill bought status ns.print("๐ŸŒŸ๐Ÿ‘œ:" +skautonam.substring(0,15) +" "+Math.floor(Math.random()*(99-1)+1) ); // Random number used to show visible scrolling in long lists } } // BREAK While loop if we have no more points (prevents points buildup) var curskillpts = await runCom1(ns, 'ns.bladeburner.getSkillPoints()', 'getSkPts'); var requiredpts= await runCom1(ns, 'ns.bladeburner.getSkillUpgradeCost(ns.args[0])', 'getSkUp', [skautonam]); //await ns.print("curskill: "+curskillpts+" required: "+requiredpts);// DEBUG if ( skreq < requiredpts ) { skreq = requiredpts } if ( curskillpts < requiredpts ) { break skillbuying; } } // @@@@@@@@@@@ END AUTO SKILL BUY @@@@@@@@@@@@@@@@ // ########### MANUAL SKILL BUY SECTION START ################# if (skautobuy == false) { //Buys the skills in rank order & stores outcome in variables //(Skills will buy automatically in preference order because if we don't //have enough points for that skill the next line will execute and so on) // ns.print(" sknam.length: " + sknam.length ); // DEBUG for (let ij = 0; ij < sknam.length; ij++) { sk[ij] = await runCom1(ns, 'ns.bladeburner.upgradeSkill(ns.args[0])', 'upgSk', [] ]); if (sk[ij] == true) { skstat = true; if (skstatus == true) { //print skill bought status ns.print("๐ŸŒŸ๐Ÿ‘œ:" + sknam[ij].substring(0,15) + " " + (Math.random()+1).toString(36).substring(11) ); // Random letters used to show visible scrolling in long lists } } } // BREAK loop if we have no more skill points (prevents points overflowing) var curskillpts = await runCom1(ns, 'ns.bladeburner.getSkillPoints()', 'getSkPts'); //ns.print("Cur skill pts: " + curskillpts ); // DEBUG var skcost = []; for (let sj = 0; sj < sknam.length; sj++) { skcost[sj] = await runCom1(ns, 'ns.bladeburner.getSkillUpgradeCost(ns.args[0])', 'getSkUpCost', [] ]); if (skreq < skcost[sj]) { skreq = skcost[sj] } //ns.print(" skcost["+ sj + "]: " + skcost[sj] ); // DEBUG if ( curskillpts < skcost[sj] ) { break skillbuying; } } } // ########### MANUAL SKILL BUY SECTION END ################# } // END WHILE TRUE } //============= END SKILLS FUNCTION ==============

Code Part 5a: Main ASync Loop

//=============================================================================== //START MAIN ASYNC FUNCTION export async function main(ns) { //Disable Logs ns.disableLog("disableLog"); ns.disableLog("exec"); ns.disableLog("asleep"); ns.disableLog("bladeburner.startAction"); ns.disableLog("bladeburner.upgradeSkill"); ns.disableLog("travelToCity"); ns.disableLog("bladeburner.getSkillUpgradeCost"); ns.disableLog("sleep"); ns.disableLog("singularity.gymWorkout"); ns.disableLog("gymWorkout"); ns.disableLog("singularity.travelToCity"); ns.disableLog("commitCrime"); ns.disableLog("singularity.stopAction"); ns.disableLog("stopAction"); ns.print ("|<===== RESIZE LOG WINDOW =====>|"); //ns.clearLog(); ns.tail(); // Open console window to view status ns.print( "Please wait, script starting..."); ns.print( "\nIf you see (Script Killed), with"); ns.print( " no crash, wait a loop or two.\n"); // @@@@@@@ AUTO-CHECKING SINGULARITY START @@@@@@@@ // This makes singularity detection automatic. We are looking for "The // Blade's Simulacrum" augment - if we own the aug then turn singularity off var augcheck = false; var augsowned= await runCom1(ns,'ns.getOwnedAugmentations(ns.args[0])','getAugs', [false]); await sleep(200); // Loop through all owned augments, looking for Blade's Simulacrum for(var ij =0; ij <augsowned.length; ij++){ //ns.print( augsowned[ij] + ","); // DEBUG if (augsowned[ij]=="The Blade\'s Simulacrum") { var augcheck = true; } } if (augcheck==false) { (singularflag=true); ns.print( "โŒSimulacrum Aug. Singularity ON"); } else { singularflag=false; ns.print( "Found Simulacrum: Singularity OFF"); } // @@@@@@@ AUTO-CHECKING SINGULARITY END @@@@@@@@@@ //If we using Singularities, then STOP study, work, program, crime actions //Needed as before we get Simulacrum aug, they will override Blade actions if (singularflag==true) { await runCom1(ns, 'ns.stopAction()', 'stopAct'); } // JOIN the BladeBurner Faction automatically const joinblades = await runCom1(ns, 'ns.bladeburner.joinBladeburnerFaction()', 'joinBlade'); ns.print ("Joined BB Faction? = ", joinblades); // Auto skill buy status if (skautobuy == true) { ns.print( "INFO: AUTO Skill-buy is ON"); } else { ns.print( "INFO: AUTO Skill-buy is OFF"); } // $$$$$$ SET AUTOLEVEL in all mission types if set to do so $$$$$$$ if (autolevelflag == true) { ns.print( "WARN Setting Auto-Levelling ON"); for (let ij = 0; ij < contracts.length; ij++) { await runCom1(ns, 'ns.bladeburner.setActionAutolevel(ns.args[0],ns.args[1],ns.args[2])', 'setActAuto', ["contract", contracts[ij], true] ); } for (let ij = 0; ij < operations.length; ij++) { await runCom1(ns, 'ns.bladeburner.setActionAutolevel(ns.args[0],ns.args[1],ns.args[2])', 'setActAuto', ["operation", operations[ij], true] ); } } //Run work function first to populate information arrays await work(ns); // ################################## // ######## START MAIN LOOP ######### while (true) { // Get Blade Ranking and current city name & p0pulation blrank =await runCom1(ns, 'ns.bladeburner.getRank()', 'getRank'); cityCur = await runCom1(ns, 'ns.bladeburner.getCity()', 'getCity'); //Store previous Chaos values (need 2 values to see visible differences) citychos2 = citychos3; citychos=await runCom1(ns,'ns.bladeburner.getCityChaos(ns.args[0])','getChaos',[cityCur]); citychos3 = citychos; //store Chaos value for next loop //Get status: ๐Ÿ“–Blade Skill points owned... skpts = await runCom1(ns, 'ns.bladeburner.getSkillPoints()', 'getSkPts'); // Check if we can work? const can1 = await canWork(ns); //ns.print("INFO Can we work? = " + can1); //DEBUG //If we can work then work, else we rest if (can1 == true) { const work1 = await work(ns); var snoozeTime = work1; } else { const rest1 = await rest(ns); var snoozeTime = rest1; } // @@@@@@@@ PRINT STATUS START @@@@@@@@@@@@@@@@@@ // Get chaos, population and communities of current city citychos = cityinfo[cityinfo.findIndex(x => x.name === cityCur)].chaos; citypopu = cityinfo[cityinfo.findIndex(x => x.name === cityCur)].pop; citycomm = cityinfo[cityinfo.findIndex(x => x.name === cityCur)].comm; // Blank Line to divide loops, show stars if skills were bought if (skstat!=false) { ns.print("โ–‘โ–‘โ–‘๐ŸŒŸโ–‘โ–‘๐ŸŒŸโ–‘โ–‘๐ŸŒŸโ–‘โ–‘๐ŸŒŸโ–‘โ–‘๐ŸŒŸโ–‘โ–‘๐ŸŒŸโ–‘โ–‘๐ŸŒŸโ–‘โ–‘โ–‘โ–‘"); } else { ns.print("โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘"); } //##Show ๐Ÿ’˜ health, owned skill points / points to next skill await middText("โ–ˆ ๐Ÿ’˜"+ns.nFormat(stamina,"0.0")+"% โ–ˆ ๐Ÿ“–"+skpts+"/"+skreq+" โ–ˆ", null,ns); //Show ๐Ÿ—กRank: current Blade rank & ๐Ÿฉธ:HEAL STATUS await middText("๐Ÿ " +cityCur.substring(0,9) +" โ–ˆ ๐Ÿ—ก"+ns.nFormat(blrank,"0,0.")+ " โ–ˆ"+" ๐Ÿฉธ" +healstatnam +"", null, ns); //##Show @:CITY NAME (shortened), ๐Ÿ”ฅ:Chaos + history + city pop await middText("๐Ÿ”ฅ" + ns.nFormat(citychos, "0.0") + "<" + ns.nFormat(citychos2, "0.0")+" ๐Ÿ‘ฅ"+ns.nFormat(citypopu,"0.0a")+ " ๐Ÿ’" + citycomm, null, ns ); // OLD Status Line // Success chance %% set, b: Blk Ops, o: Ops, c: Contracts, counts for c & o //await middText("%%:"+minsuccess+" %b:"+minsucblac+" #c:"+concount+" #o:"+opcount,null,ns); //OLD Status Line var len = 2 + minsuccess.toString().length + 4 + minsucblac.toString().length + 4 + concount.toString().length + 4 + opcount.toString().length; var suctext = TxtTr.apply('%%',[TxtTr.Col.White,TxtTr.Tran.Bold]) +":"+ TxtTr.apply(minsuccess,[TxtTr.Col.DGreen,TxtTr.Tran.Under]) +" "+ TxtTr.apply('%b',[TxtTr.Col.White,TxtTr.Tran.Bold]) +":"+ TxtTr.apply(minsucblac,[TxtTr.Col.DGreen,TxtTr.Tran.Under]) +" "+ TxtTr.apply('#c',[TxtTr.Col.White,TxtTr.Tran.Bold]) +":"+ TxtTr.apply(concount,[TxtTr.Col.Yellow]) + " " + TxtTr.apply('#o',[TxtTr.Col.White,TxtTr.Tran.Bold]) +":"+ TxtTr.apply(opcount,[TxtTr.Col.Blue]) ; //ns.print("Len: ", len); // DEBUG await middText(suctext, len, ns); // ##Show %๐Ÿ”ฎ success spre@d chance ranges for c=Contracts, o=Ops, b=Black Ops //await middText("c" + ns.nFormat(conper0, "0.0") + "-" + ns.nFormat(conper1, "0.0") + " o" + ns.nFormat(opper0, "0.0") + "-" + ns.nFormat(opper1, "0.0") + " b" + ns.nFormat(blacper0, "0.0"), "",ns); // OLD Status Line var len = 1 + Math.ceil(Math.log10(ns.nFormat( conper0, "0.0") + 1)) +2 +1 + Math.ceil(Math.log10(ns.nFormat( conper1, "0.0") + 1)) +2 +1 + 1 + Math.ceil(Math.log10(ns.nFormat( opper0, "0.0") + 1)) +2 +1 + Math.ceil(Math.log10(ns.nFormat( opper1, "0.0") + 1)) +2 +1 + 1 + Math.ceil(Math.log10(ns.nFormat(blacper0, "0.0") + 1)) + 2; var suctext = TxtTr.apply('c',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(ns.nFormat(conper0, "0.0"),[TxtTr.Col.Yellow]) +"-" + TxtTr.apply(ns.nFormat(conper1, "0.0"),[TxtTr.Col.Yellow]) +" " + TxtTr.apply('o',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(ns.nFormat(opper0, "0.0"),[TxtTr.Col.Blue]) +"-" + TxtTr.apply(ns.nFormat(opper1, "0.0"),[TxtTr.Col.Blue]) +" " + TxtTr.apply('b',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(ns.nFormat(blacper0, "0.0"),[TxtTr.Col.Purple]); await middText(suctext, len, ns);

Code Part 5b: Main Loop + Functions

// ##Show SPREADS โ›—โ›—:Set spre@d & spre@ds for c,o,b (for field analysis) //await middText("โ›—โ›—"+ minspread + " c" + ns.nFormat(conspread*100, "0.0") + "% o" + ns.nFormat(opspread*100, "0.0") + "% b" + ns.nFormat(blspread*100, "0.0") + "%", null,ns); // OLD Status Line var len = 2 + minspread.toString().length + 1 + 1 + (ns.nFormat(conspread*100, "0.0")).toString().length +1+1+1+ (ns.nFormat(opspread*100, "0.0")).toString().length +1+1+1+ (ns.nFormat(blspread*100, "0.0")).toString().length +1; var suctext = TxtTr.apply('โ›—โ›—',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(minspread,[TxtTr.Col.DGreen,TxtTr.Tran.Under]) +" "+ TxtTr.apply('c',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(ns.nFormat(conspread*100, "0.0"),[TxtTr.Col.Yellow]) +"% "+ TxtTr.apply('o',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(ns.nFormat(opspread*100, "0.0"),[TxtTr.Col.Blue]) +"% "+ TxtTr.apply('b',[TxtTr.Col.White,TxtTr.Tran.Bold]) + TxtTr.apply(ns.nFormat(blspread*100, "0.0"),[TxtTr.Col.Purple]) +"% "; await middText(suctext, len-1, ns); // ##Inform if we have skipped original city if (statuscity !="") {var text=statuscity} else {var text= "[no extra info]"} var len = 1 + text.toString().length; var suctext = TxtTr.apply(text,[TxtTr.Col.White]); //await middText(text, null,ns); // OLD Status Line await middText(suctext, len, ns); // ##Print ACTION line //await middText(statusline, null, ns); //OLD Status Line var len = 1 + statusline.toString().length; if (statusline.indexOf("Con>") != -1) { var suctext = TxtTr.apply(statusline,[TxtTr.Col.Yellow]); } else if (statusline.indexOf("Op>") !=-1) { var suctext = TxtTr.apply(statusline,[TxtTr.Col.Blue]); } else if (statusline.indexOf("B>") !=-1) { var suctext = TxtTr.apply(statusline,[TxtTr.Col.Purple,TxtTr.Tran.Bold]); } else { var suctext = TxtTr.apply(statusline,[TxtTr.Col.Orange,TxtTr.Tran.Under]); } await middText(suctext, len, ns); // @@@@@@@@ PRINT STATUS END @@@@@@@@@@@@@@@@@@ // Wait for assigned task or action to stop //await ns.asleep(snoozeTime); // sl33p doesn't work! Use asl33p await sleep(snoozeTime); // asl33p & sl33p doesn't work! // Stop Blade Actions (in case we go on to other non-Blade actions) //ns.print("Stopping blade action"); // DEBUG await runCom1(ns, 'ns.bladeburner.stopBladeburnerAction()','stopBBAct'); // If we using Singularities, stop study, work, program, crime actions if (singularflag==true) { await runCom1(ns, 'ns.stopAction()','stopAct'); } // Check if can upgrade skills //ns.print("Checking skills"); // DEBUG await checkSkills(ns); } // ######### END MAIN LOOP ######## } //END MAIN ASYNC FUNCTION //=============================================================================== //@@@@@@@@@@@ MISC FUNCTIONS START @@@@@@@@@@@@@ // Function: Sl33p (seems superior than sl33p or asl33p) export async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // FUNCTION: Get Mission chance (returns array) export async function getChance(type, name, ns) { return await runCom1(ns, 'ns.bladeburner.getActionEstimatedSuccessChance(ns.args[0], ns.args[1])', 'getChance', [type, name] ); } // FUNCTION: Get number of mission contracts remaining export async function getCounts(type, name, ns) { return await runCom1(ns, 'ns.bladeburner.getActionCountRemaining(ns.args[0], ns.args[1])', 'getCounts', [type, name] ); } // FUNCTION: Get skill level of skill learned export async function getSkillLearn(name, ns) { return await runCom1(ns, 'ns.bladeburner.getSkillLevel(ns.args[0])', 'getSkLearn', [name] ); } // FUNCTION: Display text centered in HUD display export async function middText(text, lengthtext, ns) { var w = 35; // width of window to center text in if (lengthtext != null) { l = lengthtext; } else { var l = text.length; } var w2 = Math.abs( Math.floor( (w-l) / 2) ); //await ns.print("Text length = ", text.length); // DEBUG var s = new Array(w2 + 1).join(" "); if (l<= ( w ) ) {var text2 = s + text}; // use w-1 to fine-tune odd widths await ns.print(text2); } // FUNCTION: Execute action and return time needed with c0mment //If field "levopt" is NOT empty (e.g. "y"), means we want to show level info //Eg. return await d0Act(ns,"operation","Sting Operation","STING(xtra)","y"); export async function doAct(ns, type, mission, comment, levopt) { // Get time for action var actime = await runCom1(ns, 'ns.bladeburner.getActionTime(ns.args[0],ns.args[1])', 'getActTime', [type, mission]); // Initialise variables var levelact = ""; var leveltext = ""; // If level option is set, add mission/action level to c0mment if (levopt != undefined) { // Get level of mission or action levelact = await runCom1(ns, 'ns.bladeburner.getActionCurrentLevel(ns.args[0],ns.args[1])', 'getActLevel', [type, mission]); //await ns.print("WARN Level of action: " +levelact ); // DEBUG leveltext = "-Lv"+ levelact; } //C0mment status to log, and return the time required for action statusline = "๐Ÿšถ: " +comment + leveltext +" >" +(actime/1000) + "s"; await runCom1(ns,'ns.bladeburner.startAction(ns.args[0],ns.args[1])', 'startAct', [type, mission]); return actime ; }

Code Part 6: Functions (Scripter/Colorer)

//============================================================================== // External SCRIPT RUNNER START (adapted/shortened from ALAIN BRYDEN) // Use:let members = await runCom1(ns, 'ns.gang.getMemberNames()','getMemNam'); // let curCash = await runCom1(ns, 'ns.getServerMoneyAvailable(ns.args[0])', 'getSerMon', ["home"]); // var gangbuy = await runCom1(ns, 'ns.gang.purchaseEquipment(ns.args[0], ns.args[1])','getEqCost', [member, equipment]); export async function runCom1(ns, command, fileName, args = []) { var precursor = "blade7-"; //Front filename part of temp script (e.g. gang-) var fileName = "/Temp/" + precursor + fileName + ".txt"; var fileName2 = fileName + ".js"; //ns.print ("fileName: ", fileName, "| fileName2: ", fileName2) //DEBUG // Create SCRIPT to be written to external file let script = `export async function main(ns) {` + `let r;try{r=JSON.stringify(\n` + ` ${command}\n` + `);}catch(e){r="ERROR: "+(typeof e=='string'?e:e.message||JSON.stringify(e));}\n` + `const f="${fileName}"; if(ns.read(f)!==r) await ns.write(f,r,'w') } `; // If file already exists don't write it again (speeds program up) var oldContents = await ns.read(fileName2); while (oldContents != script) { await ns.write(fileName2, script, "w"); //Wait for it to be readable var oldContents = await ns.read(fileName2); } // Fill in arguments with "0" if not specified for (var ij = 0; ij < 5; ij++) { if (args[ij] == null) args[ij] = "0"; //ns.print ("args[",ij,"] = ", args[ij]) // DEBUG } //Run the script! And convert output to related format await ns.exec(fileName2,"home",1,args[0],args[1],args[2],args[3]); await sleep(1); // superior to sl33p and asl33p // We 'try' to catch JSON errors (they vanish after 1-2 loops) const fileData = await ns.read(fileName); try { var fileData2 = JSON.parse(fileData); } catch(e) { //await ns.print("ERROR STOPPED: "+command +" "+args[0]); //DEBUG console.log('Unable to parse the string.') } return fileData2; // Return the data } // External SCRIPT RUNNER END=================================================== //============================================================================== // Transform Text START (adapted/shortened from reddit/u/GeneralZero) // Usage: ns.print(TextTransforms.apply('Hello World',[TextTransforms.Highlight.Red,TextTransforms.Color.White,TextTransforms.Transform.Underline])); export class TxtTr { static #escapeCode = '\x1b['; static #foreground = '38;5;'; static #background = '48;5;'; static #endCode = 'm'; static #reset = `${this.#escapeCode}0${this.#endCode}` // For more colors, see full color chart at: // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters static Col = { Test: { Type: "Color", Value: 46 }, // Use this to find/test new colors Black: { Type: "Color", Value: 16 }, LBrown: { Type: "Color", Value: 130 }, DRed: { Type: "Color", Value: 52 }, Red: { Type: "Color", Value: 124 }, LRed: { Type: "Color", Value: 196 }, Orange: { Type: "Color", Value: 202 }, Yellow: { Type: "Color", Value: 226 }, LYellow: { Type: "Color", Value: 229 }, DGreen: { Type: "Color", Value: 34 }, Green: { Type: "Color", Value: 46 }, LGreen: { Type: "Color", Value: 155 }, DBlue: { Type: "Color", Value: 21 }, Blue: { Type: "Color", Value: 33 }, LBlue: { Type: "Color", Value: 111 }, Cyan: { Type: "Color", Value: 30 }, LCyan: { Type: "Color", Value: 122 }, Magenta: { Type: "Color", Value: 53 }, DPurple: { Type: "Color", Value: 55 }, Purple: { Type: "Color", Value: 201 }, LPurple: { Type: "Color", Value: 206 }, White: { Type: "Color", Value: 188 }, LWhite: { Type: "Color", Value: 231 }, } static High = { Black: { Type: "Highlight", Value: 16 }, Red: { Type: "Highlight", Value: 52 }, Green: { Type: "Highlight", Value: 22 }, Yellow: { Type: "Highlight", Value: 58 }, Blue: { Type: "Highlight", Value: 17 }, Magenta: { Type: "Highlight", Value: 53 }, Cyan: { Type: "Highlight", Value: 30 }, White: { Type: "Highlight", Value: 231 }, } static Tran = { Bold: { Type: "Transform", Value: 1 }, Under: { Type: "Transform", Value: 4 }, } //Apply xTerm Text Modifications static apply(text, transforms) { let prefix = []; let code = []; let apply = ''; for (let transform of transforms) { if (transform.Type != undefined && Number.isFinite(transform.Value)) { if (transform.Type === 'Highlight') { code.push(`${this.#background}${transform.Value};`); } else if (transform.Type === 'Transform') { prefix.push(`${transform.Value};`); } else if (transform.Type === 'Color') { code.push(`${this.#foreground}${transform.Value};`); } } } if (prefix.length > 0) { apply += prefix.join(''); } if (code.length > 0) { apply += code.join(''); } if (apply.length>0) {apply = `${this.#escapeCode}${apply}${this.#endCode}`; } apply += `${text}${this.#reset}` return `${apply}`; } } // Transform Text END=========================================================== //End Of Line

Conclusion

I'll be updating this script as time goes. Already I've gotten some comments that some things may not be optimal - feel free to comment and cannibalize the code for your own scripts and functions!

Cheers and hope it helps you out (in any way)!

Source: https://steamcommunity.com/sharedfiles/filedetails/?id=2837856721					

More Bitburner guilds


โฎ™