Fix hostname generation being weird about dash 0 added

This commit is contained in:
Olivier Gagnon 2022-09-23 12:04:21 -04:00
parent 66e80b2efa
commit fb197be206
10 changed files with 190 additions and 87 deletions

@ -21,7 +21,7 @@ import {
initUnstableCircadianModulator, initUnstableCircadianModulator,
} from "./data/AugmentationCreator"; } from "./data/AugmentationCreator";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { mergeMultipliers } from "../PersonObjects/Multipliers"; import { mergeAugmentation } from "../PersonObjects/Multipliers";
export function AddToStaticAugmentations(aug: Augmentation): void { export function AddToStaticAugmentations(aug: Augmentation): void {
const name = aug.name; const name = aug.name;
@ -75,7 +75,7 @@ function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void
const staticAugmentation = StaticAugmentations[aug.name]; const staticAugmentation = StaticAugmentations[aug.name];
// Apply multipliers // Apply multipliers
Player.mults = mergeMultipliers(Player.mults, staticAugmentation.mults); Player.mults = mergeAugmentation(Player.mults, staticAugmentation.mults);
// Special logic for Congruity Implant // Special logic for Congruity Implant
if (aug.name === AugmentationNames.CongruityImplant && !reapply) { if (aug.name === AugmentationNames.CongruityImplant && !reapply) {

@ -6,6 +6,7 @@ import { WHRNG } from "../../Casino/RNG";
import React from "react"; import React from "react";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { Faction } from "src/Faction/Faction";
interface CircadianBonus { interface CircadianBonus {
bonuses: { bonuses: {
@ -1630,6 +1631,16 @@ export const initGeneralAugmentations = (): Augmentation[] => [
factions: [FactionNames.TianDiHui], factions: [FactionNames.TianDiHui],
}), }),
// new Augmentation({
// name: AugmentationNames.UnnamedAug2,
// repCost: 500e3,
// moneyCost: 5e9,
// info: "Undecided description",
// startingMoney: 100e6,
// programs: [Programs.HTTPWormProgram.name, Programs.SQLInjectProgram.name],
// factions: [FactionNames.OmniTekIncorporated],
// }),
// Grafting-exclusive Augmentation // Grafting-exclusive Augmentation
new Augmentation({ new Augmentation({
name: AugmentationNames.CongruityImplant, name: AugmentationNames.CongruityImplant,
@ -1648,6 +1659,19 @@ export const initGeneralAugmentations = (): Augmentation[] => [
stats: <>This Augmentation removes the Entropy virus, and prevents it from affecting you again.</>, stats: <>This Augmentation removes the Entropy virus, and prevents it from affecting you again.</>,
factions: [], factions: [],
}), }),
// Sleeve exclusive augmentations
new Augmentation({
name: AugmentationNames.UnnamedAug1,
isSpecial: true,
repCost: Infinity,
moneyCost: 1e12,
info: "This augmentation is exclusive to sleeves.",
stats: <>Allows sleeves to benefit from Stanek's Gift but it is less powerful if several are installed.</>,
factions: [
/*Technically in FactionNames.ChurchOfTheMachineGod but not really for display reasons */
],
}),
]; ];
export const initBladeburnerAugmentations = (): Augmentation[] => [ export const initBladeburnerAugmentations = (): Augmentation[] => [

@ -93,6 +93,8 @@ export enum AugmentationNames {
CongruityImplant = "nickofolas Congruity Implant", CongruityImplant = "nickofolas Congruity Implant",
HydroflameLeftArm = "Hydroflame Left Arm", HydroflameLeftArm = "Hydroflame Left Arm",
BigDsBigBrain = "BigD's Big ... Brain", BigDsBigBrain = "BigD's Big ... Brain",
UnnamedAug1 = "UnnamedAug1",
UnnamedAug2 = "UnnamedAug2",
// Bladeburner augs // Bladeburner augs
EsperEyewear = "EsperTech Bladeburner Eyewear", EsperEyewear = "EsperTech Bladeburner Eyewear",

@ -4,7 +4,7 @@
import { DoubleArrow } from "@mui/icons-material"; import { DoubleArrow } from "@mui/icons-material";
import { List, ListItem, ListItemText, Paper, Typography } from "@mui/material"; import { List, ListItem, ListItemText, Paper, Typography } from "@mui/material";
import * as React from "react"; import * as React from "react";
import { Multipliers, defaultMultipliers, mergeMultipliers } from "../../PersonObjects/Multipliers"; import { Multipliers, defaultMultipliers, mergeAugmentation } from "../../PersonObjects/Multipliers";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
@ -15,7 +15,7 @@ function calculateAugmentedStats(): Multipliers {
let augP: Multipliers = defaultMultipliers(); let augP: Multipliers = defaultMultipliers();
for (const aug of Player.queuedAugmentations) { for (const aug of Player.queuedAugmentations) {
const augObj = StaticAugmentations[aug.name]; const augObj = StaticAugmentations[aug.name];
augP = mergeMultipliers(augP, augObj.mults); augP = mergeAugmentation(augP, augObj.mults);
} }
return augP; return augP;
} }

@ -13,6 +13,7 @@ import { StanekConstants } from "./data/Constants";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Player } from "../Player"; import { Player } from "../Player";
import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
import { defaultMultipliers, mergeMultipliers, Multipliers, scaleMultipliers } from "../PersonObjects/Multipliers";
export class StaneksGift implements IStaneksGift { export class StaneksGift implements IStaneksGift {
storedCycles = 0; storedCycles = 0;
@ -135,81 +136,101 @@ export class StaneksGift implements IStaneksGift {
}); });
} }
updateMults(p: IPlayer): void { calculateMults(): Multipliers {
// applyEntropy also reapplies all augmentations and source files const mults = defaultMultipliers();
// This wraps up the reset nicely
p.applyEntropy(p.entropy);
for (const aFrag of this.fragments) { for (const aFrag of this.fragments) {
const fragment = aFrag.fragment(); const fragment = aFrag.fragment();
const power = this.effect(aFrag); const power = this.effect(aFrag);
switch (fragment.type) { switch (fragment.type) {
case FragmentType.HackingChance: case FragmentType.HackingChance:
p.mults.hacking_chance *= power; mults.hacking_chance *= power;
break; break;
case FragmentType.HackingSpeed: case FragmentType.HackingSpeed:
p.mults.hacking_speed *= power; mults.hacking_speed *= power;
break; break;
case FragmentType.HackingMoney: case FragmentType.HackingMoney:
p.mults.hacking_money *= power; mults.hacking_money *= power;
break; break;
case FragmentType.HackingGrow: case FragmentType.HackingGrow:
p.mults.hacking_grow *= power; mults.hacking_grow *= power;
break; break;
case FragmentType.Hacking: case FragmentType.Hacking:
p.mults.hacking *= power; mults.hacking *= power;
p.mults.hacking_exp *= power; mults.hacking_exp *= power;
break; break;
case FragmentType.Strength: case FragmentType.Strength:
p.mults.strength *= power; mults.strength *= power;
p.mults.strength_exp *= power; mults.strength_exp *= power;
break; break;
case FragmentType.Defense: case FragmentType.Defense:
p.mults.defense *= power; mults.defense *= power;
p.mults.defense_exp *= power; mults.defense_exp *= power;
break; break;
case FragmentType.Dexterity: case FragmentType.Dexterity:
p.mults.dexterity *= power; mults.dexterity *= power;
p.mults.dexterity_exp *= power; mults.dexterity_exp *= power;
break; break;
case FragmentType.Agility: case FragmentType.Agility:
p.mults.agility *= power; mults.agility *= power;
p.mults.agility_exp *= power; mults.agility_exp *= power;
break; break;
case FragmentType.Charisma: case FragmentType.Charisma:
p.mults.charisma *= power; mults.charisma *= power;
p.mults.charisma_exp *= power; mults.charisma_exp *= power;
break; break;
case FragmentType.HacknetMoney: case FragmentType.HacknetMoney:
p.mults.hacknet_node_money *= power; mults.hacknet_node_money *= power;
break; break;
case FragmentType.HacknetCost: case FragmentType.HacknetCost:
p.mults.hacknet_node_purchase_cost /= power; mults.hacknet_node_purchase_cost /= power;
p.mults.hacknet_node_ram_cost /= power; mults.hacknet_node_ram_cost /= power;
p.mults.hacknet_node_core_cost /= power; mults.hacknet_node_core_cost /= power;
p.mults.hacknet_node_level_cost /= power; mults.hacknet_node_level_cost /= power;
break; break;
case FragmentType.Rep: case FragmentType.Rep:
p.mults.company_rep *= power; mults.company_rep *= power;
p.mults.faction_rep *= power; mults.faction_rep *= power;
break; break;
case FragmentType.WorkMoney: case FragmentType.WorkMoney:
p.mults.work_money *= power; mults.work_money *= power;
break; break;
case FragmentType.Crime: case FragmentType.Crime:
p.mults.crime_success *= power; mults.crime_success *= power;
p.mults.crime_money *= power; mults.crime_money *= power;
break; break;
case FragmentType.Bladeburner: case FragmentType.Bladeburner:
p.mults.bladeburner_max_stamina *= power; mults.bladeburner_max_stamina *= power;
p.mults.bladeburner_stamina_gain *= power; mults.bladeburner_stamina_gain *= power;
p.mults.bladeburner_analysis *= power; mults.bladeburner_analysis *= power;
p.mults.bladeburner_success_chance *= power; mults.bladeburner_success_chance *= power;
break; break;
} }
} }
return mults;
}
updateMults(p: IPlayer): void {
// applyEntropy also reapplies all augmentations and source files
// This wraps up the reset nicely
p.applyEntropy(p.entropy);
const mults = this.calculateMults();
p.mults = mergeMultipliers(p.mults, mults);
p.updateSkillLevels(); p.updateSkillLevels();
const unnamedAug1Amt = p.sleeves.reduce(
(n, sleeve) => n + (sleeve.hasAugmentation(AugmentationNames.UnnamedAug1) ? 1 : 0),
0,
);
if (unnamedAug1Amt === 0) return;
// Less powerful for each copy.
const scaling = 3 / (unnamedAug1Amt + 2);
const sleeveMults = scaleMultipliers(mults, scaling);
for (const sleeve of p.sleeves) {
if (!sleeve.hasAugmentation(AugmentationNames.UnnamedAug1)) continue;
sleeve.resetMultipliers();
sleeve.mults = mergeMultipliers(sleeve.mults, sleeveMults);
sleeve.updateStatLevels();
}
} }
prestigeAugmentation(): void { prestigeAugmentation(): void {

@ -68,7 +68,7 @@ export const defaultMultipliers = (): Multipliers => {
}; };
}; };
export const mergeMultipliers = (m0: Multipliers, m1: AugmentationStats): Multipliers => { export const mergeAugmentation = (m0: Multipliers, m1: AugmentationStats): Multipliers => {
return { return {
hacking_chance: m0.hacking_chance * (m1.hacking_chance ?? 1), hacking_chance: m0.hacking_chance * (m1.hacking_chance ?? 1),
hacking_speed: m0.hacking_speed * (m1.hacking_speed ?? 1), hacking_speed: m0.hacking_speed * (m1.hacking_speed ?? 1),
@ -102,3 +102,73 @@ export const mergeMultipliers = (m0: Multipliers, m1: AugmentationStats): Multip
bladeburner_success_chance: m0.bladeburner_success_chance * (m1.bladeburner_success_chance ?? 1), bladeburner_success_chance: m0.bladeburner_success_chance * (m1.bladeburner_success_chance ?? 1),
}; };
}; };
export const mergeMultipliers = (m0: Multipliers, m1: Multipliers): Multipliers => {
return {
hacking_chance: m0.hacking_chance * m1.hacking_chance,
hacking_speed: m0.hacking_speed * m1.hacking_speed,
hacking_money: m0.hacking_money * m1.hacking_money,
hacking_grow: m0.hacking_grow * m1.hacking_grow,
hacking: m0.hacking * m1.hacking,
hacking_exp: m0.hacking_exp * m1.hacking_exp,
strength: m0.strength * m1.strength,
strength_exp: m0.strength_exp * m1.strength_exp,
defense: m0.defense * m1.defense,
defense_exp: m0.defense_exp * m1.defense_exp,
dexterity: m0.dexterity * m1.dexterity,
dexterity_exp: m0.dexterity_exp * m1.dexterity_exp,
agility: m0.agility * m1.agility,
agility_exp: m0.agility_exp * m1.agility_exp,
charisma: m0.charisma * m1.charisma,
charisma_exp: m0.charisma_exp * m1.charisma_exp,
hacknet_node_money: m0.hacknet_node_money * m1.hacknet_node_money,
hacknet_node_purchase_cost: m0.hacknet_node_purchase_cost * m1.hacknet_node_purchase_cost,
hacknet_node_ram_cost: m0.hacknet_node_ram_cost * m1.hacknet_node_ram_cost,
hacknet_node_core_cost: m0.hacknet_node_core_cost * m1.hacknet_node_core_cost,
hacknet_node_level_cost: m0.hacknet_node_level_cost * m1.hacknet_node_level_cost,
company_rep: m0.company_rep * m1.company_rep,
faction_rep: m0.faction_rep * m1.faction_rep,
work_money: m0.work_money * m1.work_money,
crime_success: m0.crime_success * m1.crime_success,
crime_money: m0.crime_money * m1.crime_money,
bladeburner_max_stamina: m0.bladeburner_max_stamina * m1.bladeburner_max_stamina,
bladeburner_stamina_gain: m0.bladeburner_stamina_gain * m1.bladeburner_stamina_gain,
bladeburner_analysis: m0.bladeburner_analysis * m1.bladeburner_analysis,
bladeburner_success_chance: m0.bladeburner_success_chance * m1.bladeburner_success_chance,
};
};
export const scaleMultipliers = (m0: Multipliers, v: number): Multipliers => {
return {
hacking_chance: (m0.hacking_chance - 1) * v + 1,
hacking_speed: (m0.hacking_speed - 1) * v + 1,
hacking_money: (m0.hacking_money - 1) * v + 1,
hacking_grow: (m0.hacking_grow - 1) * v + 1,
hacking: (m0.hacking - 1) * v + 1,
hacking_exp: (m0.hacking_exp - 1) * v + 1,
strength: (m0.strength - 1) * v + 1,
strength_exp: (m0.strength_exp - 1) * v + 1,
defense: (m0.defense - 1) * v + 1,
defense_exp: (m0.defense_exp - 1) * v + 1,
dexterity: (m0.dexterity - 1) * v + 1,
dexterity_exp: (m0.dexterity_exp - 1) * v + 1,
agility: (m0.agility - 1) * v + 1,
agility_exp: (m0.agility_exp - 1) * v + 1,
charisma: (m0.charisma - 1) * v + 1,
charisma_exp: (m0.charisma_exp - 1) * v + 1,
hacknet_node_money: (m0.hacknet_node_money - 1) * v + 1,
hacknet_node_purchase_cost: (m0.hacknet_node_purchase_cost - 1) * v + 1,
hacknet_node_ram_cost: (m0.hacknet_node_ram_cost - 1) * v + 1,
hacknet_node_core_cost: (m0.hacknet_node_core_cost - 1) * v + 1,
hacknet_node_level_cost: (m0.hacknet_node_level_cost - 1) * v + 1,
company_rep: (m0.company_rep - 1) * v + 1,
faction_rep: (m0.faction_rep - 1) * v + 1,
work_money: (m0.work_money - 1) * v + 1,
crime_success: (m0.crime_success - 1) * v + 1,
crime_money: (m0.crime_money - 1) * v + 1,
bladeburner_max_stamina: (m0.bladeburner_max_stamina - 1) * v + 1,
bladeburner_stamina_gain: (m0.bladeburner_stamina_gain - 1) * v + 1,
bladeburner_analysis: (m0.bladeburner_analysis - 1) * v + 1,
bladeburner_success_chance: (m0.bladeburner_success_chance - 1) * v + 1,
};
};

@ -7,7 +7,7 @@ import { CONSTANTS } from "../Constants";
import { calculateSkill } from "./formulas/skill"; import { calculateSkill } from "./formulas/skill";
import { calculateIntelligenceBonus } from "./formulas/intelligence"; import { calculateIntelligenceBonus } from "./formulas/intelligence";
import { IPerson } from "./IPerson"; import { IPerson } from "./IPerson";
import { defaultMultipliers, mergeMultipliers } from "./Multipliers"; import { defaultMultipliers, mergeAugmentation } from "./Multipliers";
import { Skills } from "./Skills"; import { Skills } from "./Skills";
import { HP } from "./HP"; import { HP } from "./HP";
@ -61,7 +61,7 @@ export abstract class Person implements IPerson {
* Updates this object's multipliers for the given augmentation * Updates this object's multipliers for the given augmentation
*/ */
applyAugmentation(aug: Augmentation): void { applyAugmentation(aug: Augmentation): void {
this.mults = mergeMultipliers(this.mults, aug.mults); this.mults = mergeAugmentation(this.mults, aug.mults);
} }
/** /**

@ -280,15 +280,15 @@ export class Sleeve extends Person {
return true; return true;
} }
hasAugmentation(aug: string): boolean {
return this.augmentations.some((a) => a.name === aug);
}
tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean { tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean {
if (!p.canAfford(aug.baseCost)) { if (!p.canAfford(aug.baseCost)) return false;
return false;
}
// Verify that this sleeve does not already have that augmentation. // Verify that this sleeve does not already have that augmentation.
if (this.augmentations.some((a) => a.name === aug.name)) { if (this.hasAugmentation(aug.name)) return false;
return false;
}
p.loseMoney(aug.baseCost, "sleeves"); p.loseMoney(aug.baseCost, "sleeves");
this.installAugmentation(aug); this.installAugmentation(aug);
@ -296,11 +296,6 @@ export class Sleeve extends Person {
} }
upgradeMemory(n: number): void { upgradeMemory(n: number): void {
if (n < 0) {
console.warn(`Sleeve.upgradeMemory() called with negative value: ${n}`);
return;
}
this.memory = Math.min(100, Math.round(this.memory + n)); this.memory = Math.min(100, Math.round(this.memory + n));
} }

@ -5,32 +5,24 @@ import { IPlayer } from "../IPlayer";
import { Augmentation } from "../../Augmentation/Augmentation"; import { Augmentation } from "../../Augmentation/Augmentation";
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations"; import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { Multipliers } from "../Multipliers"; import { Multipliers } from "../Multipliers";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentation[] { export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentation[] {
// You can only purchase Augmentations that are actually available from // You can only purchase Augmentations that are actually available from
// your factions. I.e. you must be in a faction that has the Augmentation // your factions. I.e. you must be in a faction that has the Augmentation
// and you must also have enough rep in that faction in order to purchase it. // and you must also have enough rep in that faction in order to purchase it.
const ownedAugNames: string[] = sleeve.augmentations.map((e) => { const ownedAugNames = sleeve.augmentations.map((e) => e.name);
return e.name;
});
const availableAugs: Augmentation[] = []; const availableAugs: Augmentation[] = [];
// Helper function that helps filter out augs that are already owned // Helper function that helps filter out augs that are already owned
// and augs that aren't allowed for sleeves // and augs that aren't allowed for sleeves
function isAvailableForSleeve(aug: Augmentation): boolean { function isAvailableForSleeve(aug: Augmentation): boolean {
if (ownedAugNames.includes(aug.name)) { if (ownedAugNames.includes(aug.name)) return false;
return false; if (availableAugs.includes(aug)) return false;
} if (aug.isSpecial) return false;
if (availableAugs.includes(aug)) {
return false;
}
if (aug.isSpecial) {
return false;
}
type MultKey = keyof Multipliers; type MultKey = keyof Multipliers;
const validMults: MultKey[] = [ const validMults: MultKey[] = [
@ -53,9 +45,7 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
"work_money", "work_money",
]; ];
for (const mult of validMults) { for (const mult of validMults) {
if (aug.mults[mult] !== 1) { if (aug.mults[mult] !== 1) return true;
return true;
}
} }
return false; return false;
@ -68,9 +58,7 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
for (const augName of Object.keys(StaticAugmentations)) { for (const augName of Object.keys(StaticAugmentations)) {
const aug = StaticAugmentations[augName]; const aug = StaticAugmentations[augName];
if (!isAvailableForSleeve(aug)) { if (!isAvailableForSleeve(aug)) continue;
continue;
}
if (fac.playerReputation > aug.getCost(p).repCost) { if (fac.playerReputation > aug.getCost(p).repCost) {
availableAugs.push(aug); availableAugs.push(aug);
@ -79,22 +67,14 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
} }
for (const facName of p.factions) { for (const facName of p.factions) {
if (facName === FactionNames.Bladeburners) { if (facName === FactionNames.Bladeburners) continue;
continue; if (facName === FactionNames.Netburners) continue;
} const fac = Factions[facName];
if (facName === FactionNames.Netburners) { if (!fac) continue;
continue;
}
const fac: Faction | null = Factions[facName];
if (fac == null) {
continue;
}
for (const augName of fac.augmentations) { for (const augName of fac.augmentations) {
const aug: Augmentation = StaticAugmentations[augName]; const aug = StaticAugmentations[augName];
if (!isAvailableForSleeve(aug)) { if (!isAvailableForSleeve(aug)) continue;
continue;
}
if (fac.playerReputation > aug.getCost(p).repCost) { if (fac.playerReputation > aug.getCost(p).repCost) {
availableAugs.push(aug); availableAugs.push(aug);
@ -102,5 +82,14 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
} }
} }
// Add the stanek sleeve aug
if (
!ownedAugNames.includes(AugmentationNames.UnnamedAug1) &&
p.factions.includes(FactionNames.ChurchOfTheMachineGod)
) {
const aug = StaticAugmentations[AugmentationNames.UnnamedAug1];
availableAugs.push(aug);
}
return availableAugs; return availableAugs;
} }

@ -23,7 +23,9 @@ export function safetlyCreateUniqueServer(params: IConstructorParams): Server {
} }
if (GetServer(hostname) != null) { if (GetServer(hostname) != null) {
hostname = `${hostname}-0`; if (hostname.slice(-2) != `-0`) {
hostname = `${hostname}-0`;
}
// Use a for loop to ensure that we don't get suck in an infinite loop somehow // Use a for loop to ensure that we don't get suck in an infinite loop somehow
for (let i = 0; i < 200; ++i) { for (let i = 0; i < 200; ++i) {