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
+193 -178
View File
@@ -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
),
);
})();
+70
View File
@@ -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);
}
+13 -13
View File
@@ -1,18 +1,18 @@
import { StaneksGift } from "./StaneksGift";
import { ActiveFragment } from "./ActiveFragment";
import { Fragment } from "./Fragment";
import { IPlayer } from "../PersonObjects/IPlayer";
export interface IStaneksGift {
fragments: ActiveFragment[];
width(): number;
height(): number;
charge(worldX: number, worldY: number, ram: number): number;
process(p: IPlayer, n: number): void;
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;
};
fragments: ActiveFragment[];
width(): number;
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;
}
+20 -27
View File
@@ -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;
+5
View File
@@ -0,0 +1,5 @@
export const StanekConstants: {
RAMBonus: number;
} = {
RAMBonus: 0.1,
};
+4 -3
View File
@@ -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);
}
+3 -3
View File
@@ -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
View File
@@ -0,0 +1,2 @@
incentive for more threads
boosters just multiply output, eg 20% * 1.5 = 30%
+10 -7
View File
@@ -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 />
+23 -12
View File
@@ -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);
+1 -1
View File
@@ -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])} />
</>
);
}