This commit is contained in:
Olivier Gagnon 2021-10-07 01:36:59 -04:00
parent da746a63c3
commit 8e58482db0
21 changed files with 19132 additions and 569 deletions

11550
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -1,18 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta charset="utf-8" />
<title>Bitburner</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png"/>
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png"/>
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png"/>
<link rel="manifest" href="dist/site.webmanifest"/>
<link rel="mask-icon" href="dist/safari-pinned-tab.svg" color="#000000"/>
<meta name="apple-mobile-web-app-title" content="Bitburner"/>
<meta name="application-name" content="Bitburner"/>
<meta name="msapplication-TileColor" content="#000000"/>
<meta name="msapplication-config" content="dist/browserconfig.xml"/>
<meta name="theme-color" content="#ffffff"/>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png" />
<link rel="manifest" href="dist/site.webmanifest" />
<link rel="mask-icon" href="dist/safari-pinned-tab.svg" color="#000000" />
<meta name="apple-mobile-web-app-title" content="Bitburner" />
<meta name="application-name" content="Bitburner" />
<meta name="msapplication-TileColor" content="#000000" />
<meta name="msapplication-config" content="dist/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" />
<!-- Google Analytics -->
<script>
@ -51,7 +51,7 @@
</style>
<link rel="shortcut icon" href="favicon.ico"></head>
<body>
<div id="root"/>
<div id="root" />
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body>
<!-- http://plaza.dsolver.ca/m/hydroflame4418 -->
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -2377,8 +2377,7 @@ function initAugmentations(): void {
'Allison "Mother" Stanek imparts you with her gift. An ' +
"experimental Augmentation implanted at the base of the neck. " +
"It allows you to overclock your entire system by carefully " +
"changing the configuration.<br><br>" +
"Its unstable nature decreases all your stats by 10%",
"changing the configuration.",
isSpecial: true,
hacking_chance_mult: 0.9,
hacking_speed_mult: 0.9,
@ -2406,7 +2405,7 @@ function initAugmentations(): void {
hacknet_node_core_cost_mult: 1.1,
hacknet_node_level_cost_mult: 1.1,
work_money_mult: 0.9,
stats: null,
stats: <>Its unstable nature decreases all your stats by 10%</>,
});
StaneksGift1.addToFactions([ChurchOfTheMachineGodFactionName]);
resetAugmentation(StaneksGift1);

@ -542,7 +542,7 @@ BitNodes["BitNode13"] = new BitNode(
<br />
<br />
Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any
other.' + Find her in Chongquin and gain her trust.
other. Find her in Chongquing and gain her trust.
<br />
<br />
In this BitNode:
@ -557,17 +557,7 @@ BitNodes["BitNode13"] = new BitNode(
level up to a maximum of 3. This Source-File lets the Church of the Machine God appear in other BitNodes.
<br />
<br />
This Source-File also increases Stanek's Gift multipliers by:
<br />
<br />
Level 1: 8%
<br />
Level 2: 12%
<br />
Level 3: 14%
<br />
<br />
Each level of this Source-File also increases the size of the gift.
Each level of this Source-File increases the size of Stanek's Gift.
</>
),
);

@ -94,7 +94,7 @@ export function FragmentById(id: number): Fragment | null {
[_, _, X],
],
FragmentType.Hacking, // type
10,
1,
1, // limit
),
);
@ -108,7 +108,189 @@ export function FragmentById(id: number): Fragment | null {
[_, X, _],
],
FragmentType.Hacking, // type
10,
1,
1, // limit
),
);
Fragments.push(
new Fragment(
5, // id
[
// shape
[X, X],
],
FragmentType.HackingSpeed, // type
1.3,
1, // limit
),
);
Fragments.push(
new Fragment(
6, // id
[
[X, _],
[X, X],
], // shape
FragmentType.HackingMoney, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
7, // id
[
[X, X],
[X, X],
], // shape
FragmentType.HackingGrow, // type
0.5, // power
1, // limit
),
);
Fragments.push(
new Fragment(
8, // id
[
[X, X, X],
[_, X, _],
[X, X, X],
], // shape
FragmentType.Hacking, // type
1, // power
1, // limit
),
);
Fragments.push(
new Fragment(
10, // id
[
[X, X],
[_, X],
], // shape
FragmentType.Strength, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
12, // id
[
[_, X],
[X, X],
], // shape
FragmentType.Defense, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
14, // id
[
[X, X],
[X, _],
], // shape
FragmentType.Dexterity, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
16, // id
[
[X, _],
[X, X],
], // shape
FragmentType.Agility, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
18, // id
[
[X, X],
[X, _],
], // shape
FragmentType.Charisma, // type
3, // power
1, // limit
),
);
Fragments.push(
new Fragment(
20, // id
[
[X, _, _],
[X, X, _],
[X, X, X],
], // shape
FragmentType.HacknetMoney, // type
1, // power
1, // limit
),
);
Fragments.push(
new Fragment(
21, // id
[
[X, X],
[_, X],
[_, X],
], // shape
FragmentType.HacknetCost, // type
-1, // power
1, // limit
),
);
Fragments.push(
new Fragment(
25, // id
[
[X, X, X],
[_, X, _],
], // shape
FragmentType.Rep, // type
0.5, // power
1, // limit
),
);
Fragments.push(
new Fragment(
27, // id
[
[X, _],
[_, X],
], // shape
FragmentType.WorkMoney, // type
10, // power
1, // limit
),
);
Fragments.push(
new Fragment(
28, // id
[[X, X]], // shape
FragmentType.Crime, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
30, // id
[
[X, X, X],
[X, X, X],
[X, X, X],
], // shape
FragmentType.Bladeburner, // type
1.3, // power
1, // limit
),
);
@ -122,190 +304,23 @@ export function FragmentById(id: number): Fragment | null {
[X, X, X],
],
FragmentType.Booster, // type
500,
1.1, // power
3, // limit
),
);
Fragments.push(
new Fragment(
5, // id
31, // id
[
// shape
[X, X],
[X],
[X],
[X],
[X],
],
FragmentType.HackingSpeed, // type
50,
1, // limit
),
);
Fragments.push(
new Fragment(
6, // id
[
[X, _],
[X, X],
], // shape
FragmentType.HackingMoney, // type
10, // power
1, // limit
),
);
Fragments.push(
new Fragment(
7, // id
[
[X, X],
[X, X],
], // shape
FragmentType.HackingGrow, // type
30, // power
1, // limit
),
);
Fragments.push(
new Fragment(
8, // id
[
[X, X, X],
[_, X, _],
[X, X, X],
], // shape
FragmentType.Hacking, // type
50, // power
1, // limit
),
);
Fragments.push(
new Fragment(
10, // id
[
[X, X],
[_, X],
], // shape
FragmentType.Strength, // type
50, // power
1, // limit
),
);
Fragments.push(
new Fragment(
12, // id
[
[_, X],
[X, X],
], // shape
FragmentType.Defense, // type
50, // power
1, // limit
),
);
Fragments.push(
new Fragment(
14, // id
[
[X, X],
[X, _],
], // shape
FragmentType.Dexterity, // type
50, // power
1, // limit
),
);
Fragments.push(
new Fragment(
16, // id
[
[X, _],
[X, X],
], // shape
FragmentType.Agility, // type
50, // power
1, // limit
),
);
Fragments.push(
new Fragment(
18, // id
[
[X, X],
[X, _],
], // shape
FragmentType.Charisma, // type
50, // power
1, // limit
),
);
Fragments.push(
new Fragment(
20, // id
[
[X, _, _],
[X, X, _],
[X, X, X],
], // shape
FragmentType.HacknetMoney, // type
30, // power
1, // limit
),
);
Fragments.push(
new Fragment(
21, // id
[
[X, X],
[_, X],
[_, X],
], // shape
FragmentType.HacknetCost, // type
-10, // power
1, // limit
),
);
Fragments.push(
new Fragment(
25, // id
[
[X, X, X],
[_, X, _],
], // shape
FragmentType.Rep, // type
100, // power
1, // limit
),
);
Fragments.push(
new Fragment(
27, // id
[
[X, _],
[_, X],
], // shape
FragmentType.WorkMoney, // type
20, // power
1, // limit
),
);
Fragments.push(
new Fragment(
28, // id
[[X, X]], // shape
FragmentType.Crime, // type
20, // power
1, // limit
),
);
Fragments.push(
new Fragment(
30, // id
[
[X, X, X],
[X, X, X],
[X, X, X],
], // shape
FragmentType.Bladeburner, // type
50, // power
1, // limit
FragmentType.Booster, // type
1.1, // power
3, // limit
),
);
})();

@ -24,3 +24,73 @@ export enum FragmentType {
// utility fragments.
Booster,
}
export function Effect(tpe: FragmentType): string {
switch (tpe) {
case FragmentType.HackingChance: {
return "+x% hack() success chance";
break;
}
case FragmentType.HackingSpeed: {
return "+x% faster hack(), grow(), and weaken()";
break;
}
case FragmentType.HackingMoney: {
return "+x% hack() power";
break;
}
case FragmentType.HackingGrow: {
return "+x% grow() power";
break;
}
case FragmentType.Hacking: {
return "+x% hacking skill";
break;
}
case FragmentType.Strength: {
return "+x% strength skill";
break;
}
case FragmentType.Defense: {
return "+x% defense skill";
break;
}
case FragmentType.Dexterity: {
return "+x% dexterity skill";
break;
}
case FragmentType.Agility: {
return "+x% agility skill";
break;
}
case FragmentType.Charisma: {
return "+x% charisma skill";
break;
}
case FragmentType.HacknetMoney: {
return "+x% hacknet production";
break;
}
case FragmentType.HacknetCost: {
return "-x% all hacknet cost";
break;
}
case FragmentType.Rep: {
return "+x% reputation from factions and companies";
break;
}
case FragmentType.WorkMoney: {
return "+x% work money";
break;
}
case FragmentType.Crime: {
return "+x% crime money";
break;
}
case FragmentType.Bladeburner: {
return "+x% all bladeburner stats";
break;
}
}
throw new Error("Calling effect for fragment type that doesn't have an effect " + tpe);
}

@ -1,4 +1,3 @@
import { StaneksGift } from "./StaneksGift";
import { ActiveFragment } from "./ActiveFragment";
import { Fragment } from "./Fragment";
import { IPlayer } from "../PersonObjects/IPlayer";
@ -9,10 +8,11 @@ export interface IStaneksGift {
height(): number;
charge(worldX: number, worldY: number, ram: number): number;
process(p: IPlayer, n: number): void;
effect(fragment: ActiveFragment): number;
canPlace(x: number, y: number, fragment: Fragment): boolean;
place(x: number, y: number, fragment: Fragment): boolean;
fragmentAt(worldX: number, worldY: number): ActiveFragment | null;
deleteAt(worldX: number, worldY: number): boolean;
clear(): void;
count(fragment: Fragment): number;
};
}

@ -1,4 +1,4 @@
import { Fragment, FragmentById } from "./Fragment";
import { Fragment } from "./Fragment";
import { ActiveFragment } from "./ActiveFragment";
import { FragmentType } from "./FragmentType";
import { IStaneksGift } from "./IStaneksGift";
@ -22,42 +22,34 @@ export class StaneksGift implements IStaneksGift {
const af = this.fragmentAt(worldX, worldY);
if (af === null) return 0;
// Find all the neighbooring cells
const cells = af.neighboors();
const charge = CalculateCharge(ram);
af.charge += charge;
Factions["Church of the Machine God"].playerReputation += Math.log(ram) / Math.log(2);
return ram;
}
process(p: IPlayer, numCycles: number): void {
this.updateMults(p);
}
effect(fragment: ActiveFragment): number {
// Find all the neighbooring cells
const cells = fragment.neighboors();
// find the neighbooring active fragments.
const maybeFragments = cells.map((n) => this.fragmentAt(n[0], n[1]));
// Filter out nulls with typescript "Type guard". Whatever
let neighboors = maybeFragments.filter((v: ActiveFragment | null): v is ActiveFragment => !!v);
// filter unique fragments
neighboors = neighboors.filter((value, index) => neighboors.indexOf(value) === index);
// count number of neighbooring boosts and cooling.
neighboors = neighboors.filter((fragment) => fragment.fragment().type === FragmentType.Booster);
let boost = 1;
for (const neighboor of neighboors) {
const f = neighboor.fragment();
if (f.type === FragmentType.Booster) boost *= 1 + f.power / 1000;
boost *= neighboor.fragment().power;
}
const extraCharge = CalculateCharge(ram, boost);
af.charge += extraCharge;
Factions["Church of the Machine God"].playerReputation += extraCharge;
return ram;
}
process(p: IPlayer, numCycles: number): void {
for (const activeFragment of this.fragments) {
const fragment = activeFragment.fragment();
// Boosters and cooling don't deal with heat.
if (fragment.type === FragmentType.Booster) continue;
}
this.updateMults(p);
return CalculateEffect(fragment.charge, fragment.fragment().power, boost);
}
canPlace(x: number, y: number, fragment: Fragment): boolean {
@ -116,7 +108,8 @@ export class StaneksGift implements IStaneksGift {
for (const aFrag of this.fragments) {
const fragment = aFrag.fragment();
const power = CalculateEffect(aFrag.charge, fragment.power);
const power = this.effect(aFrag);
switch (fragment.type) {
case FragmentType.HackingChance:
p.hacking_chance_mult *= power;

@ -0,0 +1,5 @@
export const StanekConstants: {
RAMBonus: number;
} = {
RAMBonus: 0.1,
};

@ -1,4 +1,5 @@
export function CalculateCharge(ram: number, boost: number): number {
const extraCharge = ram * Math.pow(boost, 2);
return extraCharge;
import { StanekConstants } from "../data/Constants";
export function CalculateCharge(ram: number): number {
return ram * Math.pow(1 + Math.log2(ram) * StanekConstants.RAMBonus, 0.7);
}

@ -1,3 +1,3 @@
export function CalculateEffect(charge: number, power: number): number {
return Math.pow((power/1000)+1, Math.log(charge+1)/Math.log(8))
export function CalculateEffect(charge: number, power: number, boost: number): number {
return 1 + (Math.log(charge + 1) / (Math.log(3) * 100)) * power * boost;
}

2
src/CotMG/notes Normal file

@ -0,0 +1,2 @@
incentive for more threads
boosters just multiply output, eg 20% * 1.5 = 30%

@ -1,13 +1,14 @@
import React, { useState, useEffect } from "react";
import { ActiveFragment } from "../ActiveFragment";
import { FragmentType } from "../FragmentType";
import { IStaneksGift } from "../IStaneksGift";
import { FragmentType, Effect } from "../FragmentType";
import { numeralWrapper } from "../../ui/numeralFormat";
import { CalculateEffect } from "../formulas/effect";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
type IProps = {
gift: IStaneksGift;
fragment: ActiveFragment | null;
x: number;
y: number;
@ -28,7 +29,7 @@ export function FragmentInspector(props: IProps): React.ReactElement {
<Typography>
ID: N/A
<br />
Type: N/A
Effect: N/A
<br />
Magnitude: N/A
<br />
@ -48,24 +49,26 @@ export function FragmentInspector(props: IProps): React.ReactElement {
const f = props.fragment.fragment();
let charge = numeralWrapper.formatStaneksGiftCharge(props.fragment.charge);
let effect = "N/A";
// Boosters and cooling don't deal with heat.
if (f.type === FragmentType.Booster) {
if ([FragmentType.Booster, FragmentType.None, FragmentType.Delete].includes(f.type)) {
charge = "N/A";
effect = `${f.power}x adjacent fragment power`;
} else {
effect = Effect(f.type).replace("+x%", numeralWrapper.formatPercentage(props.gift.effect(props.fragment) - 1));
}
const effect = numeralWrapper.format(CalculateEffect(props.fragment.charge, f.power) - 1, "+0.00%");
return (
<Paper>
<Typography>
ID: {props.fragment.id}
<br />
Type: {FragmentType[f.type]}
Effect: {effect}
<br />
Power: {numeralWrapper.formatStaneksGiftPower(f.power)}
<br />
Charge: {charge}
<br />
Effect: {effect}
<br />
root [X, Y] {props.fragment.x}, {props.fragment.y}
<br />

@ -1,6 +1,6 @@
import React, { useState } from "react";
import { Fragments, Fragment, NoneFragment, DeleteFragment } from "../Fragment";
import { FragmentType } from "../FragmentType";
import { FragmentType, Effect } from "../FragmentType";
import { IStaneksGift } from "../IStaneksGift";
import { FragmentPreview } from "./FragmentPreview";
import { numeralWrapper } from "../../ui/numeralFormat";
@ -8,6 +8,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
type IOptionProps = {
gift: IStaneksGift;
@ -23,21 +24,26 @@ function FragmentOption(props: IOptionProps): React.ReactElement {
<></>
);
return (
<>
<Box display="flex">
<Box sx={{ mx: 2 }}>
<FragmentPreview
width={props.fragment.width()}
height={props.fragment.height()}
colorAt={(x, y) => {
return !props.fragment.fullAt(x, y) ? "" : props.fragment.type === FragmentType.Booster ? "blue" : "green";
}}
/>
</Box>
<Typography>
{FragmentType[props.fragment.type]}
{props.fragment.type === FragmentType.Booster
? `${props.fragment.power}x adjacent fragment power`
: Effect(props.fragment.type)}
<br />
power: {numeralWrapper.formatStaneksGiftPower(props.fragment.power)}
<br />
{remaining}
</Typography>
<br />
<FragmentPreview
width={props.fragment.width()}
height={props.fragment.height()}
colorAt={(x, y) => (props.fragment.fullAt(x, y) ? "green" : "")}
/>
</>
</Box>
);
}
@ -51,8 +57,13 @@ export function FragmentSelector(props: IProps): React.ReactElement {
function onChange(event: SelectChangeEvent<string | number>): void {
const v = event.target.value;
setValue(v);
if (v === "None") props.selectFragment(NoneFragment);
else if (v === "Delete") props.selectFragment(DeleteFragment);
if (v === "None") {
props.selectFragment(NoneFragment);
return;
} else if (v === "Delete") {
props.selectFragment(DeleteFragment);
return;
}
const fragment = Fragments.find((f) => f.id === v);
if (fragment === undefined) throw new Error("Fragment selector selected an undefined fragment with id " + v);
if (typeof v === "number") props.selectFragment(fragment);

@ -136,7 +136,7 @@ export function Grid(props: GridProps): React.ReactElement {
</Table>
<FragmentSelector gift={props.gift} selectFragment={updateSelectedFragment} />
<Button onClick={clear}>Clear</Button>
<FragmentInspector x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} />
<FragmentInspector gift={props.gift} x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} />
</>
);
}

@ -250,6 +250,10 @@ function prestigeSourceFile(flume: boolean): void {
dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!");
}
if (Player.bitNodeN === 13) {
dialogBoxCreate("Trouble is brewing in Chongqing");
}
// Reset Stock market, gang, and corporation
if (Player.hasWseAccount) {
initStockMarket();

@ -161,7 +161,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
const canJob = props.player.companyName !== "";
const canStockMarket = props.player.hasWseAccount;
const canBladeburner = !!(props.player.bladeburner as any);
const canStaneksGift = props.player.hasAugmentation(AugmentationNames.StaneksGift1);
const canStaneksGift = props.player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1);
function clickTerminal(): void {
props.router.toTerminal();
@ -442,7 +442,9 @@ export function SidebarRoot(props: IProps): React.ReactElement {
<DeveloperBoardIcon color={props.page !== Page.StaneksGift ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.StaneksGift ? "secondary" : "primary"}>StaneksGift</Typography>
<Typography color={props.page !== Page.StaneksGift ? "secondary" : "primary"}>
Stanek's Gift
</Typography>
</ListItemText>
</ListItem>
)}

@ -204,3 +204,7 @@ SourceFiles["SourceFile12"] = new SourceFile(
12,
<>This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.</>,
);
SourceFiles["SourceFile13"] = new SourceFile(
12,
<>Each level of this Source-File increases the size of Stanek's Gift.</>,
);

@ -174,7 +174,7 @@ class NumeralFormatter {
}
formatStaneksGiftPower(n: number): string {
return this.format(n, "0");
return this.format(n, "0.00");
}
parseMoney(s: string): number {