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); }