2019-04-14 11:08:10 +02:00
|
|
|
import { Augmentations } from "../Augmentation/Augmentations";
|
2021-09-24 23:16:14 +02:00
|
|
|
import { Augmentation } from "../Augmentation/Augmentation";
|
2019-04-14 11:08:10 +02:00
|
|
|
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
|
|
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
|
|
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
|
|
|
import { CONSTANTS } from "../Constants";
|
2021-09-18 01:43:08 +02:00
|
|
|
|
2019-04-14 11:08:10 +02:00
|
|
|
import { Faction } from "./Faction";
|
|
|
|
import { Factions } from "./Factions";
|
|
|
|
import { Player } from "../Player";
|
2022-03-30 03:10:07 +02:00
|
|
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
2019-04-14 11:08:10 +02:00
|
|
|
import { Settings } from "../Settings/Settings";
|
2021-09-05 01:09:30 +02:00
|
|
|
import {
|
|
|
|
getHackingWorkRepGain,
|
|
|
|
getFactionSecurityWorkRepGain,
|
|
|
|
getFactionFieldWorkRepGain,
|
2021-04-18 17:18:56 +02:00
|
|
|
} from "../PersonObjects/formulas/reputation";
|
2021-08-15 08:14:07 +02:00
|
|
|
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-25 20:42:57 +02:00
|
|
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
2021-10-01 19:08:37 +02:00
|
|
|
import { InvitationEvent } from "./ui/InvitationModal";
|
2022-03-19 09:09:59 +01:00
|
|
|
import { FactionNames } from "./data/FactionNames";
|
2022-03-31 02:58:09 +02:00
|
|
|
import { SFC32RNG } from "../Casino/RNG";
|
2022-02-28 12:47:37 +01:00
|
|
|
|
2021-09-24 23:16:14 +02:00
|
|
|
export function inviteToFaction(faction: Faction): void {
|
2021-12-09 00:29:56 +01:00
|
|
|
Player.receiveInvite(faction.name);
|
2021-09-13 00:03:07 +02:00
|
|
|
faction.alreadyInvited = true;
|
|
|
|
if (!Settings.SuppressFactionInvites) {
|
2021-10-01 19:08:37 +02:00
|
|
|
InvitationEvent.emit(faction);
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-24 23:16:14 +02:00
|
|
|
export function joinFaction(faction: Faction): void {
|
2021-09-05 01:09:30 +02:00
|
|
|
if (faction.isMember) return;
|
|
|
|
faction.isMember = true;
|
|
|
|
Player.factions.push(faction.name);
|
2022-03-30 03:10:07 +02:00
|
|
|
const allFactions = Object.values(FactionNames).map((faction) => faction as string);
|
|
|
|
Player.factions.sort((a, b) => allFactions.indexOf(a) - allFactions.indexOf(b));
|
2021-09-05 01:09:30 +02:00
|
|
|
const factionInfo = faction.getInfo();
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
//Determine what factions you are banned from now that you have joined this faction
|
2022-01-16 01:45:03 +01:00
|
|
|
for (const enemy of factionInfo.enemies) {
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Factions[enemy] instanceof Faction) {
|
|
|
|
Factions[enemy].isBanned = true;
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2021-09-25 07:26:03 +02:00
|
|
|
for (let i = 0; i < Player.factionInvitations.length; ++i) {
|
2021-09-09 05:47:34 +02:00
|
|
|
if (Player.factionInvitations[i] == faction.name || Factions[Player.factionInvitations[i]].isBanned) {
|
2021-09-05 01:09:30 +02:00
|
|
|
Player.factionInvitations.splice(i, 1);
|
|
|
|
i--;
|
2021-05-06 21:49:20 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//Returns a boolean indicating whether the player has the prerequisites for the
|
|
|
|
//specified Augmentation
|
2021-09-24 23:16:14 +02:00
|
|
|
export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
2021-09-05 01:09:30 +02:00
|
|
|
let hasPrereqs = true;
|
|
|
|
if (aug.prereqs && aug.prereqs.length > 0) {
|
|
|
|
for (let i = 0; i < aug.prereqs.length; ++i) {
|
|
|
|
const prereqAug = Augmentations[aug.prereqs[i]];
|
|
|
|
if (prereqAug == null) {
|
|
|
|
console.error(`Invalid prereq Augmentation ${aug.prereqs[i]}`);
|
|
|
|
continue;
|
|
|
|
}
|
2022-04-13 18:24:01 +02:00
|
|
|
|
|
|
|
if (Player.hasAugmentation(prereqAug, true) === false) {
|
2021-09-05 01:09:30 +02:00
|
|
|
hasPrereqs = false;
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Check if the aug is purchased
|
|
|
|
for (let j = 0; j < Player.queuedAugmentations.length; ++j) {
|
|
|
|
if (Player.queuedAugmentations[j].name === prereqAug.name) {
|
|
|
|
hasPrereqs = true;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
return hasPrereqs;
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-24 23:16:14 +02:00
|
|
|
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
2021-09-25 07:26:03 +02:00
|
|
|
const hasPrereqs = hasAugmentationPrereqs(aug);
|
2021-09-05 01:09:30 +02:00
|
|
|
if (!hasPrereqs) {
|
2022-03-16 20:43:04 +01:00
|
|
|
const txt = `You must first purchase or install ${aug.prereqs.join(",")} before you can purchase this one.`;
|
2021-09-05 01:09:30 +02:00
|
|
|
if (sing) {
|
|
|
|
return txt;
|
|
|
|
} else {
|
|
|
|
dialogBoxCreate(txt);
|
|
|
|
}
|
2022-04-12 23:18:36 +02:00
|
|
|
} else if (aug.baseCost !== 0 && Player.money < aug.baseCost) {
|
2021-09-25 07:26:03 +02:00
|
|
|
const txt = "You don't have enough money to purchase " + aug.name;
|
2021-09-05 01:09:30 +02:00
|
|
|
if (sing) {
|
|
|
|
return txt;
|
|
|
|
}
|
|
|
|
dialogBoxCreate(txt);
|
|
|
|
} else if (fac.playerReputation < aug.baseRepRequirement) {
|
2021-09-25 07:26:03 +02:00
|
|
|
const txt = "You don't have enough faction reputation to purchase " + aug.name;
|
2021-09-05 01:09:30 +02:00
|
|
|
if (sing) {
|
|
|
|
return txt;
|
|
|
|
}
|
|
|
|
dialogBoxCreate(txt);
|
2022-04-12 23:18:36 +02:00
|
|
|
} else if (aug.baseCost === 0 || Player.money >= aug.baseCost) {
|
2021-09-25 07:26:03 +02:00
|
|
|
const queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
2021-09-05 01:09:30 +02:00
|
|
|
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
|
|
|
queuedAugmentation.level = getNextNeurofluxLevel();
|
|
|
|
}
|
|
|
|
Player.queuedAugmentations.push(queuedAugmentation);
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2022-04-12 23:18:36 +02:00
|
|
|
Player.loseMoney(aug.baseCost, "augmentations");
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// If you just purchased Neuroflux Governor, recalculate the cost
|
|
|
|
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
2021-09-25 07:26:03 +02:00
|
|
|
let nextLevel = getNextNeurofluxLevel();
|
2021-09-05 01:09:30 +02:00
|
|
|
--nextLevel;
|
2021-09-25 07:26:03 +02:00
|
|
|
const mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
2021-09-09 05:47:34 +02:00
|
|
|
aug.baseRepRequirement = 500 * mult * BitNodeMultipliers.AugmentationRepCost;
|
2021-09-05 01:09:30 +02:00
|
|
|
aug.baseCost = 750e3 * mult * BitNodeMultipliers.AugmentationMoneyCost;
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-25 07:26:03 +02:00
|
|
|
for (let i = 0; i < Player.queuedAugmentations.length - 1; ++i) {
|
2021-09-09 05:47:34 +02:00
|
|
|
aug.baseCost *= CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]];
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2022-01-16 01:45:03 +01:00
|
|
|
for (const name of Object.keys(Augmentations)) {
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Augmentations.hasOwnProperty(name)) {
|
2021-09-09 05:47:34 +02:00
|
|
|
Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]];
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (sing) {
|
|
|
|
return "You purchased " + aug.name;
|
2022-03-11 16:32:48 +01:00
|
|
|
} else if (!Settings.SuppressBuyAugmentationConfirmation) {
|
2022-03-19 09:09:59 +01:00
|
|
|
dialogBoxCreate(
|
|
|
|
"You purchased " +
|
2022-03-30 03:10:07 +02:00
|
|
|
aug.name +
|
|
|
|
". Its enhancements will not take " +
|
|
|
|
"effect until they are installed. To install your augmentations, go to the " +
|
|
|
|
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
|
|
|
"augmentations will now be more expensive.",
|
2022-03-19 09:09:59 +01:00
|
|
|
);
|
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
} else {
|
|
|
|
dialogBoxCreate(
|
|
|
|
"Hmm, something went wrong when trying to purchase an Augmentation. " +
|
2022-03-30 03:10:07 +02:00
|
|
|
"Please report this to the game developer with an explanation of how to " +
|
|
|
|
"reproduce this.",
|
2021-09-05 01:09:30 +02:00
|
|
|
);
|
|
|
|
}
|
2021-09-24 23:16:14 +02:00
|
|
|
return "";
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-24 23:16:14 +02:00
|
|
|
export function getNextNeurofluxLevel(): number {
|
2021-09-05 01:09:30 +02:00
|
|
|
// Get current Neuroflux level based on Player's augmentations
|
|
|
|
let currLevel = 0;
|
2021-09-25 08:36:49 +02:00
|
|
|
for (let i = 0; i < Player.augmentations.length; ++i) {
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
|
|
|
currLevel = Player.augmentations[i].level;
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Account for purchased but uninstalled Augmentations
|
2021-09-25 08:36:49 +02:00
|
|
|
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
|
2021-09-09 05:47:34 +02:00
|
|
|
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
2021-09-05 01:09:30 +02:00
|
|
|
++currLevel;
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
return currLevel + 1;
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-24 23:16:14 +02:00
|
|
|
export function processPassiveFactionRepGain(numCycles: number): void {
|
2022-01-16 01:45:03 +01:00
|
|
|
for (const name of Object.keys(Factions)) {
|
2021-09-05 01:09:30 +02:00
|
|
|
if (name === Player.currentWorkFactionName) continue;
|
|
|
|
if (!Factions.hasOwnProperty(name)) continue;
|
|
|
|
const faction = Factions[name];
|
|
|
|
if (!faction.isMember) continue;
|
|
|
|
// No passive rep for special factions
|
|
|
|
const info = faction.getInfo();
|
|
|
|
if (!info.offersWork()) continue;
|
|
|
|
// No passive rep for gangs.
|
|
|
|
if (Player.getGangName() === name) continue;
|
|
|
|
// 0 favor = 1%/s
|
|
|
|
// 50 favor = 6%/s
|
|
|
|
// 100 favor = 11%/s
|
|
|
|
const favorMult = Math.min(0.1, faction.favor / 1000 + 0.01);
|
|
|
|
// Find the best of all possible favor gain, minimum 1 rep / 2 minute.
|
|
|
|
const hRep = getHackingWorkRepGain(Player, faction);
|
|
|
|
const sRep = getFactionSecurityWorkRepGain(Player, faction);
|
|
|
|
const fRep = getFactionFieldWorkRepGain(Player, faction);
|
2021-09-09 05:47:34 +02:00
|
|
|
const rate = Math.max(hRep * favorMult, sRep * favorMult, fRep * favorMult, 1 / 120);
|
2021-04-18 17:18:56 +02:00
|
|
|
|
2021-09-09 05:47:34 +02:00
|
|
|
faction.playerReputation += rate * numCycles * Player.faction_rep_mult * BitNodeMultipliers.FactionPassiveRepGain;
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
}
|
2022-03-30 03:10:07 +02:00
|
|
|
|
2022-03-31 02:58:09 +02:00
|
|
|
export const getFactionAugmentationsFiltered = (player: IPlayer, faction: Faction): string[] => {
|
2022-03-30 03:10:07 +02:00
|
|
|
// If player has a gang with this faction, return (almost) all augmentations
|
|
|
|
if (player.hasGangWith(faction.name)) {
|
|
|
|
let augs = Object.values(Augmentations);
|
|
|
|
|
|
|
|
// Remove special augs
|
|
|
|
augs = augs.filter((a) => !a.isSpecial);
|
|
|
|
|
2022-04-08 06:39:11 +02:00
|
|
|
const blacklist: string[] = [AugmentationNames.NeuroFluxGovernor, AugmentationNames.CongruityImplant];
|
2022-03-30 03:10:07 +02:00
|
|
|
|
|
|
|
if (player.bitNodeN !== 2) {
|
|
|
|
// TRP is not available outside of BN2 for Gangs
|
|
|
|
blacklist.push(AugmentationNames.TheRedPill);
|
|
|
|
}
|
|
|
|
|
2022-03-31 02:58:09 +02:00
|
|
|
const rng = SFC32RNG(`BN${player.bitNodeN}.${player.sourceFileLvl(player.bitNodeN)}`);
|
|
|
|
// Remove faction-unique augs that don't belong to this faction
|
|
|
|
const uniqueFilter = (a: Augmentation): boolean => {
|
|
|
|
// Keep all the non-unique one
|
|
|
|
if (a.factions.length > 1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Keep all the ones that this faction has anyway.
|
|
|
|
if (faction.augmentations.includes(a.name)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rng() >= 1 - BitNodeMultipliers.GangUniqueAugs;
|
|
|
|
};
|
|
|
|
augs = augs.filter(uniqueFilter);
|
|
|
|
|
2022-03-30 03:10:07 +02:00
|
|
|
// Remove blacklisted augs
|
|
|
|
augs = augs.filter((a) => !blacklist.includes(a.name));
|
|
|
|
|
|
|
|
return augs.map((a) => a.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return faction.augmentations.slice();
|
|
|
|
};
|