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

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 {