time to get some sleep, graph is in stylishGraph.js and the crime monitor is in test3.js
This commit is contained in:
@@ -152,7 +152,7 @@ function setupTerminalInput() {
|
|||||||
// Process AI response using OpenAI API
|
// Process AI response using OpenAI API
|
||||||
async function processAIResponse(messages, apiUrl, apiKey) {
|
async function processAIResponse(messages, apiUrl, apiKey) {
|
||||||
const data = {
|
const data = {
|
||||||
model: 'gpt-3.5',
|
model: 'gpt-3.5-turbo',
|
||||||
messages: messages,
|
messages: messages,
|
||||||
logit_bias: {
|
logit_bias: {
|
||||||
'22515': -100 // Strongly discourage the token "Ah"
|
'22515': -100 // Strongly discourage the token "Ah"
|
||||||
|
|||||||
15
Mizzajl/home/ChangeBackground.js
Normal file
15
Mizzajl/home/ChangeBackground.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
const doc = eval("document");
|
||||||
|
|
||||||
|
// Check if the background div already exists
|
||||||
|
let backgroundDiv = doc.getElementById("terminal-background");
|
||||||
|
|
||||||
|
if (backgroundDiv) {
|
||||||
|
// Change the background image
|
||||||
|
backgroundDiv.style.backgroundImage = "url('https://example.com/new-image.jpg')"; // Replace with your new image URL
|
||||||
|
ns.tprint("Background image changed successfully.");
|
||||||
|
} else {
|
||||||
|
ns.tprint("No background found to change.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/** @param {NS} ns */
|
/** @param {NS} ns */
|
||||||
export async function main(ns) {
|
export async function main(ns) {
|
||||||
|
ns.tail();
|
||||||
let aCitites = ["Sector-12", "Aevum", "Volhaven", "Chongqing", "New Tokyo", "Ishima"];
|
let aCitites = ["Sector-12", "Aevum", "Volhaven", "Chongqing", "New Tokyo", "Ishima"];
|
||||||
let sCorpName = "RM Enterprises";
|
let sCorpName = "RM Enterprises";
|
||||||
let sDivisionName = "Agri-Ram";
|
let sDivisionName = "Agri-Ram";
|
||||||
@@ -30,14 +31,34 @@ export async function main(ns) {
|
|||||||
if (!ns.readPort(nListenPID)) { ns.tprint("Error! Couldn't start Corporation!"); return };
|
if (!ns.readPort(nListenPID)) { ns.tprint("Error! Couldn't start Corporation!"); return };
|
||||||
ns.tprint(oCorpStatus);
|
ns.tprint(oCorpStatus);
|
||||||
while (nStep < 199) {
|
while (nStep < 199) {
|
||||||
|
await ns.corporation.nextUpdate();
|
||||||
|
if (nStep > 40) {
|
||||||
|
for (let sCity of aCitites) {
|
||||||
|
nListenPID = ns.run("/corp/GetOfficeData.js", 1, sDivisionName, sCity);
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
|
oOfficeData = ns.readPort(nListenPID);
|
||||||
|
if (oOfficeData.avgEnergy < 99.5) {
|
||||||
|
nListenPID = ns.run("/corp/BuyTea.js", 1, sDivisionName, sCity);
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
|
}
|
||||||
|
if (oOfficeData.avgMorale < 99.5) {
|
||||||
|
nListenPID = ns.run("/corp/ThrowParty.js", 1, sDivisionName, sCity, 500000);
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
|
}
|
||||||
|
// InsertSmartSupplyHere
|
||||||
|
}
|
||||||
|
};
|
||||||
nStep = oCorpStatus.nStep;
|
nStep = oCorpStatus.nStep;
|
||||||
ns.tprint(nStep);
|
|
||||||
|
switch (nStep) {
|
||||||
|
case 0:
|
||||||
nListenPID = ns.run("/corp/GetCorpData.js");
|
nListenPID = ns.run("/corp/GetCorpData.js");
|
||||||
await ns.nextPortWrite(nListenPID);
|
await ns.nextPortWrite(nListenPID);
|
||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
oCorpData = ns.readPort(nListenPID);
|
oCorpData = ns.readPort(nListenPID);
|
||||||
switch (nStep) {
|
|
||||||
case 0:
|
|
||||||
if (!oCorpData.divisions.length > 0) {
|
if (!oCorpData.divisions.length > 0) {
|
||||||
nListenPID = ns.run("/corp/CorpStart.js", 1, sDivisionName, "Agriculture");
|
nListenPID = ns.run("/corp/CorpStart.js", 1, sDivisionName, "Agriculture");
|
||||||
await ns.nextPortWrite(nListenPID);
|
await ns.nextPortWrite(nListenPID);
|
||||||
@@ -57,17 +78,23 @@ export async function main(ns) {
|
|||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
oCorpStatus.nStep = 15;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
nListenPID = ns.run("/corp/BuyWarehouseAPI.js");
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
oCorpStatus.nStep = 20;
|
oCorpStatus.nStep = 20;
|
||||||
break;
|
break;
|
||||||
case 20:
|
case 20:
|
||||||
nListenPID = ns.run("/corp/HasUnlock.js", 1, "Smart Supply");
|
/*nListenPID = ns.run("/corp/HasUnlock.js", 1, "Smart Supply");
|
||||||
await ns.nextPortWrite(nListenPID);
|
await ns.nextPortWrite(nListenPID);
|
||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
bUnlockStatus = ns.readPort(nListenPID);
|
bUnlockStatus = ns.readPort(nListenPID);
|
||||||
if (!bUnlockStatus) {
|
if (!bUnlockStatus) {
|
||||||
await ns.nextPortWrite(ns.run("/corp/BuyUnlock.js", 1, "Smart Supply"));
|
await ns.nextPortWrite(ns.run("/corp/BuyUnlock.js", 1, "Smart Supply"));
|
||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
}
|
}*/
|
||||||
for (let sCity of aCitites) {
|
for (let sCity of aCitites) {
|
||||||
nListenPID = ns.run("/corp/GetWarehouseData.js", 1, sDivisionName, sCity);
|
nListenPID = ns.run("/corp/GetWarehouseData.js", 1, sDivisionName, sCity);
|
||||||
await ns.nextPortWrite(nListenPID);
|
await ns.nextPortWrite(nListenPID);
|
||||||
@@ -77,10 +104,7 @@ export async function main(ns) {
|
|||||||
await ns.nextPortWrite(ns.run("/corp/PurchaseWarehouses.js", 1, sDivisionName, sCity));
|
await ns.nextPortWrite(ns.run("/corp/PurchaseWarehouses.js", 1, sDivisionName, sCity));
|
||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
}
|
}
|
||||||
await ns.nextPortWrite(ns.run("/corp/SetSmartSupply.js", 1, sDivisionName, sCity));
|
|
||||||
await ns.sleep(1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
oCorpStatus.nStep = 30;
|
oCorpStatus.nStep = 30;
|
||||||
break;
|
break;
|
||||||
case 30:
|
case 30:
|
||||||
@@ -101,12 +125,48 @@ export async function main(ns) {
|
|||||||
await ns.nextPortWrite(nListenPID);
|
await ns.nextPortWrite(nListenPID);
|
||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
oOfficeData = ns.readPort(nListenPID);
|
oOfficeData = ns.readPort(nListenPID);
|
||||||
nListenPID = ns.run("/corp/HireWorkers.js", 1, sDivisionName, sCity, JSON.stringify(oOfficeData), JSON.stringify({ nWorkerNumbers: [1, 1, 1, 1, 0, 0] }));
|
nListenPID = ns.run("/corp/HireWorkers.js", 1, sDivisionName, sCity, JSON.stringify(oOfficeData));
|
||||||
await ns.nextPortWrite(nListenPID);
|
await ns.nextPortWrite(nListenPID);
|
||||||
await ns.sleep(1);
|
await ns.sleep(1);
|
||||||
}
|
}
|
||||||
oCorpStatus.nStep = 50;
|
oCorpStatus.nStep = 45;
|
||||||
break;
|
break;
|
||||||
|
case 45:
|
||||||
|
nListenPID = ns.run("/corp/GetDivisionsData.js", 1, sDivisionName);
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
|
oDivisionData = ns.readPort(nListenPID);
|
||||||
|
if (!oDivisionData.researchPoints > 55) { continue } else {
|
||||||
|
for (let sCity of aCitites) {
|
||||||
|
nListenPID = ns.run("/corp/GetOfficeData.js", 1, sDivisionName, sCity);
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
|
oOfficeData = ns.readPort(nListenPID);
|
||||||
|
nListenPID = ns.run("/corp/SetWorkerOnPosition.js", 1, sDivisionName, sCity, JSON.stringify(oOfficeData), JSON.stringify({ nWorkerNumbers: [1, 1, 1, 1, 0, 0] }));
|
||||||
|
await ns.nextPortWrite(nListenPID);
|
||||||
|
await ns.sleep(1);
|
||||||
|
}
|
||||||
|
oCorpStatus.nStep = 70;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 70:
|
||||||
|
break;
|
||||||
|
case 80:
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
break;
|
||||||
|
case 100:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ns.write("CorpStatus.txt", JSON.stringify(oCorpStatus), "w")
|
||||||
|
await ns.sleep(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
case 50:
|
case 50:
|
||||||
let aCurrentGoods = [
|
let aCurrentGoods = [
|
||||||
{ "sMaterialName": "Food", "yAmount": "MAX", "yPrice": "MP-5" },
|
{ "sMaterialName": "Food", "yAmount": "MAX", "yPrice": "MP-5" },
|
||||||
@@ -150,19 +210,5 @@ export async function main(ns) {
|
|||||||
}
|
}
|
||||||
oCorpStatus.nStep = 70;
|
oCorpStatus.nStep = 70;
|
||||||
break;
|
break;
|
||||||
case 70:
|
|
||||||
oCorpStatus.nStep = 200;
|
*/
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
break;
|
|
||||||
case 90:
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ns.write("CorpStatus.txt", JSON.stringify(oCorpStatus), "w")
|
|
||||||
await ns.sleep(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
Mizzajl/home/RemoveBackground.js
Normal file
15
Mizzajl/home/RemoveBackground.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
const doc = eval("document");
|
||||||
|
|
||||||
|
// Find the background div by its ID
|
||||||
|
let backgroundDiv = doc.getElementById("terminal-background");
|
||||||
|
|
||||||
|
if (backgroundDiv) {
|
||||||
|
// Remove the background element
|
||||||
|
backgroundDiv.remove();
|
||||||
|
ns.tprint("Background removed.");
|
||||||
|
} else {
|
||||||
|
ns.tprint("No background found to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Mizzajl/home/SetBackground.js
Normal file
36
Mizzajl/home/SetBackground.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
// Evaluate the document to access the DOM
|
||||||
|
const doc = eval("document");
|
||||||
|
|
||||||
|
// Check if the background has already been added to avoid duplicates
|
||||||
|
if (doc.getElementById("terminal-background")) {
|
||||||
|
ns.tprint("Background already set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new <div> element to hold the background image
|
||||||
|
let backgroundDiv = doc.createElement("div");
|
||||||
|
backgroundDiv.id = "terminal-background"; // Set an ID for later reference
|
||||||
|
|
||||||
|
// Add CSS styling for the background
|
||||||
|
backgroundDiv.style = `
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: -1; /* Send it to the back */
|
||||||
|
background-image: url('https://r4.wallpaperflare.com/wallpaper/510/751/778/akira-kaneda-motorcycle-anime-wallpaper-c90008ed51badd0b96b7680fa02106ad.jpg'); /* Replace with your image URL */
|
||||||
|
background-size: cover; /* Ensure the image covers the whole screen */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
opacity: 0.5; /* Adjust opacity for readability */
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Append the background <div> to the body of the document
|
||||||
|
doc.body.appendChild(backgroundDiv);
|
||||||
|
|
||||||
|
// Inform the user that the background has been set
|
||||||
|
ns.tprint("Custom background image set successfully!");
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ export async function main(ns) {
|
|||||||
if (!ns.isRunning(sGangScript)) { drun(ns, sGangScript); }
|
if (!ns.isRunning(sGangScript)) { drun(ns, sGangScript); }
|
||||||
//if (!ns.isRunning(sCorpControl)) { ns.run(sCorpControl); }
|
//if (!ns.isRunning(sCorpControl)) { ns.run(sCorpControl); }
|
||||||
if (!ns.isRunning(sPServScript)) { drun(ns, sPServScript); }
|
if (!ns.isRunning(sPServScript)) { drun(ns, sPServScript); }
|
||||||
await DistributeRunAndWait(ns, sBackdoorScript);
|
await RunAndWait(ns, sBackdoorScript);
|
||||||
await DistributeRunAndWait(ns, sUpdateTarget);
|
await DistributeRunAndWait(ns, sUpdateTarget);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
13
Mizzajl/home/closeAllWindows.js
Normal file
13
Mizzajl/home/closeAllWindows.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
const doc = eval("document");
|
||||||
|
|
||||||
|
// Get and remove all elements with the specific container IDs
|
||||||
|
const containers = doc.querySelectorAll('[id*="money-graph-container"]');
|
||||||
|
|
||||||
|
containers.forEach(container => {
|
||||||
|
container.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
ns.tprint("Removed all windows.");
|
||||||
|
}
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
/** @param {NS} ns */
|
/** @param {NS} ns */
|
||||||
export async function main(ns) {
|
export async function main(ns) {
|
||||||
let [sDivName, sCity] = ns.args;
|
let [sDivName, sCity] = ns.args;
|
||||||
//ns.tprint("sDivName = " + sDivName);
|
let bSuccess = ns.corporation.buyTea(sDivName, sCity);
|
||||||
//ns.tprint("sCity = " + sCity);
|
|
||||||
let bSuccess = ns.corporation.buyTea(sDivName, sCity)
|
|
||||||
//ns.tprint("bSuccess = " + bSuccess);
|
|
||||||
ns.writePort(ns.pid, bSuccess);
|
ns.writePort(ns.pid, bSuccess);
|
||||||
}
|
}
|
||||||
7
Mizzajl/home/corp/BuyWarehouseAPI.js
Normal file
7
Mizzajl/home/corp/BuyWarehouseAPI.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
if (!ns.corporation.hasUnlock("Warehouse API")) {
|
||||||
|
ns.corporation.purchaseUnlock("Warehouse API");
|
||||||
|
ns.writePort(ns.pid, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/** @param {NS} ns */
|
/** @param {NS} ns */
|
||||||
export async function main(ns) {
|
export async function main(ns) {
|
||||||
let [sDivName, sCity] = ns.args;
|
let [sDivName, sCity] = ns.args;
|
||||||
|
//ns.tprint(ns.corporation.getOffice(sDivName, sCity))
|
||||||
ns.writePort(ns.pid, ns.corporation.getOffice(sDivName, sCity))
|
ns.writePort(ns.pid, ns.corporation.getOffice(sDivName, sCity))
|
||||||
}
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
/** @param {NS} ns */
|
|
||||||
export async function main(ns) {
|
|
||||||
ns.writePort(ns.pid, ns.corporation.hasUnlock("Smart Supply"));
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/** @param {NS} ns */
|
|
||||||
export async function main(ns) {
|
|
||||||
let [sDivName, sCity, oCurrentOffice, oWorkerDistribution] = ns.args;
|
|
||||||
oCurrentOffice = JSON.parse(oCurrentOffice);
|
|
||||||
let aWorkerDistribution = JSON.parse(oWorkerDistribution).nWorkerNumbers;
|
|
||||||
let nTotalWorkers = 0;
|
|
||||||
const len = aWorkerDistribution.length;
|
|
||||||
for (let i = 0; i < len; i++) nTotalWorkers += aWorkerDistribution[i];
|
|
||||||
let i = 0;
|
|
||||||
while (oCurrentOffice.numEmployees < oCurrentOffice.size && oCurrentOffice.numEmployees < nTotalWorkers && i < 1) {
|
|
||||||
(oCurrentOffice.employeeJobs.Operations < aWorkerDistribution[0]) ? ns.corporation.hireEmployee(sDivName, sCity, "Operations") : "";
|
|
||||||
(oCurrentOffice.employeeJobs.Engineer < aWorkerDistribution[1]) ? ns.corporation.hireEmployee(sDivName, sCity, "Engineer") : "";
|
|
||||||
(oCurrentOffice.employeeJobs.Business < aWorkerDistribution[2]) ? ns.corporation.hireEmployee(sDivName, sCity, "Business") : "";
|
|
||||||
(oCurrentOffice.employeeJobs.Management < aWorkerDistribution[3]) ? ns.corporation.hireEmployee(sDivName, sCity, "Management") : "";
|
|
||||||
(oCurrentOffice.employeeJobs["Research & Development"] < aWorkerDistribution[4]) ? ns.corporation.hireEmployee(sDivName, sCity, "Research & Development") : "";
|
|
||||||
(oCurrentOffice.employeeJobs.Intern < aWorkerDistribution[5]) ? ns.corporation.hireEmployee(sDivName, sCity, "Intern") : "";
|
|
||||||
await ns.sleep(1)
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
ns.writePort(ns.pid, true);
|
|
||||||
}
|
|
||||||
26
Mizzajl/home/corp/SetWorkerOnPosition.js
Normal file
26
Mizzajl/home/corp/SetWorkerOnPosition.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
let [sDivName, sCity, oCurrentOffice, oWorkerDistribution] = ns.args;
|
||||||
|
oCurrentOffice = JSON.parse(oCurrentOffice);
|
||||||
|
let aWorkerDistribution = JSON.parse(oWorkerDistribution).nWorkerNumbers;
|
||||||
|
let nTotalWorkers = 0;
|
||||||
|
const len = aWorkerDistribution.length;
|
||||||
|
for (let i = 0; i < len; i++) nTotalWorkers += aWorkerDistribution[i];
|
||||||
|
if (nTotalWorkers <= oCurrentOffice.numEmployees) {
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Operations", 0);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Engineer", 0);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Business", 0);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Management", 0);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Research & Development", 0);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Intern", 0);
|
||||||
|
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Operations", aWorkerDistribution[0]);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Engineer", aWorkerDistribution[1]);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Business", aWorkerDistribution[2]);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Management", aWorkerDistribution[3]);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Research & Development", aWorkerDistribution[4]);
|
||||||
|
ns.corporation.setAutoJobAssignment(sDivName, sCity, "Intern", aWorkerDistribution[5]);
|
||||||
|
await ns.sleep(1)
|
||||||
|
};
|
||||||
|
ns.writePort(ns.pid, true);
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
/** @param {NS} ns */
|
/** @param {NS} ns */
|
||||||
export async function main(ns) {
|
export async function main(ns) {
|
||||||
let [sDivName, sCity, nSpend] = ns.args;
|
let [sDivName, sCity, nSpend] = ns.args;
|
||||||
//ns.tprint("sDivName = " + sDivName);
|
let nMoraleMultiplier = ns.corporation.throwParty(sDivName, sCity, nSpend);
|
||||||
//ns.tprint("sCity = " + sCity);
|
|
||||||
//ns.tprint("nSpend = " + nSpend);
|
|
||||||
let nMoraleMultiplier = ns.corporation.throwParty(sDivName, sCity, nSpend)
|
|
||||||
//ns.tprint("nMoraleMultiplier = " + nMoraleMultiplier);
|
|
||||||
ns.writePort(ns.pid, nMoraleMultiplier);
|
ns.writePort(ns.pid, nMoraleMultiplier);
|
||||||
}
|
}
|
||||||
271
Mizzajl/home/stylishGraph.js
Normal file
271
Mizzajl/home/stylishGraph.js
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
const doc = eval("document");
|
||||||
|
|
||||||
|
// File to store money data
|
||||||
|
const moneyRecordFile = "MoneyRecord.txt";
|
||||||
|
const recordInterval = 10000; // Record every 10 seconds
|
||||||
|
const graphDuration = 300000; // Last 5 minutes (in milliseconds)
|
||||||
|
let isClosed = false; // Track if the window is closed
|
||||||
|
|
||||||
|
// Function to format numbers as K (thousand), M (million), B (billion), etc.
|
||||||
|
function formatLargeNumber(number) {
|
||||||
|
if (number >= 1e12) {
|
||||||
|
return `$${(number / 1e12).toFixed(3)}t`;
|
||||||
|
} else if (number >= 1e9) {
|
||||||
|
return `$${(number / 1e9).toFixed(3)}b`;
|
||||||
|
} else if (number >= 1e6) {
|
||||||
|
return `$${(number / 1e6).toFixed(3)}m`;
|
||||||
|
} else if (number >= 1e3) {
|
||||||
|
return `$${(number / 1e3).toFixed(3)}k`;
|
||||||
|
} else {
|
||||||
|
return `$${number.toFixed(2)}`; // Less than 1000, show as a standard number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any existing container if it exists
|
||||||
|
const existingContainer = doc.getElementById("money-graph-container");
|
||||||
|
if (existingContainer) {
|
||||||
|
existingContainer.remove(); // Remove the existing container
|
||||||
|
ns.tprint("Previous graph closed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the container for the graph
|
||||||
|
const container = doc.createElement("div");
|
||||||
|
container.id = "money-graph-container";
|
||||||
|
container.style = `
|
||||||
|
position: absolute;
|
||||||
|
top: 200px;
|
||||||
|
left: 200px;
|
||||||
|
width: 600px;
|
||||||
|
height: 300px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.9); /* Black background with 90% opacity */
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
border: 2px solid #666;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: "Source Code Pro", monospace;
|
||||||
|
z-index: 1000;
|
||||||
|
cursor: move;
|
||||||
|
box-shadow: 0px 0px 15px rgba(0, 255, 0, 0.5); /* Glow effect */
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Create a header bar with a close button
|
||||||
|
const header = doc.createElement("div");
|
||||||
|
header.style = `
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
padding: 5px;
|
||||||
|
background: rgba(17, 17, 17, 0.9); /* Dark background with 90% opacity */
|
||||||
|
border-bottom: 1px solid #666;
|
||||||
|
text-shadow: 0px 0px 10px #0f0;
|
||||||
|
`;
|
||||||
|
header.innerText = "Server Money Graph";
|
||||||
|
|
||||||
|
// Close button
|
||||||
|
const closeButton = doc.createElement("button");
|
||||||
|
closeButton.innerText = "X";
|
||||||
|
closeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #666;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-left: 10px;
|
||||||
|
`;
|
||||||
|
closeButton.addEventListener("click", () => {
|
||||||
|
container.remove(); // Close the graph container
|
||||||
|
ns.tprint("Graph window closed.");
|
||||||
|
isClosed = true; // Mark the window as closed
|
||||||
|
});
|
||||||
|
|
||||||
|
header.appendChild(closeButton);
|
||||||
|
container.appendChild(header);
|
||||||
|
|
||||||
|
// Create the canvas for the graph
|
||||||
|
const canvas = doc.createElement("canvas");
|
||||||
|
canvas.id = "money-graph";
|
||||||
|
canvas.width = 580; // Slightly smaller than the container for padding
|
||||||
|
canvas.height = 200;
|
||||||
|
canvas.style = `
|
||||||
|
background-color: rgba(17, 17, 17, 0.9); /* Dark background with 90% opacity */
|
||||||
|
border: 1px solid #666;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 10px;
|
||||||
|
`;
|
||||||
|
container.appendChild(canvas);
|
||||||
|
|
||||||
|
// Create the money display (on the right side of the graph)
|
||||||
|
const moneyDisplay = doc.createElement("div");
|
||||||
|
moneyDisplay.style = `
|
||||||
|
color: #ffd700; /* Yellow color for money display */
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 100px;
|
||||||
|
`;
|
||||||
|
moneyDisplay.innerText = "Money: Loading...";
|
||||||
|
container.appendChild(moneyDisplay);
|
||||||
|
|
||||||
|
doc.body.appendChild(container);
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// Movable functionality for the entire container
|
||||||
|
let isMoving = false;
|
||||||
|
let offsetX = 0, offsetY = 0;
|
||||||
|
|
||||||
|
// Start moving the container on mousedown
|
||||||
|
function startMove(e) {
|
||||||
|
isMoving = true;
|
||||||
|
offsetX = e.clientX - container.getBoundingClientRect().left;
|
||||||
|
offsetY = e.clientY - container.getBoundingClientRect().top;
|
||||||
|
container.style.cursor = "grabbing"; // Change cursor to grabbing while moving
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop moving on mouseup
|
||||||
|
function stopMove() {
|
||||||
|
if (isMoving) {
|
||||||
|
isMoving = false;
|
||||||
|
container.style.cursor = "move"; // Change cursor back to move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the movement of the window
|
||||||
|
function moveWindow(e) {
|
||||||
|
if (isMoving) {
|
||||||
|
container.style.left = `${e.clientX - offsetX}px`;
|
||||||
|
container.style.top = `${e.clientY - offsetY}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach event listeners for movement
|
||||||
|
container.addEventListener("mousedown", startMove);
|
||||||
|
doc.addEventListener("mousemove", moveWindow);
|
||||||
|
doc.addEventListener("mouseup", stopMove);
|
||||||
|
doc.addEventListener("mouseleave", stopMove); // Stop moving if mouse leaves the window
|
||||||
|
|
||||||
|
// Function to record money data to file with timestamps
|
||||||
|
function recordMoneyData() {
|
||||||
|
const currentMoney = ns.getServerMoneyAvailable("home");
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const record = `${timestamp},${currentMoney}\n`;
|
||||||
|
ns.write(moneyRecordFile, record, "a"); // Append without await
|
||||||
|
moneyDisplay.innerText = `Money: ${formatLargeNumber(currentMoney)}`; // Update money display with formatted value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to draw grid lines
|
||||||
|
function drawGridLines(maxMoney, minMoney) {
|
||||||
|
const numSteps = 5; // Number of steps on the axes
|
||||||
|
const stepY = (maxMoney - minMoney) / numSteps; // Step size for Y-axis
|
||||||
|
const stepX = graphDuration / numSteps; // Step size for X-axis (time)
|
||||||
|
|
||||||
|
// Draw vertical grid lines (X-axis steps)
|
||||||
|
for (let i = 1; i <= numSteps; i++) {
|
||||||
|
const x = 40 + (i * (canvas.width - 60)) / numSteps;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x, 10);
|
||||||
|
ctx.lineTo(x, 180);
|
||||||
|
ctx.strokeStyle = 'rgba(0, 255, 0, 0.2)'; // Faint green grid line
|
||||||
|
ctx.stroke();
|
||||||
|
// Draw X-axis labels
|
||||||
|
const timeLabel = `${Math.round((i * stepX) / 1000)}s`;
|
||||||
|
ctx.fillStyle = '#0c0';
|
||||||
|
ctx.font = '12px "Source Code Pro"';
|
||||||
|
ctx.fillText(timeLabel, x - 10, 190);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw horizontal grid lines (Y-axis steps)
|
||||||
|
for (let i = 1; i <= numSteps; i++) {
|
||||||
|
const y = 180 - (i * 170) / numSteps;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(40, y);
|
||||||
|
ctx.lineTo(550, y);
|
||||||
|
ctx.strokeStyle = 'rgba(0, 255, 0, 0.2)'; // Faint green grid line
|
||||||
|
ctx.stroke();
|
||||||
|
// Draw Y-axis labels with formatted money
|
||||||
|
const moneyLabel = formatLargeNumber(minMoney + i * stepY);
|
||||||
|
ctx.fillStyle = '#0c0';
|
||||||
|
ctx.font = '12px "Source Code Pro"';
|
||||||
|
ctx.fillText(moneyLabel, 5, y + 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to draw the graph with dynamic scaling from file
|
||||||
|
async function drawGraph() {
|
||||||
|
const fileData = await ns.read(moneyRecordFile);
|
||||||
|
if (!fileData) return;
|
||||||
|
|
||||||
|
const records = fileData.trim().split("\n").map(line => {
|
||||||
|
const [timestamp, money] = line.split(",");
|
||||||
|
return { timestamp: parseInt(timestamp), money: parseFloat(money) };
|
||||||
|
});
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const recentRecords = records.filter(record => now - record.timestamp <= graphDuration);
|
||||||
|
|
||||||
|
// Clear the canvas
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
if (recentRecords.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxMoney = Math.max(...recentRecords.map(record => record.money));
|
||||||
|
const minMoney = Math.min(...recentRecords.map(record => record.money));
|
||||||
|
|
||||||
|
if (maxMoney === minMoney) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw gridlines
|
||||||
|
drawGridLines(maxMoney, minMoney);
|
||||||
|
|
||||||
|
// Draw axes
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(40, 10); // Left margin
|
||||||
|
ctx.lineTo(40, 180); // Bottom margin
|
||||||
|
ctx.lineTo(550, 180); // Right margin
|
||||||
|
ctx.strokeStyle = '#0c0'; // Green for axes
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Plot the data points with yellow line
|
||||||
|
ctx.strokeStyle = '#ffd700'; // Yellow for the money line
|
||||||
|
ctx.beginPath();
|
||||||
|
const firstPoint = recentRecords[0];
|
||||||
|
const startTime = firstPoint.timestamp;
|
||||||
|
const initialY = 180 - ((firstPoint.money - minMoney) / (maxMoney - minMoney)) * 170; // Scale to fit graph height
|
||||||
|
ctx.moveTo(40, initialY);
|
||||||
|
|
||||||
|
recentRecords.forEach((record) => {
|
||||||
|
const timeDiff = record.timestamp - startTime;
|
||||||
|
const x = 40 + (timeDiff / graphDuration) * (canvas.width - 60); // Scaled x-axis
|
||||||
|
const y = 180 - ((record.money - minMoney) / (maxMoney - minMoney)) * 170; // Scaled y-axis
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main loop to record money data and update graph
|
||||||
|
try {
|
||||||
|
while (!isClosed) {
|
||||||
|
recordMoneyData(); // Record data without await
|
||||||
|
await drawGraph(); // Ensure graph is updated properly
|
||||||
|
await ns.sleep(recordInterval); // Wait for 10 seconds
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ns.tprint(`Error: ${e.message}`);
|
||||||
|
} finally {
|
||||||
|
if (doc.body.contains(container)) {
|
||||||
|
container.remove(); // Clean up the container when the script ends
|
||||||
|
}
|
||||||
|
ns.tprint("Script stopped.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,238 +0,0 @@
|
|||||||
/** @param {NS} ns */
|
|
||||||
export async function main(ns) {
|
|
||||||
ns.disableLog('sleep'); // Disable log spamming
|
|
||||||
|
|
||||||
let counter = 0;
|
|
||||||
let incrementValue = 1;
|
|
||||||
let isRunning = true;
|
|
||||||
let isMinimized = false; // Tracks whether the window is minimized or not
|
|
||||||
|
|
||||||
// Define colors from the provided theme
|
|
||||||
const theme = {
|
|
||||||
primary: "#0c0",
|
|
||||||
primarylight: "#0f0",
|
|
||||||
primarydark: "#090",
|
|
||||||
error: "#c00",
|
|
||||||
backgroundprimary: "#000", // Black background
|
|
||||||
button: "#333", // Button background
|
|
||||||
buttonHoverLight: "#555", // Lighter button hover effect
|
|
||||||
buttonHoverDark: "#111", // Darker button hover effect
|
|
||||||
rippleColor: "rgba(255, 255, 255, 0.5)", // Color of the ripple effect
|
|
||||||
border: "#666" // Border color
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a div for the display (the main window)
|
|
||||||
const doc = eval("document");
|
|
||||||
let container = doc.createElement("div");
|
|
||||||
container.style = `
|
|
||||||
position: fixed;
|
|
||||||
top: 100px;
|
|
||||||
left: 100px;
|
|
||||||
background: ${theme.backgroundprimary}; /* Solid black background */
|
|
||||||
color: ${theme.primary}; /* Primary color for text */
|
|
||||||
padding: 5px;
|
|
||||||
z-index: 1000;
|
|
||||||
font-family: monospace;
|
|
||||||
border: 2px solid ${theme.border}; /* Border around the whole window */
|
|
||||||
width: 220px;
|
|
||||||
border-radius: 5px;
|
|
||||||
`;
|
|
||||||
doc.body.appendChild(container);
|
|
||||||
|
|
||||||
// Create title bar with ^ and X buttons (minimize and close)
|
|
||||||
let titleBar = doc.createElement("div");
|
|
||||||
titleBar.style = `
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-weight: bold;
|
|
||||||
color: ${theme.primarylight}; /* Light primary color for header */
|
|
||||||
cursor: default;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
border-bottom: 1px solid ${theme.border}; /* Border between title and content */
|
|
||||||
`;
|
|
||||||
container.appendChild(titleBar);
|
|
||||||
|
|
||||||
let title = doc.createElement("span");
|
|
||||||
title.innerText = "Overview Counter";
|
|
||||||
titleBar.appendChild(title);
|
|
||||||
|
|
||||||
let controls = doc.createElement("div");
|
|
||||||
|
|
||||||
// Create minimize button (^ for minimize/restore)
|
|
||||||
let minimizeButton = doc.createElement("button");
|
|
||||||
minimizeButton.innerText = "^";
|
|
||||||
minimizeButton.style = `
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: ${theme.primarylight}; /* Light primary color for minimize button */
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0 5px;
|
|
||||||
`;
|
|
||||||
controls.appendChild(minimizeButton);
|
|
||||||
|
|
||||||
// Create close button (X to close)
|
|
||||||
let closeButton = doc.createElement("button");
|
|
||||||
closeButton.innerText = "X";
|
|
||||||
closeButton.style = `
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: ${theme.error}; /* Error color for close button */
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0 5px;
|
|
||||||
`;
|
|
||||||
controls.appendChild(closeButton);
|
|
||||||
|
|
||||||
titleBar.appendChild(controls);
|
|
||||||
|
|
||||||
// Create the content area (display for counter and buttons)
|
|
||||||
let content = doc.createElement("div");
|
|
||||||
content.style = "margin-top: 10px;";
|
|
||||||
container.appendChild(content);
|
|
||||||
|
|
||||||
let counterDisplay = doc.createElement("p");
|
|
||||||
counterDisplay.style = `
|
|
||||||
margin: 5px 0;
|
|
||||||
color: ${theme.primarylight}; /* Primary light color for counter text */
|
|
||||||
`;
|
|
||||||
content.appendChild(counterDisplay);
|
|
||||||
|
|
||||||
// Function to apply button styles with hover and ripple effects
|
|
||||||
function createStyledButton(text) {
|
|
||||||
let button = doc.createElement("button");
|
|
||||||
button.innerText = text;
|
|
||||||
button.style = `
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden; /* Allow ripple effect to be confined inside the button */
|
|
||||||
background: ${theme.button}; /* Button background color */
|
|
||||||
color: ${theme.primary}; /* Primary color for button text */
|
|
||||||
border: 1px solid ${theme.border};
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
padding: 5px;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 3px;
|
|
||||||
transition: background-color 0.3s ease; /* Smooth transition for hover effect */
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Apply hover effect (lighter if button is dark, darker if light)
|
|
||||||
button.addEventListener("mouseenter", () => {
|
|
||||||
button.style.backgroundColor = theme.button === "#333" ? theme.buttonHoverLight : theme.buttonHoverDark;
|
|
||||||
});
|
|
||||||
|
|
||||||
button.addEventListener("mouseleave", () => {
|
|
||||||
button.style.backgroundColor = theme.button;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add ripple effect on click
|
|
||||||
button.addEventListener("click", (e) => {
|
|
||||||
let ripple = doc.createElement("span");
|
|
||||||
let size = Math.max(button.offsetWidth, button.offsetHeight);
|
|
||||||
let x = e.clientX - button.getBoundingClientRect().left - size / 2;
|
|
||||||
let y = e.clientY - button.getBoundingClientRect().top - size / 2;
|
|
||||||
|
|
||||||
ripple.style = `
|
|
||||||
position: absolute;
|
|
||||||
width: ${size}px;
|
|
||||||
height: ${size}px;
|
|
||||||
background: ${theme.rippleColor};
|
|
||||||
border-radius: 50%;
|
|
||||||
opacity: 0;
|
|
||||||
animation: ripple-animation 0.6s ease-out;
|
|
||||||
left: ${x}px;
|
|
||||||
top: ${y}px;
|
|
||||||
`;
|
|
||||||
button.appendChild(ripple);
|
|
||||||
|
|
||||||
// Remove ripple element after animation
|
|
||||||
ripple.addEventListener("animationend", () => {
|
|
||||||
ripple.remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add keyframes for ripple animation
|
|
||||||
const styleSheet = doc.styleSheets[0];
|
|
||||||
styleSheet.insertRule(`
|
|
||||||
@keyframes ripple-animation {
|
|
||||||
from {
|
|
||||||
transform: scale(0);
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: scale(4);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, styleSheet.cssRules.length);
|
|
||||||
|
|
||||||
// Create buttons with hover effects, animations, and ripple effect
|
|
||||||
let incrementButton = createStyledButton("Increase Increment");
|
|
||||||
let decrementButton = createStyledButton("Decrease Increment");
|
|
||||||
let pauseButton = createStyledButton("Pause/Resume");
|
|
||||||
let quitButton = createStyledButton("Quit");
|
|
||||||
|
|
||||||
content.appendChild(incrementButton);
|
|
||||||
content.appendChild(decrementButton);
|
|
||||||
content.appendChild(pauseButton);
|
|
||||||
content.appendChild(quitButton);
|
|
||||||
|
|
||||||
// Add event listeners for the buttons
|
|
||||||
incrementButton.addEventListener("click", () => incrementValue += 1);
|
|
||||||
decrementButton.addEventListener("click", () => incrementValue = Math.max(0, incrementValue - 1));
|
|
||||||
pauseButton.addEventListener("click", () => incrementValue = incrementValue === 0 ? 1 : 0);
|
|
||||||
quitButton.addEventListener("click", () => {
|
|
||||||
isRunning = false;
|
|
||||||
container.remove(); // Remove the container on quit
|
|
||||||
});
|
|
||||||
|
|
||||||
// Minimize/Restore window
|
|
||||||
minimizeButton.addEventListener("click", () => {
|
|
||||||
isMinimized = !isMinimized;
|
|
||||||
content.style.display = isMinimized ? "none" : "block";
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close window
|
|
||||||
closeButton.addEventListener("click", () => {
|
|
||||||
isRunning = false;
|
|
||||||
container.remove(); // Remove the window
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make the window draggable
|
|
||||||
let isDragging = false;
|
|
||||||
let offsetX, offsetY;
|
|
||||||
|
|
||||||
container.addEventListener("mousedown", (e) => {
|
|
||||||
isDragging = true;
|
|
||||||
offsetX = e.clientX - container.getBoundingClientRect().left;
|
|
||||||
offsetY = e.clientY - container.getBoundingClientRect().top;
|
|
||||||
});
|
|
||||||
|
|
||||||
doc.addEventListener("mousemove", (e) => {
|
|
||||||
if (isDragging) {
|
|
||||||
container.style.left = `${e.clientX - offsetX}px`;
|
|
||||||
container.style.top = `${e.clientY - offsetY}px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
doc.addEventListener("mouseup", () => {
|
|
||||||
isDragging = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Main loop to update the counter display
|
|
||||||
while (isRunning) {
|
|
||||||
counter += incrementValue;
|
|
||||||
counterDisplay.innerText = `Counter: ${counter}\nIncrement Value: ${incrementValue}`;
|
|
||||||
|
|
||||||
await ns.sleep(1000); // Sleep 1 second between updates
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the container when the script stops
|
|
||||||
container.remove();
|
|
||||||
ns.tprint("Script terminated.");
|
|
||||||
}
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
/** @param {NS} ns */
|
|
||||||
export async function main(ns) {
|
|
||||||
ns.disableLog('sleep'); // Disable log spamming
|
|
||||||
|
|
||||||
const doc = eval("document");
|
|
||||||
const body = doc.body;
|
|
||||||
let isMinimized = false; // Track the minimize state
|
|
||||||
|
|
||||||
// Read crime stats from the CrimeStats.txt file
|
|
||||||
let crimeStatsData = await ns.read("CrimeStats.txt");
|
|
||||||
let crimes = JSON.parse(crimeStatsData); // Parse the JSON data from the file
|
|
||||||
|
|
||||||
// Add dynamic crime chance and calculate stats per second
|
|
||||||
for (let crime of crimes) {
|
|
||||||
crime.chance = ns.singularity.getCrimeChance(crime.name) * 100; // Get success chance as a number
|
|
||||||
let timeInSeconds = crime.time / 1000; // Convert ms to seconds for calculations
|
|
||||||
|
|
||||||
// Calculate stats per second
|
|
||||||
crime.hacking_exp_per_sec = crime.hacking_exp / timeInSeconds;
|
|
||||||
crime.strength_exp_per_sec = crime.strength_exp / timeInSeconds;
|
|
||||||
crime.defense_exp_per_sec = crime.defense_exp / timeInSeconds;
|
|
||||||
crime.dexterity_exp_per_sec = crime.dexterity_exp / timeInSeconds;
|
|
||||||
crime.agility_exp_per_sec = crime.agility_exp / timeInSeconds;
|
|
||||||
crime.charisma_exp_per_sec = crime.charisma_exp / timeInSeconds;
|
|
||||||
crime.intelligence_exp_per_sec = crime.intelligence_exp / timeInSeconds || 0; // Handle potential missing data
|
|
||||||
crime.money_per_sec = crime.money / timeInSeconds;
|
|
||||||
crime.karma_per_sec = crime.karma / timeInSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the CSS window container
|
|
||||||
let container = doc.createElement("div");
|
|
||||||
container.style = `
|
|
||||||
position: fixed;
|
|
||||||
top: 100px;
|
|
||||||
left: 100px;
|
|
||||||
background: black; /* Black background */
|
|
||||||
color: #0c0; /* Green text */
|
|
||||||
z-index: 1000;
|
|
||||||
font-family: "Source Code Pro", monospace; /* Apply the terminal font */
|
|
||||||
font-size: 16px;
|
|
||||||
border: 2px solid #666;
|
|
||||||
border-radius: 5px;
|
|
||||||
width: 1400px; /* Increased width */
|
|
||||||
height: 400px; /* Increased height */
|
|
||||||
overflow-y: auto;
|
|
||||||
`;
|
|
||||||
body.appendChild(container);
|
|
||||||
|
|
||||||
// Create the title bar with minimize and close buttons
|
|
||||||
let titleBar = doc.createElement("div");
|
|
||||||
titleBar.style = `
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
background: black; /* Black background for title bar */
|
|
||||||
color: #0c0; /* Green text */
|
|
||||||
border-bottom: 1px solid #666;
|
|
||||||
font-weight: bold;
|
|
||||||
`;
|
|
||||||
container.appendChild(titleBar);
|
|
||||||
|
|
||||||
// Title text
|
|
||||||
let title = doc.createElement("span");
|
|
||||||
title.innerText = "Crime Stats Monitor";
|
|
||||||
titleBar.appendChild(title);
|
|
||||||
|
|
||||||
// Create a container for the buttons and align them to the right
|
|
||||||
let buttonContainer = doc.createElement("div");
|
|
||||||
buttonContainer.style = `
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
`;
|
|
||||||
titleBar.appendChild(buttonContainer);
|
|
||||||
|
|
||||||
// Minimize button (▲ for minimize, ▼ for restore)
|
|
||||||
let minimizeButton = doc.createElement("button");
|
|
||||||
minimizeButton.innerText = "▲"; // Start as minimize button
|
|
||||||
minimizeButton.style = `
|
|
||||||
background: none;
|
|
||||||
border: 1px solid #666;
|
|
||||||
color: #0c0; /* Green text */
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 5px;
|
|
||||||
width: 30px; /* Set same width for buttons */
|
|
||||||
`;
|
|
||||||
buttonContainer.appendChild(minimizeButton);
|
|
||||||
|
|
||||||
minimizeButton.addEventListener("click", () => {
|
|
||||||
if (isMinimized) {
|
|
||||||
minimizeButton.innerText = "▲"; // Minimize arrow
|
|
||||||
container.style.height = "400px"; // Restore height
|
|
||||||
} else {
|
|
||||||
minimizeButton.innerText = "▼"; // Restore arrow
|
|
||||||
container.style.height = "25px"; // Minimize height
|
|
||||||
}
|
|
||||||
isMinimized = !isMinimized;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close button (X)
|
|
||||||
let closeButton = doc.createElement("button");
|
|
||||||
closeButton.innerText = "X";
|
|
||||||
closeButton.style = `
|
|
||||||
background: none;
|
|
||||||
border: 1px solid #666;
|
|
||||||
color: #0c0; /* Green text */
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 5px;
|
|
||||||
width: 30px; /* Set same width for buttons */
|
|
||||||
`;
|
|
||||||
buttonContainer.appendChild(closeButton);
|
|
||||||
|
|
||||||
closeButton.addEventListener("click", () => {
|
|
||||||
container.remove(); // Close the window
|
|
||||||
});
|
|
||||||
|
|
||||||
// Table for displaying the crime stats
|
|
||||||
let table = doc.createElement("table");
|
|
||||||
table.style = `
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
color: #0c0; /* Green text */
|
|
||||||
`;
|
|
||||||
container.appendChild(table);
|
|
||||||
|
|
||||||
// Track the current sort direction for each column (null, 'asc', or 'desc')
|
|
||||||
let sortOrder = new Array(13).fill(null); // One for each column
|
|
||||||
|
|
||||||
// Add table headers with clickable sorting functionality and arrows
|
|
||||||
let headers = [
|
|
||||||
"Crime", "Time (s)", "Chance", "Hack Exp/s", "Str Exp/s", "Def Exp/s",
|
|
||||||
"Dex Exp/s", "Agi Exp/s", "Cha Exp/s", "Money/s", "Karma/s", "$/%/s", "IntXP/s"
|
|
||||||
];
|
|
||||||
|
|
||||||
let headerRow = doc.createElement("tr");
|
|
||||||
|
|
||||||
headers.forEach((header, index) => {
|
|
||||||
let th = doc.createElement("th");
|
|
||||||
th.innerHTML = `${header} <span></span>`; // Span for the arrow
|
|
||||||
th.style = `
|
|
||||||
padding: 5px;
|
|
||||||
background: #333;
|
|
||||||
border: 1px solid #666;
|
|
||||||
cursor: pointer;
|
|
||||||
white-space: nowrap; /* Prevent wrapping */
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Add sorting functionality for each column
|
|
||||||
th.addEventListener("click", () => {
|
|
||||||
clearAllArrows(); // Remove all arrows
|
|
||||||
sortCrimesByColumn(index); // Sort by this column
|
|
||||||
toggleSortOrder(index); // Toggle sort order for this column
|
|
||||||
});
|
|
||||||
headerRow.appendChild(th);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.appendChild(headerRow);
|
|
||||||
|
|
||||||
// Function to toggle the sort order for a column
|
|
||||||
function toggleSortOrder(columnIndex) {
|
|
||||||
// Toggle between 'asc' and 'desc'
|
|
||||||
if (sortOrder[columnIndex] === 'asc') {
|
|
||||||
sortOrder[columnIndex] = 'desc';
|
|
||||||
} else {
|
|
||||||
sortOrder[columnIndex] = 'asc';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the arrows for this column
|
|
||||||
updateArrow(columnIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to update the arrow for a specific column
|
|
||||||
function updateArrow(columnIndex) {
|
|
||||||
let th = headerRow.querySelectorAll("th")[columnIndex];
|
|
||||||
let arrowSpan = th.querySelector("span");
|
|
||||||
|
|
||||||
if (sortOrder[columnIndex] === 'asc') {
|
|
||||||
arrowSpan.innerHTML = " ▲"; // Up arrow for ascending
|
|
||||||
} else if (sortOrder[columnIndex] === 'desc') {
|
|
||||||
arrowSpan.innerHTML = " ▼"; // Down arrow for descending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to clear all arrows
|
|
||||||
function clearAllArrows() {
|
|
||||||
headerRow.querySelectorAll("th span").forEach(arrow => {
|
|
||||||
arrow.innerHTML = ""; // Remove all arrows
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to format numbers with 4 decimal places
|
|
||||||
function formatNumber(num) {
|
|
||||||
return parseFloat(num.toFixed(4)); // Convert to number with 4 decimal places
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to display crimes in the table
|
|
||||||
function displayCrimes(crimesList) {
|
|
||||||
// Clear any existing rows (except the header)
|
|
||||||
while (table.rows.length > 1) {
|
|
||||||
table.deleteRow(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
crimesList.forEach(crime => {
|
|
||||||
let row = doc.createElement("tr");
|
|
||||||
|
|
||||||
let columns = [
|
|
||||||
{ text: crime.name, value: crime.name }, // Treat as string
|
|
||||||
{ text: formatNumber(crime.time / 1000), value: crime.time / 1000 }, // Time in seconds
|
|
||||||
{ text: formatNumber(crime.chance), value: crime.chance }, // Success chance
|
|
||||||
{ text: formatNumber(crime.hacking_exp_per_sec), value: crime.hacking_exp_per_sec },
|
|
||||||
{ text: formatNumber(crime.strength_exp_per_sec), value: crime.strength_exp_per_sec },
|
|
||||||
{ text: formatNumber(crime.defense_exp_per_sec), value: crime.defense_exp_per_sec },
|
|
||||||
{ text: formatNumber(crime.dexterity_exp_per_sec), value: crime.dexterity_exp_per_sec },
|
|
||||||
{ text: formatNumber(crime.agility_exp_per_sec), value: crime.agility_exp_per_sec },
|
|
||||||
{ text: formatNumber(crime.charisma_exp_per_sec), value: crime.charisma_exp_per_sec },
|
|
||||||
{ text: formatNumber(crime.money_per_sec), value: crime.money_per_sec },
|
|
||||||
{ text: formatNumber(crime.karma_per_sec), value: crime.karma_per_sec },
|
|
||||||
{ text: formatNumber(crime.money * crime.chance / 100), value: crime.money * crime.chance / 100 }, // Money per chance per second
|
|
||||||
{ text: formatNumber(crime.intelligence_exp_per_sec), value: crime.intelligence_exp_per_sec } // Intelligence XP per second
|
|
||||||
];
|
|
||||||
|
|
||||||
columns.forEach((col, index) => {
|
|
||||||
let td = doc.createElement("td");
|
|
||||||
td.innerText = col.text; // Display formatted text
|
|
||||||
td.dataset.value = col.value; // Store the numeric value for sorting
|
|
||||||
|
|
||||||
td.style = `
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid #666;
|
|
||||||
text-align: center;
|
|
||||||
white-space: nowrap; /* Prevent text wrapping */
|
|
||||||
`;
|
|
||||||
row.appendChild(td);
|
|
||||||
});
|
|
||||||
|
|
||||||
table.appendChild(row);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorting function (high to low for numeric values)
|
|
||||||
function sortCrimesByColumn(columnIndex) {
|
|
||||||
let rows = Array.from(table.querySelectorAll('tr:nth-child(n+2)')); // Get all rows except header
|
|
||||||
let order = sortOrder[columnIndex]; // Ascending or descending
|
|
||||||
|
|
||||||
rows.sort((rowA, rowB) => {
|
|
||||||
let valA = rowA.cells[columnIndex].dataset.value;
|
|
||||||
let valB = rowB.cells[columnIndex].dataset.value;
|
|
||||||
|
|
||||||
// Check if values are numeric and sort accordingly
|
|
||||||
if (!isNaN(valA) && !isNaN(valB)) {
|
|
||||||
return order === 'asc' ? parseFloat(valA) - parseFloat(valB) : parseFloat(valB) - parseFloat(valA);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not numeric, sort alphabetically
|
|
||||||
return order === 'asc' ? String(valA).localeCompare(String(valB)) : String(valB).localeCompare(String(valA));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Append rows in sorted order
|
|
||||||
rows.forEach(row => table.appendChild(row));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display the crimes initially
|
|
||||||
displayCrimes(crimes);
|
|
||||||
|
|
||||||
// Make the window draggable
|
|
||||||
let isDragging = false;
|
|
||||||
let offsetX, offsetY;
|
|
||||||
|
|
||||||
titleBar.addEventListener("mousedown", (e) => {
|
|
||||||
isDragging = true;
|
|
||||||
offsetX = e.clientX - container.getBoundingClientRect().left;
|
|
||||||
offsetY = e.clientY - container.getBoundingClientRect().top;
|
|
||||||
});
|
|
||||||
|
|
||||||
doc.addEventListener("mousemove", (e) => {
|
|
||||||
if (isDragging) {
|
|
||||||
container.style.left = `${e.clientX - offsetX}px`;
|
|
||||||
container.style.top = `${e.clientY - offsetY}px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
doc.addEventListener("mouseup", () => {
|
|
||||||
isDragging = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -45,6 +45,7 @@ export async function main(ns) {
|
|||||||
top: 100px;
|
top: 100px;
|
||||||
left: 100px;
|
left: 100px;
|
||||||
background: black; /* Black background */
|
background: black; /* Black background */
|
||||||
|
opacity: 0.9; /* 50% transparency */
|
||||||
color: #0c0; /* Green text */
|
color: #0c0; /* Green text */
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
font-family: "Source Code Pro", monospace; /* Apply the terminal font */
|
font-family: "Source Code Pro", monospace; /* Apply the terminal font */
|
||||||
|
|||||||
Reference in New Issue
Block a user