bitburner-scripts/src/ezgame/formulas/gang.ts
Vomitblood f12de39c91 namespaced formulas for easier importing
Co-authored-by: Copilot <copilot@github.com>
2026-05-02 01:00:05 +08:00

215 lines
6.6 KiB
TypeScript

import { currentNodeMults } from "./exports";
export const gang = {
ascensionMultiplier: calculateAscensionMult,
ascensionPointsGain: calculateAscensionPointsGain,
moneyGain: calculateMoneyGain,
respectGain: calculateRespectGain,
wantedLevelGain: calculateWantedLevelGain,
wantedPenalty: calculateWantedPenalty,
};
interface FormulaGang {
respect: number;
territory: number;
wantedLevel: number;
}
interface ITerritory {
money: number;
respect: number;
wanted: number;
}
interface ITaskParams {
baseRespect?: number;
baseWanted?: number;
baseMoney?: number;
hackWeight?: number;
strWeight?: number;
defWeight?: number;
dexWeight?: number;
agiWeight?: number;
chaWeight?: number;
difficulty?: number;
territory?: ITerritory;
}
class GangMember {
name: string;
task = "Unassigned";
earnedRespect = 0;
hack = 1;
str = 1;
def = 1;
dex = 1;
agi = 1;
cha = 1;
hack_exp = 0;
str_exp = 0;
def_exp = 0;
dex_exp = 0;
agi_exp = 0;
cha_exp = 0;
hack_mult = 1;
str_mult = 1;
def_mult = 1;
dex_mult = 1;
agi_mult = 1;
cha_mult = 1;
hack_asc_points = 0;
str_asc_points = 0;
def_asc_points = 0;
dex_asc_points = 0;
agi_asc_points = 0;
cha_asc_points = 0;
upgrades: string[] = []; // Names of upgrades
augmentations: string[] = []; // Names of augmentations only
constructor(name = "") {
this.name = name;
}
}
class GangMemberTask {
name: string;
desc: string;
isHacking: boolean;
isCombat: boolean;
baseRespect: number;
baseWanted: number;
baseMoney: number;
hackWeight: number;
strWeight: number;
defWeight: number;
dexWeight: number;
agiWeight: number;
chaWeight: number;
difficulty: number;
territory: ITerritory;
// Defines tasks that Gang Members can work on
constructor(name: string, desc: string, isHacking: boolean, isCombat: boolean, params: ITaskParams) {
this.name = name;
this.desc = desc;
// Flags that describe whether this Task is applicable for Hacking/Combat gangs
this.isHacking = isHacking;
this.isCombat = isCombat;
// Base gain rates for respect/wanted/money
this.baseRespect = params.baseRespect ? params.baseRespect : 0;
this.baseWanted = params.baseWanted ? params.baseWanted : 0;
this.baseMoney = params.baseMoney ? params.baseMoney : 0;
// Weighting for the effect that each stat has on the tasks effectiveness.
// Weights must add up to 100
this.hackWeight = params.hackWeight ? params.hackWeight : 0;
this.strWeight = params.strWeight ? params.strWeight : 0;
this.defWeight = params.defWeight ? params.defWeight : 0;
this.dexWeight = params.dexWeight ? params.dexWeight : 0;
this.agiWeight = params.agiWeight ? params.agiWeight : 0;
this.chaWeight = params.chaWeight ? params.chaWeight : 0;
if (
Math.round(
this.hackWeight + this.strWeight + this.defWeight + this.dexWeight + this.agiWeight + this.chaWeight,
) != 100
) {
console.error(`GangMemberTask ${this.name} weights do not add up to 100`);
}
// 1 - 100
this.difficulty = params.difficulty ? params.difficulty : 1;
// Territory Factors. Exponential factors that dictate how territory affects gains
// Formula: Territory Multiplier = (Territory * 100) ^ factor / 100
// So factor should be > 1 if something should scale exponentially with territory
// and should be < 1 if it should have diminishing returns
this.territory = params.territory ? params.territory : { money: 1, respect: 1, wanted: 1 };
}
}
function calculateWantedPenalty(gang: FormulaGang): number {
return gang.respect / (gang.respect + gang.wantedLevel);
}
function calculateRespectGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
if (task.baseRespect === 0) return 0;
let statWeight =
(task.hackWeight / 100) * member.hack +
(task.strWeight / 100) * member.str +
(task.defWeight / 100) * member.def +
(task.dexWeight / 100) * member.dex +
(task.agiWeight / 100) * member.agi +
(task.chaWeight / 100) * member.cha;
statWeight -= 4 * task.difficulty;
if (statWeight <= 0) return 0;
const territoryMult = Math.max(0.005, Math.pow(gang.territory * 100, task.territory.respect) / 100);
const territoryPenalty = (0.2 * gang.territory + 0.8) * currentNodeMults.GangSoftcap;
if (isNaN(territoryMult) || territoryMult <= 0) return 0;
const respectMult = calculateWantedPenalty(gang);
return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);
}
function calculateWantedLevelGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
if (task.baseWanted === 0) return 0;
let statWeight =
(task.hackWeight / 100) * member.hack +
(task.strWeight / 100) * member.str +
(task.defWeight / 100) * member.def +
(task.dexWeight / 100) * member.dex +
(task.agiWeight / 100) * member.agi +
(task.chaWeight / 100) * member.cha;
statWeight -= 3.5 * task.difficulty;
if (statWeight <= 0) return 0;
const territoryMult = Math.max(0.005, Math.pow(gang.territory * 100, task.territory.wanted) / 100);
if (isNaN(territoryMult) || territoryMult <= 0) return 0;
if (task.baseWanted < 0) {
return 0.4 * task.baseWanted * statWeight * territoryMult;
}
const calc = (7 * task.baseWanted) / Math.pow(3 * statWeight * territoryMult, 0.8);
// Put an arbitrary cap on this to prevent wanted level from rising too fast if the
// denominator is very small. Might want to rethink formula later
return Math.min(100, calc);
}
function calculateMoneyGain(gang: FormulaGang, member: GangMember, task: GangMemberTask): number {
if (task.baseMoney === 0) return 0;
let statWeight =
(task.hackWeight / 100) * member.hack +
(task.strWeight / 100) * member.str +
(task.defWeight / 100) * member.def +
(task.dexWeight / 100) * member.dex +
(task.agiWeight / 100) * member.agi +
(task.chaWeight / 100) * member.cha;
statWeight -= 3.2 * task.difficulty;
if (statWeight <= 0) return 0;
const territoryMult = Math.max(0.005, Math.pow(gang.territory * 100, task.territory.money) / 100);
if (isNaN(territoryMult) || territoryMult <= 0) return 0;
const respectMult = calculateWantedPenalty(gang);
const territoryPenalty = (0.2 * gang.territory + 0.8) * currentNodeMults.GangSoftcap;
return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);
}
function calculateAscensionPointsGain(exp: number): number {
return Math.max(exp - 1000, 0);
}
function calculateAscensionMult(points: number): number {
return Math.max(Math.pow(points / 2000, 0.5), 1);
}