tweak and bugfix gang management script
This commit is contained in:
parent
d851d84c05
commit
93c201ed1f
216
src/gang.js
216
src/gang.js
|
@ -4,12 +4,33 @@ export async function main(ns) {
|
|||
ns.tail()
|
||||
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 VIGILANTE_JUSTICE = "Vigilante Justice"
|
||||
const MUG_PEOPLE = "Mug People"
|
||||
const TERRORISM = "Terrorism"
|
||||
const TRAIN_COMBAT = "Train Combat"
|
||||
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 = [
|
||||
"CJ",
|
||||
"Big Smoke",
|
||||
|
@ -25,26 +46,81 @@ export async function main(ns) {
|
|||
"Madd Dogg",
|
||||
"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)
|
||||
return Math.floor(Math.min(
|
||||
return Math.min(
|
||||
memberInfo.str_asc_mult,
|
||||
memberInfo.def_asc_mult,
|
||||
memberInfo.dex_asc_mult,
|
||||
memberInfo.agi_asc_mult,
|
||||
) / 1.5)
|
||||
// memberInfo.agi_asc_mult,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
function getAscendTreshold(memberName) {
|
||||
const memberInfo = ns.gang.getMemberInformation(memberName)
|
||||
const mult = Math.min(
|
||||
memberInfo.str_asc_mult,
|
||||
memberInfo.def_asc_mult,
|
||||
memberInfo.dex_asc_mult,
|
||||
memberInfo.agi_asc_mult,
|
||||
)
|
||||
const mult = getMinAscMult(memberName)
|
||||
if (mult < 1.632) return 1.6326;
|
||||
if (mult < 2.336) return 1.4315;
|
||||
if (mult < 2.999) return 1.284;
|
||||
|
@ -61,29 +137,20 @@ export async function main(ns) {
|
|||
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) {
|
||||
return getMinAscensionResult(memberName) >= getAscendTreshold(memberName)
|
||||
}
|
||||
|
||||
function isRecruitementReady(relativePower, memberCount) {
|
||||
const res = relativePower / 3 > memberCount - 3 // TODO
|
||||
// ns.print(ascentionCount / 3)
|
||||
const res = relativePower * 1.25 + 2 > memberCount // TODO
|
||||
ns.print(relativePower * 1.25 + 2)
|
||||
return res
|
||||
}
|
||||
|
||||
function getGangWarWinChances() {
|
||||
function getGangWarWinChance() {
|
||||
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))
|
||||
return Math.min(...chancesToWin)
|
||||
}
|
||||
|
@ -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
|
||||
if (getGangWarWinChances() >= 0.6) {
|
||||
if (getGangWarWinChance() >= GANG_WAR_START_TRESH) {
|
||||
// go to war
|
||||
ns.gang.setTerritoryWarfare(true)
|
||||
}
|
||||
else if (getGangWarWinChances() <= 0.55) {
|
||||
else if (getGangWarWinChance() <= GANG_WAR_STOP_TRESH) {
|
||||
// disengage
|
||||
ns.gang.setTerritoryWarfare(false)
|
||||
}
|
||||
|
||||
// score each member by their estimated power level
|
||||
let memberDatas = gangMembers.map(x => [x, estimateMemberPower(x)])
|
||||
memberDatas.sort((a, b) => b[1] - a[1])
|
||||
const targetRelativePower = memberDatas[0][1] - 1
|
||||
let memberDatas = gangMembers.map(x => [x, {
|
||||
"relativePower": estimateMemberPower(x),
|
||||
"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) {
|
||||
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)
|
||||
// ns.print(getMinAscensionResult(memberName) / getAscendTreshold(memberName))
|
||||
// ns.print(isAscensionReady(memberName))
|
||||
|
||||
if (relativePower < targetRelativePower && relativePower < 40) {
|
||||
ns.print("assignment: catchup")
|
||||
// compute the phase of each members
|
||||
if (relativePower < targetRelativePower) {
|
||||
// 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
|
||||
ns.print("assignment: level up after ascention")
|
||||
else if (gangMembers.length < MAX_MEMBER_COUNT && isRecruitementReady(targetRelativePower, gangMembers.length)) {
|
||||
// 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
|
||||
ns.gang.setMemberTask(memberName, TRAIN_COMBAT)
|
||||
memberData[1]["training"] = true
|
||||
}
|
||||
else if (gangInfo.wantedPenalty < 0) {
|
||||
ns.print("assignment: reduce wanted level")
|
||||
// reduce wanted level
|
||||
ns.print(gangInfo.wantedPenalty)
|
||||
// try to keep the wanted penalty at 0%
|
||||
ns.gang.setMemberTask(memberName, VIGILANTE_JUSTICE)
|
||||
memberData[1]["vigilante"] = true
|
||||
}
|
||||
else if (gangMembers.length < maxMemberCount && isRecruitementReady(relativePower, gangMembers.length)) {
|
||||
ns.print("assignment: gain respect")
|
||||
// gain respect to recruit new member
|
||||
else if (memberData[1]["phase"] == PHASE_RECRUIT) {
|
||||
ns.print("assignment: gain respect to recruit new members")
|
||||
if (minSkillLevel < 500) {
|
||||
ns.gang.setMemberTask(memberName, MUG_PEOPLE)
|
||||
}
|
||||
else {
|
||||
ns.gang.setMemberTask(memberName, TERRORISM)
|
||||
}
|
||||
else if (relativePower < 20) { // TODO
|
||||
ns.print("assignment: train to next ascension")
|
||||
}
|
||||
else if (relativePower < MIN_POWER_LEVEL) {
|
||||
ns.print("assignment: train")
|
||||
// train up to next ascention
|
||||
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")
|
||||
// prepare for gang war
|
||||
ns.gang.setMemberTask(memberName, TERRITORY_WARFARE)
|
||||
}
|
||||
else {
|
||||
ns.print("assignment: make money")
|
||||
// go for the money
|
||||
ns.gang.setMemberTask(memberName, MAKE_MONEY) // TODO
|
||||
}
|
||||
ns.gang.setMemberTask(memberName, MAKE_MONEY)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue