215 lines
6.6 KiB
TypeScript
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);
|
|
}
|