1
0
Fork 0

tweak and bugfix gang management script

This commit is contained in:
Massaki Archambault 2023-09-17 12:07:59 -04:00
parent d851d84c05
commit 93c201ed1f
1 changed files with 158 additions and 64 deletions

View File

@ -4,12 +4,33 @@ export async function main(ns) {
ns.tail() ns.tail()
ns.disableLog('ALL') ns.disableLog('ALL')
// config
/* Maximum number of members in a gang */
const MAX_MEMBER_COUNT = 12
/* Percent of training to the next ascension a member must do after ascending */
const MIN_ASCENSION_PERCENT = 0.9
/* Minimum power level a member must reach before transitioning to gang war/money making */
const MIN_POWER_LEVEL = 15
/* Win chance required to start a gang war */
const GANG_WAR_START_TRESH = 0.6
/* Minimum win chance before pulling out of a gang war */
const GANG_WAR_STOP_TRESH = 0.55
/* Target win chance */
const GANG_WAR_TARGET = 0.9
// enum
const MAKE_MONEY = "Human Trafficking" const MAKE_MONEY = "Human Trafficking"
const VIGILANTE_JUSTICE = "Vigilante Justice" const VIGILANTE_JUSTICE = "Vigilante Justice"
const MUG_PEOPLE = "Mug People"
const TERRORISM = "Terrorism" const TERRORISM = "Terrorism"
const TRAIN_COMBAT = "Train Combat" const TRAIN_COMBAT = "Train Combat"
const TERRITORY_WARFARE = "Territory Warfare" const TERRITORY_WARFARE = "Territory Warfare"
const maxMemberCount = 12
const PHASE_CATCHUP = "catchup"
const PHASE_RECRUIT = "recruit"
const PHASE_WAR = "war"
const PHASE_MONEY = "money"
const memberNamePool = [ const memberNamePool = [
"CJ", "CJ",
"Big Smoke", "Big Smoke",
@ -25,26 +46,81 @@ export async function main(ns) {
"Madd Dogg", "Madd Dogg",
"Little Weasel", "Little Weasel",
] ]
const equipments = [
"Baseball Bat",
"Katana",
"Glock 18C",
"P90C", "Steyr AUG",
"AK-47",
"M15A10 Assault Rifle",
"AWM Sniper Rifle",
"Bulletproof Vest",
"Full Body Armor",
"Liquid Body Armor",
"Graphene Plating Armor",
"Ford Flex V20",
"ATX1070 Superbike",
"Mercedes-Benz S9001",
"White Ferrari",
"Bionic Arms",
"Bionic Legs",
"Bionic Spine",
"BrachiBlades",
"Nanofiber Weave",
"Synthetic Heart",
"Synfibril Muscle",
"Graphene Bone Lacings",
function estimateMemberPower(memberName) { // Hacking stuff, low priority so they go to the end of the list
"BitWire",
"Neuralstimulator",
"DataJack",
"NUKE Rootkit",
"Soulstealer Rootkit",
"Demon Rootkit",
"Hmap Node",
"Jack the Ripper",
]
function getMinAscMult(memberName) {
const memberInfo = ns.gang.getMemberInformation(memberName) const memberInfo = ns.gang.getMemberInformation(memberName)
return Math.floor(Math.min( return Math.min(
memberInfo.str_asc_mult, memberInfo.str_asc_mult,
memberInfo.def_asc_mult, memberInfo.def_asc_mult,
memberInfo.dex_asc_mult, memberInfo.dex_asc_mult,
memberInfo.agi_asc_mult, // memberInfo.agi_asc_mult,
) / 1.5) )
}
function getMinAscensionResult(memberName) {
const memberAscensionResult = ns.gang.getAscensionResult(memberName)
return memberAscensionResult === undefined ? undefined : Math.min(
memberAscensionResult.str,
memberAscensionResult.def,
memberAscensionResult.dex,
// memberAscensionResult.agi
)
}
function estimateMemberPower(memberName) {
return getMinAscMult(memberName) / 1.6
}
function getMinSkillLevel(memberName) {
const memberInfo = ns.gang.getMemberInformation(memberName)
return Math.min(
memberInfo.str,
memberInfo.def,
memberInfo.dex,
memberInfo.agi,
)
} }
// Credit: Mysteyes. https://discord.com/channels/415207508303544321/415207923506216971/940379724214075442 // Credit: Mysteyes. https://discord.com/channels/415207508303544321/415207923506216971/940379724214075442
function getAscendTreshold(memberName) { function getAscendTreshold(memberName) {
const memberInfo = ns.gang.getMemberInformation(memberName) const memberInfo = ns.gang.getMemberInformation(memberName)
const mult = Math.min( const mult = getMinAscMult(memberName)
memberInfo.str_asc_mult,
memberInfo.def_asc_mult,
memberInfo.dex_asc_mult,
memberInfo.agi_asc_mult,
)
if (mult < 1.632) return 1.6326; if (mult < 1.632) return 1.6326;
if (mult < 2.336) return 1.4315; if (mult < 2.336) return 1.4315;
if (mult < 2.999) return 1.284; if (mult < 2.999) return 1.284;
@ -61,29 +137,20 @@ export async function main(ns) {
return 1.0591; return 1.0591;
} }
function getMinAscensionResult(memberName) {
const memberAscensionResult = ns.gang.getAscensionResult(memberName)
return memberAscensionResult === undefined ? undefined : Math.min(
memberAscensionResult.str,
memberAscensionResult.def,
memberAscensionResult.dex,
memberAscensionResult.agi
)
}
function isAscensionReady(memberName) { function isAscensionReady(memberName) {
return getMinAscensionResult(memberName) >= getAscendTreshold(memberName) return getMinAscensionResult(memberName) >= getAscendTreshold(memberName)
} }
function isRecruitementReady(relativePower, memberCount) { function isRecruitementReady(relativePower, memberCount) {
const res = relativePower / 3 > memberCount - 3 // TODO const res = relativePower * 1.25 + 2 > memberCount // TODO
// ns.print(ascentionCount / 3) ns.print(relativePower * 1.25 + 2)
return res return res
} }
function getGangWarWinChances() { function getGangWarWinChance() {
const gangInfo = ns.gang.getGangInformation() const gangInfo = ns.gang.getGangInformation()
const otherGangNames = Object.keys(ns.gang.getOtherGangInformation()).filter(x => gangInfo.faction != x && x.territory > 0) const otherGangInfo = ns.gang.getOtherGangInformation()
const otherGangNames = Object.keys(otherGangInfo).filter(x => x != gangInfo.faction && otherGangInfo[x]["territory"] > 0)
const chancesToWin = otherGangNames.map(x => ns.gang.getChanceToWinClash(x)) const chancesToWin = otherGangNames.map(x => ns.gang.getChanceToWinClash(x))
return Math.min(...chancesToWin) return Math.min(...chancesToWin)
} }
@ -100,7 +167,7 @@ export async function main(ns) {
ns.gang.recruitMember(memberName) ns.gang.recruitMember(memberName)
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
} }
const gangMembers = ns.gang.getMemberNames() const gangMembers = ns.gang.getMemberNames()
// check for and ascend members who are ready // check for and ascend members who are ready
@ -111,76 +178,103 @@ export async function main(ns) {
} }
} }
for (const memberName of gangMembers) {
if (isAscensionReady(memberName)) {
// ns.print("ascending " + memberName)
ns.gang.ascendMember(memberName)
}
}
// TODO: equipement
// gang war // gang war
if (getGangWarWinChances() >= 0.6) { if (getGangWarWinChance() >= GANG_WAR_START_TRESH) {
// go to war // go to war
ns.gang.setTerritoryWarfare(true) ns.gang.setTerritoryWarfare(true)
} }
else if (getGangWarWinChances() <= 0.55) { else if (getGangWarWinChance() <= GANG_WAR_STOP_TRESH) {
// disengage // disengage
ns.gang.setTerritoryWarfare(false) ns.gang.setTerritoryWarfare(false)
} }
// score each member by their estimated power level // score each member by their estimated power level
let memberDatas = gangMembers.map(x => [x, estimateMemberPower(x)]) let memberDatas = gangMembers.map(x => [x, {
memberDatas.sort((a, b) => b[1] - a[1]) "relativePower": estimateMemberPower(x),
const targetRelativePower = memberDatas[0][1] - 1 "minSkillLevel": getMinSkillLevel(x),
"ascensionPercent": getMinAscensionResult(x) / getAscendTreshold(x),
"phase": undefined,
"training": false,
"vigilante": false,
}])
memberDatas.sort((a, b) => b[1]["relativePower"] - a[1]["relativePower"])
const targetRelativePower = memberDatas[0][1]["relativePower"] - 2
for (const memberData of memberDatas) { for (const memberData of memberDatas) {
const memberName = memberData[0] const memberName = memberData[0]
const relativePower = memberData[1] const relativePower = memberData[1]["relativePower"]
const minSkillLevel = memberData[1]["minSkillLevel"]
const ascensionPercent = memberData[1]["ascensionPercent"]
ns.print(memberName) // compute the phase of each members
// ns.print(getMinAscensionResult(memberName) / getAscendTreshold(memberName)) if (relativePower < targetRelativePower) {
// ns.print(isAscensionReady(memberName))
if (relativePower < targetRelativePower && relativePower < 40) {
ns.print("assignment: catchup")
// bring up newcomers to the same level than established members // bring up newcomers to the same level than established members
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) memberData[1]["phase"] = PHASE_CATCHUP
} }
else if (getMinAscensionResult(memberName) / getAscendTreshold(memberName) < 0.9) { // TODO: arbitrary constant to be ajusted else if (gangMembers.length < MAX_MEMBER_COUNT && isRecruitementReady(targetRelativePower, gangMembers.length)) {
ns.print("assignment: level up after ascention") // gain respect to recruit new member
memberData[1]["phase"] = PHASE_RECRUIT
}
else if (gangInfo.territory < 1 && getGangWarWinChance() < GANG_WAR_TARGET) {
// prepare for gang war
memberData[1]["phase"] = PHASE_WAR
}
else {
// if everything else is done, make money
memberData[1]["phase"] = PHASE_MONEY
}
if (memberData[1]["phase"] == PHASE_CATCHUP) {
ns.print("assignment: catchup")
ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
memberData[1]["training"] = true
}
else if (ascensionPercent < MIN_ASCENSION_PERCENT) { // TODO: arbitrary constant to be ajusted
ns.print("assignment: level up after ascension")
// train a member back up after ascention // train a member back up after ascention
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
memberData[1]["training"] = true
} }
else if (gangInfo.wantedPenalty < 0) { else if (gangInfo.wantedPenalty < 0) {
ns.print("assignment: reduce wanted level") ns.print("assignment: reduce wanted level")
// reduce wanted level // try to keep the wanted penalty at 0%
ns.print(gangInfo.wantedPenalty)
ns.gang.setMemberTask(memberName, VIGILANTE_JUSTICE) ns.gang.setMemberTask(memberName, VIGILANTE_JUSTICE)
memberData[1]["vigilante"] = true
} }
else if (gangMembers.length < maxMemberCount && isRecruitementReady(relativePower, gangMembers.length)) { else if (memberData[1]["phase"] == PHASE_RECRUIT) {
ns.print("assignment: gain respect") ns.print("assignment: gain respect to recruit new members")
// gain respect to recruit new member if (minSkillLevel < 500) {
ns.gang.setMemberTask(memberName, TERRORISM) ns.gang.setMemberTask(memberName, MUG_PEOPLE)
}
else {
ns.gang.setMemberTask(memberName, TERRORISM)
}
} }
else if (relativePower < 20) { // TODO else if (relativePower < MIN_POWER_LEVEL) {
ns.print("assignment: train to next ascension") ns.print("assignment: train")
// train up to next ascention // train up to next ascention
ns.gang.setMemberTask(memberName, TRAIN_COMBAT) ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
memberData[1]["training"] = true
} }
else if (gangInfo.territory < 1 && getGangWarWinChances() < 0.95) { else if (memberData[1]["phase"] == PHASE_WAR) {
ns.print("assignment: gang war") ns.print("assignment: gang war")
// prepare for gang war
ns.gang.setMemberTask(memberName, TERRITORY_WARFARE) ns.gang.setMemberTask(memberName, TERRITORY_WARFARE)
} }
else { else {
ns.print("assignment: make money") ns.print("assignment: make money")
// go for the money ns.gang.setMemberTask(memberName, MAKE_MONEY)
ns.gang.setMemberTask(memberName, MAKE_MONEY) // TODO
} }
}
// buy equipement
if (memberData[1]["phase"] == PHASE_WAR || memberData[1]["phase"] == PHASE_MONEY) {
for (const equipment of equipments) {
ns.gang.purchaseEquipment(memberName, equipment)
}
}
ns.print(getMinAscensionResult(memberName) / getAscendTreshold(memberName))
}
ns.print(memberDatas)
await ns.sleep(5000) await ns.sleep(5000)
} }
} }