fix decimal

This commit is contained in:
Olivier Gagnon
2021-11-11 21:35:26 -05:00
65 changed files with 340 additions and 309 deletions

46
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,7 @@ getPlayer() Netscript Function
Returns an object with the Player's stats. The object has the following properties:: Returns an object with the Player's stats. The object has the following properties::
{ {
hacking_skill: Current Hacking skill level hacking: Current Hacking skill level
hp: Current health points hp: Current health points
max_hp: Maximum health points max_hp: Maximum health points
strength: Current Strength skill level strength: Current Strength skill level

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

22
package-lock.json generated
View File

@ -1,11 +1,11 @@
{ {
"name": "bitburner", "name": "bitburner",
"version": "0.58.0", "version": "1.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "0.58.0", "version": "1.0.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"dependencies": { "dependencies": {
@ -28,6 +28,7 @@
"arg": "^5.0.0", "arg": "^5.0.0",
"better-react-mathjax": "^1.0.3", "better-react-mathjax": "^1.0.3",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"date-fns": "^2.25.0",
"decimal.js": "7.2.3", "decimal.js": "7.2.3",
"escodegen": "^1.11.0", "escodegen": "^1.11.0",
"file-saver": "^1.3.8", "file-saver": "^1.3.8",
@ -6963,6 +6964,18 @@
"whatwg-url": "^7.0.0" "whatwg-url": "^7.0.0"
} }
}, },
"node_modules/date-fns": {
"version": "2.25.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz",
"integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==",
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/date-now": { "node_modules/date-now": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
@ -26992,6 +27005,11 @@
"whatwg-url": "^7.0.0" "whatwg-url": "^7.0.0"
} }
}, },
"date-fns": {
"version": "2.25.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz",
"integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w=="
},
"date-now": { "date-now": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",

View File

@ -29,7 +29,7 @@
"arg": "^5.0.0", "arg": "^5.0.0",
"better-react-mathjax": "^1.0.3", "better-react-mathjax": "^1.0.3",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"decimal.js": "7.2.3", "date-fns": "^2.25.0",
"escodegen": "^1.11.0", "escodegen": "^1.11.0",
"file-saver": "^1.3.8", "file-saver": "^1.3.8",
"jquery": "^3.5.0", "jquery": "^3.5.0",

View File

@ -27,12 +27,12 @@ export function NewIndustry(corporation: ICorporation, industry: string, name: s
if (cost === undefined) { if (cost === undefined) {
throw new Error(`Invalid industry: '${industry}'`); throw new Error(`Invalid industry: '${industry}'`);
} }
if (corporation.funds.lt(cost)) { if (corporation.funds < cost) {
throw new Error("Not enough money to create a new division in this industry"); throw new Error("Not enough money to create a new division in this industry");
} else if (name === "") { } else if (name === "") {
throw new Error("New division must have a name!"); throw new Error("New division must have a name!");
} else { } else {
corporation.funds = corporation.funds.minus(cost); corporation.funds = corporation.funds - cost;
corporation.divisions.push( corporation.divisions.push(
new Industry({ new Industry({
corp: corporation, corp: corporation,
@ -44,10 +44,10 @@ export function NewIndustry(corporation: ICorporation, industry: string, name: s
} }
export function NewCity(corporation: ICorporation, division: IIndustry, city: string): void { export function NewCity(corporation: ICorporation, division: IIndustry, city: string): void {
if (corporation.funds.lt(CorporationConstants.OfficeInitialCost)) { if (corporation.funds < CorporationConstants.OfficeInitialCost) {
throw new Error("You don't have enough company funds to open a new office!"); throw new Error("You don't have enough company funds to open a new office!");
} else { } else {
corporation.funds = corporation.funds.minus(CorporationConstants.OfficeInitialCost); corporation.funds = corporation.funds - CorporationConstants.OfficeInitialCost;
division.offices[city] = new OfficeSpace({ division.offices[city] = new OfficeSpace({
loc: city, loc: city,
size: CorporationConstants.OfficeInitialSize, size: CorporationConstants.OfficeInitialSize,
@ -56,7 +56,7 @@ export function NewCity(corporation: ICorporation, division: IIndustry, city: st
} }
export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnlockUpgrade): void { export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnlockUpgrade): void {
if (corporation.funds.lt(upgrade[1])) { if (corporation.funds < upgrade[1]) {
throw new Error("Insufficient funds"); throw new Error("Insufficient funds");
} }
corporation.unlock(upgrade); corporation.unlock(upgrade);
@ -67,7 +67,7 @@ export function LevelUpgrade(corporation: ICorporation, upgrade: CorporationUpgr
const priceMult = upgrade[2]; const priceMult = upgrade[2];
const level = corporation.upgrades[upgrade[0]]; const level = corporation.upgrades[upgrade[0]];
const cost = baseCost * Math.pow(priceMult, level); const cost = baseCost * Math.pow(priceMult, level);
if (corporation.funds.lt(cost)) { if (corporation.funds < cost) {
throw new Error("Insufficient funds"); throw new Error("Insufficient funds");
} else { } else {
corporation.upgrade(upgrade); corporation.upgrade(upgrade);
@ -259,15 +259,15 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size:
mult += Math.pow(costMultiplier, initialPriceMult + i); mult += Math.pow(costMultiplier, initialPriceMult + i);
} }
const cost = CorporationConstants.OfficeInitialCost * mult; const cost = CorporationConstants.OfficeInitialCost * mult;
if (corp.funds.lt(cost)) return; if (corp.funds < cost) return;
office.size += size; office.size += size;
corp.funds = corp.funds.minus(cost); corp.funds = corp.funds - cost;
} }
export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number { export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number {
const totalCost = costPerEmployee * office.employees.length; const totalCost = costPerEmployee * office.employees.length;
if (corp.funds.lt(totalCost)) return 0; if (corp.funds < totalCost) return 0;
corp.funds = corp.funds.minus(totalCost); corp.funds = corp.funds - totalCost;
let mult = 0; let mult = 0;
for (let i = 0; i < office.employees.length; ++i) { for (let i = 0; i < office.employees.length; ++i) {
mult = office.employees[i].throwParty(costPerEmployee); mult = office.employees[i].throwParty(costPerEmployee);
@ -277,7 +277,7 @@ export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmplo
} }
export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city: string): void { export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city: string): void {
if (corp.funds.lt(CorporationConstants.WarehouseInitialCost)) return; if (corp.funds < CorporationConstants.WarehouseInitialCost) return;
if (division.warehouses[city] instanceof Warehouse) return; if (division.warehouses[city] instanceof Warehouse) return;
division.warehouses[city] = new Warehouse({ division.warehouses[city] = new Warehouse({
corp: corp, corp: corp,
@ -285,21 +285,21 @@ export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city:
loc: city, loc: city,
size: CorporationConstants.WarehouseInitialSize, size: CorporationConstants.WarehouseInitialSize,
}); });
corp.funds = corp.funds.minus(CorporationConstants.WarehouseInitialCost); corp.funds = corp.funds - CorporationConstants.WarehouseInitialCost;
} }
export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse): void { export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse): void {
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1); const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
++warehouse.level; ++warehouse.level;
warehouse.updateSize(corp, division); warehouse.updateSize(corp, division);
corp.funds = corp.funds.minus(sizeUpgradeCost); corp.funds = corp.funds - sizeUpgradeCost;
} }
export function BuyCoffee(corp: ICorporation, division: IIndustry, office: OfficeSpace): void { export function BuyCoffee(corp: ICorporation, division: IIndustry, office: OfficeSpace): void {
const upgrade = IndustryUpgrades[0]; const upgrade = IndustryUpgrades[0];
const cost = office.employees.length * upgrade[1]; const cost = office.employees.length * upgrade[1];
if (corp.funds.lt(cost)) return; if (corp.funds < cost) return;
corp.funds = corp.funds.minus(cost); corp.funds = corp.funds - cost;
division.upgrade(upgrade, { division.upgrade(upgrade, {
corporation: corp, corporation: corp,
office: office, office: office,
@ -309,8 +309,8 @@ export function BuyCoffee(corp: ICorporation, division: IIndustry, office: Offic
export function HireAdVert(corp: ICorporation, division: IIndustry, office: OfficeSpace): void { export function HireAdVert(corp: ICorporation, division: IIndustry, office: OfficeSpace): void {
const upgrade = IndustryUpgrades[1]; const upgrade = IndustryUpgrades[1];
const cost = upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]); const cost = upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]);
if (corp.funds.lt(cost)) return; if (corp.funds < cost) return;
corp.funds = corp.funds.minus(cost); corp.funds = corp.funds - cost;
division.upgrade(upgrade, { division.upgrade(upgrade, {
corporation: corp, corporation: corp,
office: office, office: office,
@ -340,7 +340,7 @@ export function MakeProduct(
if (isNaN(marketingInvest)) { if (isNaN(marketingInvest)) {
throw new Error("Invalid value for marketing investment"); throw new Error("Invalid value for marketing investment");
} }
if (corp.funds.lt(designInvest + marketingInvest)) { if (corp.funds < designInvest + marketingInvest) {
throw new Error("You don't have enough company funds to make this large of an investment"); throw new Error("You don't have enough company funds to make this large of an investment");
} }
const product = new Product({ const product = new Product({
@ -352,7 +352,7 @@ export function MakeProduct(
if (division.products[product.name] instanceof Product) { if (division.products[product.name] instanceof Product) {
throw new Error(`You already have a product with this name!`); throw new Error(`You already have a product with this name!`);
} }
corp.funds = corp.funds.minus(designInvest + marketingInvest); corp.funds = corp.funds - (designInvest + marketingInvest);
division.products[product.name] = product; division.products[product.name] = product;
} }

View File

@ -14,10 +14,6 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver"; import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver";
import { isString } from "../utils/helpers/isString"; import { isString } from "../utils/helpers/isString";
// UI Related Imports
import Decimal from "decimal.js";
interface IParams { interface IParams {
name?: string; name?: string;
} }
@ -29,9 +25,9 @@ export class Corporation {
divisions: Industry[] = []; divisions: Industry[] = [];
//Financial stats //Financial stats
funds = new Decimal(150e9); funds = 150e9;
revenue = new Decimal(0); revenue = 0;
expenses = new Decimal(0); expenses = 0;
fundingRound = 0; fundingRound = 0;
public = false; //Publicly traded public = false; //Publicly traded
totalShares = CorporationConstants.INITIALSHARES; // Total existing shares totalShares = CorporationConstants.INITIALSHARES; // Total existing shares
@ -65,7 +61,7 @@ export class Corporation {
console.error("Trying to add invalid amount of funds. Report to a developper."); console.error("Trying to add invalid amount of funds. Report to a developper.");
return; return;
} }
this.funds = this.funds.plus(amt); this.funds = this.funds + amt;
} }
getState(): string { getState(): string {
@ -97,8 +93,8 @@ export class Corporation {
//At the start of a new cycle, calculate profits from previous cycle //At the start of a new cycle, calculate profits from previous cycle
if (state === "START") { if (state === "START") {
this.revenue = new Decimal(0); this.revenue = 0;
this.expenses = new Decimal(0); this.expenses = 0;
this.divisions.forEach((ind) => { this.divisions.forEach((ind) => {
if (ind.lastCycleRevenue === -Infinity || ind.lastCycleRevenue === Infinity) { if (ind.lastCycleRevenue === -Infinity || ind.lastCycleRevenue === Infinity) {
return; return;
@ -106,18 +102,18 @@ export class Corporation {
if (ind.lastCycleExpenses === -Infinity || ind.lastCycleExpenses === Infinity) { if (ind.lastCycleExpenses === -Infinity || ind.lastCycleExpenses === Infinity) {
return; return;
} }
this.revenue = this.revenue.plus(ind.lastCycleRevenue); this.revenue = this.revenue + ind.lastCycleRevenue;
this.expenses = this.expenses.plus(ind.lastCycleExpenses); this.expenses = this.expenses + ind.lastCycleExpenses;
}); });
const profit = this.revenue.minus(this.expenses); const profit = this.revenue - this.expenses;
const cycleProfit = profit.times(marketCycles * CorporationConstants.SecsPerMarketCycle); const cycleProfit = profit * (marketCycles * CorporationConstants.SecsPerMarketCycle);
if (isNaN(this.funds) || this.funds === Infinity || this.funds === -Infinity) { if (isNaN(this.funds) || this.funds === Infinity || this.funds === -Infinity) {
dialogBoxCreate( dialogBoxCreate(
"There was an error calculating your Corporations funds and they got reset to 0. " + "There was an error calculating your Corporations funds and they got reset to 0. " +
"This is a bug. Please report to game developer.<br><br>" + "This is a bug. Please report to game developer.<br><br>" +
"(Your funds have been set to $150b for the inconvenience)", "(Your funds have been set to $150b for the inconvenience)",
); );
this.funds = new Decimal(150e9); this.funds = 150e9;
} }
// Process dividends // Process dividends
@ -147,28 +143,36 @@ export class Corporation {
} }
getDividends(): number { getDividends(): number {
const profit = this.revenue.minus(this.expenses); const profit = this.revenue - this.expenses;
const cycleProfit = profit.times(CorporationConstants.SecsPerMarketCycle); const cycleProfit = profit * CorporationConstants.SecsPerMarketCycle;
const totalDividends = (this.dividendPercentage / 100) * cycleProfit; const totalDividends = (this.dividendPercentage / 100) * cycleProfit;
const dividendsPerShare = totalDividends / this.totalShares; const dividendsPerShare = totalDividends / this.totalShares;
const dividends = this.numShares * dividendsPerShare * (1 - this.dividendTaxPercentage / 100); const dividends = this.numShares * dividendsPerShare * (1 - this.dividendTaxPercentage / 100);
return Math.pow(dividends, BitNodeMultipliers.CorporationSoftCap); let upgrades = -0.15;
if (this.unlockUpgrades[5] === 1) {
upgrades += 0.05;
}
if (this.unlockUpgrades[6] === 1) {
upgrades += 0.1;
}
console.log(upgrades);
return Math.pow(dividends, BitNodeMultipliers.CorporationSoftCap + upgrades);
} }
determineValuation(): number { determineValuation(): number {
let val, let val,
profit = this.revenue.minus(this.expenses).toNumber(); profit = this.revenue - this.expenses;
if (this.public) { if (this.public) {
// Account for dividends // Account for dividends
if (this.dividendPercentage > 0) { if (this.dividendPercentage > 0) {
profit *= (100 - this.dividendPercentage) / 100; profit *= (100 - this.dividendPercentage) / 100;
} }
val = this.funds.toNumber() + profit * 85e3; val = this.funds + profit * 85e3;
val *= Math.pow(1.1, this.divisions.length); val *= Math.pow(1.1, this.divisions.length);
val = Math.max(val, 0); val = Math.max(val, 0);
} else { } else {
val = 10e9 + Math.max(this.funds.toNumber(), 0) / 3; //Base valuation val = 10e9 + Math.max(this.funds, 0) / 3; //Base valuation
if (profit > 0) { if (profit > 0) {
val += profit * 315e3; val += profit * 315e3;
val *= Math.pow(1.1, this.divisions.length); val *= Math.pow(1.1, this.divisions.length);
@ -262,12 +266,12 @@ export class Corporation {
while (this.unlockUpgrades.length <= upgN) { while (this.unlockUpgrades.length <= upgN) {
this.unlockUpgrades.push(0); this.unlockUpgrades.push(0);
} }
if (this.funds.lt(price)) { if (this.funds < price) {
dialogBoxCreate("You don't have enough funds to unlock this!"); dialogBoxCreate("You don't have enough funds to unlock this!");
return; return;
} }
this.unlockUpgrades[upgN] = 1; this.unlockUpgrades[upgN] = 1;
this.funds = this.funds.minus(price); this.funds = this.funds - price;
// Apply effects for one-time upgrades // Apply effects for one-time upgrades
if (upgN === 5) { if (upgN === 5) {
@ -290,12 +294,12 @@ export class Corporation {
this.upgradeMultipliers.push(1); this.upgradeMultipliers.push(1);
} }
const totalCost = basePrice * Math.pow(priceMult, this.upgrades[upgN]); const totalCost = basePrice * Math.pow(priceMult, this.upgrades[upgN]);
if (this.funds.lt(totalCost)) { if (this.funds < totalCost) {
dialogBoxCreate("You don't have enough funds to purchase this!"); dialogBoxCreate("You don't have enough funds to purchase this!");
return; return;
} }
++this.upgrades[upgN]; ++this.upgrades[upgN];
this.funds = this.funds.minus(totalCost); this.funds = this.funds - totalCost;
//Increase upgrade multiplier //Increase upgrade multiplier
this.upgradeMultipliers[upgN] = 1 + this.upgrades[upgN] * upgradeAmt; this.upgradeMultipliers[upgN] = 1 + this.upgrades[upgN] * upgradeAmt;

View File

@ -9,9 +9,9 @@ export interface ICorporation {
divisions: Industry[]; divisions: Industry[];
funds: any; funds: number;
revenue: any; revenue: number;
expenses: any; expenses: number;
fundingRound: number; fundingRound: number;
public: boolean; public: boolean;
totalShares: number; totalShares: number;

View File

@ -31,10 +31,10 @@ export interface IIndustry {
prodMult: number; prodMult: number;
// Decimal // Decimal
lastCycleRevenue: any; lastCycleRevenue: number;
lastCycleExpenses: any; lastCycleExpenses: number;
thisCycleRevenue: any; thisCycleRevenue: number;
thisCycleExpenses: any; thisCycleExpenses: number;
upgrades: number[]; upgrades: number[];

View File

@ -1,6 +1,5 @@
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver"; import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
import Decimal from "decimal.js";
import { Industries, IndustryStartingCosts, IndustryResearchTrees } from "./IndustryData"; import { Industries, IndustryStartingCosts, IndustryResearchTrees } from "./IndustryData";
import { CorporationConstants } from "./data/Constants"; import { CorporationConstants } from "./data/Constants";
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
@ -55,10 +54,10 @@ export class Industry implements IIndustry {
prodMult = 0; //Production multiplier prodMult = 0; //Production multiplier
//Financials //Financials
lastCycleRevenue: any; lastCycleRevenue: number;
lastCycleExpenses: any; lastCycleExpenses: number;
thisCycleRevenue: any; thisCycleRevenue: number;
thisCycleExpenses: any; thisCycleExpenses: number;
//Upgrades //Upgrades
upgrades: number[] = Array(Object.keys(IndustryUpgrades).length).fill(0); upgrades: number[] = Array(Object.keys(IndustryUpgrades).length).fill(0);
@ -87,10 +86,10 @@ export class Industry implements IIndustry {
this.type = params.type ? params.type : Industries.Agriculture; this.type = params.type ? params.type : Industries.Agriculture;
//Financials //Financials
this.lastCycleRevenue = new Decimal(0); this.lastCycleRevenue = 0;
this.lastCycleExpenses = new Decimal(0); this.lastCycleExpenses = 0;
this.thisCycleRevenue = new Decimal(0); this.thisCycleRevenue = 0;
this.thisCycleExpenses = new Decimal(0); this.thisCycleExpenses = 0;
this.warehouses = { this.warehouses = {
[CityName.Aevum]: 0, [CityName.Aevum]: 0,
@ -399,17 +398,17 @@ export class Industry implements IIndustry {
dialogBoxCreate( dialogBoxCreate(
"Something went wrong when compting Corporation's revenue/expenses. This is a bug. Please report to game developer", "Something went wrong when compting Corporation's revenue/expenses. This is a bug. Please report to game developer",
); );
this.thisCycleRevenue = new Decimal(0); this.thisCycleRevenue = 0;
this.thisCycleExpenses = new Decimal(0); this.thisCycleExpenses = 0;
} }
this.lastCycleRevenue = this.thisCycleRevenue.dividedBy(marketCycles * CorporationConstants.SecsPerMarketCycle); this.lastCycleRevenue = this.thisCycleRevenue / (marketCycles * CorporationConstants.SecsPerMarketCycle);
this.lastCycleExpenses = this.thisCycleExpenses.dividedBy(marketCycles * CorporationConstants.SecsPerMarketCycle); this.lastCycleExpenses = this.thisCycleExpenses / (marketCycles * CorporationConstants.SecsPerMarketCycle);
this.thisCycleRevenue = new Decimal(0); this.thisCycleRevenue = 0;
this.thisCycleExpenses = new Decimal(0); this.thisCycleExpenses = 0;
// Once you start making revenue, the player should no longer be // Once you start making revenue, the player should no longer be
// considered new, and therefore no longer needs the 'tutorial' UI elements // considered new, and therefore no longer needs the 'tutorial' UI elements
if (this.lastCycleRevenue.gt(0)) { if (this.lastCycleRevenue > 0) {
this.newInd = false; this.newInd = false;
} }
@ -422,7 +421,7 @@ export class Industry implements IIndustry {
employeeSalary += office.process(marketCycles, corporation, this); employeeSalary += office.process(marketCycles, corporation, this);
} }
} }
this.thisCycleExpenses = this.thisCycleExpenses.plus(employeeSalary); this.thisCycleExpenses = this.thisCycleExpenses + employeeSalary;
// Process change in demand/competition of materials/products // Process change in demand/competition of materials/products
this.processMaterialMarket(); this.processMaterialMarket();
@ -446,15 +445,15 @@ export class Industry implements IIndustry {
// Process production, purchase, and import/export of materials // Process production, purchase, and import/export of materials
let res = this.processMaterials(marketCycles, corporation); let res = this.processMaterials(marketCycles, corporation);
if (Array.isArray(res)) { if (Array.isArray(res)) {
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]); this.thisCycleRevenue = this.thisCycleRevenue + res[0];
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]); this.thisCycleExpenses = this.thisCycleExpenses + res[1];
} }
// Process creation, production & sale of products // Process creation, production & sale of products
res = this.processProducts(marketCycles, corporation); res = this.processProducts(marketCycles, corporation);
if (Array.isArray(res)) { if (Array.isArray(res)) {
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]); this.thisCycleRevenue = this.thisCycleRevenue + res[0];
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]); this.thisCycleExpenses = this.thisCycleExpenses + res[1];
} }
} }
@ -1476,10 +1475,10 @@ export class Industry implements IIndustry {
division.prodMult = this.prodMult; division.prodMult = this.prodMult;
division.state = this.state; division.state = this.state;
division.newInd = this.newInd; division.newInd = this.newInd;
division.lastCycleRevenue = this.lastCycleRevenue.plus(0); division.lastCycleRevenue = this.lastCycleRevenue + 0;
division.lastCycleExpenses = this.lastCycleExpenses.plus(0); division.lastCycleExpenses = this.lastCycleExpenses + 0;
division.thisCycleRevenue = this.thisCycleRevenue.plus(0); division.thisCycleRevenue = this.thisCycleRevenue + 0;
division.thisCycleExpenses = this.thisCycleExpenses.plus(0); division.thisCycleExpenses = this.thisCycleExpenses + 0;
division.upgrades = this.upgrades.slice(); division.upgrades = this.upgrades.slice();
division.prodMats = this.prodMats.slice(); division.prodMats = this.prodMats.slice();
return division; return division;

View File

@ -53,14 +53,14 @@ export const CorporationUnlockUpgrades: IMap<CorporationUnlockUpgrade> = {
], ],
"5": [ "5": [
5, 5,
500e9, 500e12,
"Shady Accounting", "Shady Accounting",
"Utilize unscrupulous accounting practices and pay off government officials to save money " + "Utilize unscrupulous accounting practices and pay off government officials to save money " +
"on taxes. This reduces the dividend tax rate by 5%.", "on taxes. This reduces the dividend tax rate by 5%.",
], ],
"6": [ "6": [
6, 6,
2e12, 2e15,
"Government Partnership", "Government Partnership",
"Help national governments further their agendas in exchange for lowered taxes. " + "Help national governments further their agendas in exchange for lowered taxes. " +
"This reduces the dividend tax rate by 10%", "This reduces the dividend tax rate by 10%",

View File

@ -38,7 +38,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
isNaN(stock) || isNaN(stock) ||
money < 0 || money < 0 ||
stock < 0 || stock < 0 ||
corp.funds.lt(money) || corp.funds < money ||
stock > corp.numShares; stock > corp.numShares;
function onMoneyChange(event: React.ChangeEvent<HTMLInputElement>): void { function onMoneyChange(event: React.ChangeEvent<HTMLInputElement>): void {
@ -61,7 +61,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
if (money === 0 && stock === 0) return ""; if (money === 0 && stock === 0) return "";
if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) { if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) {
return "ERROR: Invalid value(s) entered"; return "ERROR: Invalid value(s) entered";
} else if (corp.funds.lt(money)) { } else if (corp.funds < money) {
return "ERROR: You do not have this much money to bribe with"; return "ERROR: You do not have this much money to bribe with";
} else if (stock > corp.numShares) { } else if (stock > corp.numShares) {
return "ERROR: You do not have this many shares to bribe with"; return "ERROR: You do not have this many shares to bribe with";
@ -84,7 +84,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
"You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.", "You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.",
); );
fac.playerReputation += rep; fac.playerReputation += rep;
corp.funds = corp.funds.minus(money); corp.funds = corp.funds - money;
corp.numShares -= stock; corp.numShares -= stock;
props.onClose(); props.onClose();
} }

View File

@ -32,7 +32,7 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
if (cost === undefined) { if (cost === undefined) {
throw new Error(`Invalid industry: '${industry}'`); throw new Error(`Invalid industry: '${industry}'`);
} }
const disabled = corp.funds.lt(cost) || name === ""; const disabled = corp.funds < cost || name === "";
function newIndustry(): void { function newIndustry(): void {
if (disabled) return; if (disabled) return;

View File

@ -19,7 +19,7 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
const possibleCities = Object.keys(division.offices).filter((cityName: string) => division.offices[cityName] === 0); const possibleCities = Object.keys(division.offices).filter((cityName: string) => division.offices[cityName] === 0);
const [city, setCity] = useState(possibleCities[0]); const [city, setCity] = useState(possibleCities[0]);
const disabled = corp.funds.lt(CorporationConstants.OfficeInitialCost); const disabled = corp.funds < CorporationConstants.OfficeInitialCost;
function onCityChange(event: SelectChangeEvent<string>): void { function onCityChange(event: SelectChangeEvent<string>): void {
setCity(event.target.value); setCity(event.target.value);

View File

@ -440,7 +440,7 @@ export function IndustryOffice(props: IProps): React.ReactElement {
<br /> <br />
<Tooltip title={<Typography>Upgrade the office's size so that it can hold more employees!</Typography>}> <Tooltip title={<Typography>Upgrade the office's size so that it can hold more employees!</Typography>}>
<span> <span>
<Button disabled={corp.funds.lt(0)} onClick={() => setUpgradeOfficeSizeOpen(true)}> <Button disabled={corp.funds < 0} onClick={() => setUpgradeOfficeSizeOpen(true)}>
Upgrade size Upgrade size
</Button> </Button>
</span> </span>
@ -458,7 +458,7 @@ export function IndustryOffice(props: IProps): React.ReactElement {
title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>} title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>}
> >
<span> <span>
<Button disabled={corp.funds.lt(0)} onClick={() => setThrowPartyOpen(true)}> <Button disabled={corp.funds < 0} onClick={() => setThrowPartyOpen(true)}>
Throw Party Throw Party
</Button> </Button>
</span> </span>

View File

@ -79,11 +79,7 @@ function MakeProductButton(): React.ReactElement {
) )
} }
> >
<Button <Button color={shouldFlash() ? "error" : "primary"} onClick={() => setMakeOpen(true)} disabled={corp.funds < 0}>
color={shouldFlash() ? "error" : "primary"}
onClick={() => setMakeOpen(true)}
disabled={corp.funds.lt(0)}
>
{createProductButtonText} {createProductButtonText}
</Button> </Button>
</Tooltip> </Tooltip>
@ -97,7 +93,7 @@ function Text(): React.ReactElement {
const [helpOpen, setHelpOpen] = useState(false); const [helpOpen, setHelpOpen] = useState(false);
const [researchOpen, setResearchOpen] = useState(false); const [researchOpen, setResearchOpen] = useState(false);
const vechain = corp.unlockUpgrades[4] === 1; const vechain = corp.unlockUpgrades[4] === 1;
const profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber(); const profit = division.lastCycleRevenue - division.lastCycleExpenses;
let advertisingInfo = false; let advertisingInfo = false;
const advertisingFactors = division.getAdvertisingFactors(); const advertisingFactors = division.getAdvertisingFactors();
@ -119,7 +115,7 @@ function Text(): React.ReactElement {
return ( return (
<> <>
<Typography> <Typography>
Industry: {division.type} (Corp Funds: <Money money={corp.funds.toNumber()} />) Industry: {division.type} (Corp Funds: <Money money={corp.funds} />)
</Typography> </Typography>
<br /> <br />
<StatsTable <StatsTable
@ -149,8 +145,8 @@ function Text(): React.ReactElement {
<br /> <br />
<StatsTable <StatsTable
rows={[ rows={[
["Revenue:", <MoneyRate money={division.lastCycleRevenue.toNumber()} />], ["Revenue:", <MoneyRate money={division.lastCycleRevenue} />],
["Expenses:", <MoneyRate money={division.lastCycleExpenses.toNumber()} />], ["Expenses:", <MoneyRate money={division.lastCycleExpenses} />],
["Profit:", <MoneyRate money={profit} />], ["Profit:", <MoneyRate money={profit} />],
]} ]}
/> />
@ -241,8 +237,8 @@ function Upgrades(props: { office: OfficeSpace; rerender: () => void }): React.R
} }
function onClick(): void { function onClick(): void {
if (corp.funds.lt(cost)) return; if (corp.funds < cost) return;
corp.funds = corp.funds.minus(cost); corp.funds = corp.funds - cost;
division.upgrade(upgrade, { division.upgrade(upgrade, {
corporation: corp, corporation: corp,
office: props.office, office: props.office,
@ -253,7 +249,7 @@ function Upgrades(props: { office: OfficeSpace; rerender: () => void }): React.R
upgrades.push( upgrades.push(
<Tooltip key={index} title={upgrade[5]}> <Tooltip key={index} title={upgrade[5]}>
<span> <span>
<Button disabled={corp.funds.lt(cost)} onClick={onClick}> <Button disabled={corp.funds < cost} onClick={onClick}>
{upgrade[4]} -&nbsp; {upgrade[4]} -&nbsp;
<MoneyCost money={cost} corp={corp} /> <MoneyCost money={cost} corp={corp} />
</Button> </Button>

View File

@ -45,14 +45,14 @@ function WarehouseRoot(props: IProps): React.ReactElement {
// Upgrade Warehouse size button // Upgrade Warehouse size button
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, props.warehouse.level + 1); const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, props.warehouse.level + 1);
const canAffordUpgrade = corp.funds.gt(sizeUpgradeCost); const canAffordUpgrade = corp.funds > sizeUpgradeCost;
function upgradeWarehouseOnClick(): void { function upgradeWarehouseOnClick(): void {
if (division === null) return; if (division === null) return;
if (props.warehouse === 0) return; if (props.warehouse === 0) return;
if (!canAffordUpgrade) return; if (!canAffordUpgrade) return;
++props.warehouse.level; ++props.warehouse.level;
props.warehouse.updateSize(corp, division); props.warehouse.updateSize(corp, division);
corp.funds = corp.funds.minus(sizeUpgradeCost); corp.funds = corp.funds - sizeUpgradeCost;
props.rerender(); props.rerender();
} }
@ -197,7 +197,7 @@ interface IEmptyProps {
function EmptyWarehouse(props: IEmptyProps): React.ReactElement { function EmptyWarehouse(props: IEmptyProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
const division = useDivision(); const division = useDivision();
const disabled = corp.funds.lt(CorporationConstants.WarehouseInitialCost); const disabled = corp.funds < CorporationConstants.WarehouseInitialCost;
function purchaseWarehouse(): void { function purchaseWarehouse(): void {
if (disabled) return; if (disabled) return;
PurchaseWarehouse(corp, division, props.city); PurchaseWarehouse(corp, division, props.city);

View File

@ -81,7 +81,7 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
privateShares = Math.round(privateShares / 1e6) * 1e6; privateShares = Math.round(privateShares / 1e6) * 1e6;
corp.issuedShares += newShares - privateShares; corp.issuedShares += newShares - privateShares;
corp.funds = corp.funds.plus(profit); corp.funds = corp.funds + profit;
corp.immediatelyUpdateSharePrice(); corp.immediatelyUpdateSharePrice();
props.onClose(); props.onClose();
dialogBoxCreate( dialogBoxCreate(

View File

@ -28,7 +28,7 @@ export function LevelableUpgrade(props: IProps): React.ReactElement {
const tooltip = data[5]; const tooltip = data[5];
function onClick(): void { function onClick(): void {
if (corp.funds.lt(cost)) return; if (corp.funds < cost) return;
try { try {
LevelUpgrade(corp, props.upgrade); LevelUpgrade(corp, props.upgrade);
} catch (err) { } catch (err) {
@ -40,11 +40,13 @@ export function LevelableUpgrade(props: IProps): React.ReactElement {
return ( return (
<Grid item xs={4}> <Grid item xs={4}>
<Box display="flex" alignItems="center" flexDirection="row-reverse"> <Box display="flex" alignItems="center" flexDirection="row-reverse">
<Button disabled={corp.funds.lt(cost)} sx={{ mx: 1 }} onClick={onClick}> <Button disabled={corp.funds < cost} sx={{ mx: 1 }} onClick={onClick}>
<MoneyCost money={cost} corp={corp} /> <MoneyCost money={cost} corp={corp} />
</Button> </Button>
<Tooltip title={tooltip}> <Tooltip title={tooltip}>
<Typography>{data[4]} - lvl {level}</Typography> <Typography>
{data[4]} - lvl {level}
</Typography>
</Tooltip> </Tooltip>
</Box> </Box>
</Grid> </Grid>

View File

@ -23,7 +23,7 @@ interface IProps {
export function MoneyCost(props: IProps): React.ReactElement { export function MoneyCost(props: IProps): React.ReactElement {
const classes = useStyles(); const classes = useStyles();
if (!props.corp.funds.gt(props.money)) if (!(props.corp.funds > props.money))
return <span className={classes.unbuyable}>{numeralWrapper.formatMoney(props.money)}</span>; return <span className={classes.unbuyable}>{numeralWrapper.formatMoney(props.money)}</span>;
return <span className={classes.money}>{numeralWrapper.formatMoney(props.money)}</span>; return <span className={classes.money}>{numeralWrapper.formatMoney(props.money)}</span>;

View File

@ -36,7 +36,7 @@ interface IProps {
export function Overview({ rerender }: IProps): React.ReactElement { export function Overview({ rerender }: IProps): React.ReactElement {
const player = use.Player(); const player = use.Player();
const corp = useCorporation(); const corp = useCorporation();
const profit: number = corp.revenue.minus(corp.expenses).toNumber(); const profit: number = corp.revenue - corp.expenses;
const multRows: any[][] = []; const multRows: any[][] = [];
function appendMult(name: string, value: number): void { function appendMult(name: string, value: number): void {
@ -57,9 +57,9 @@ export function Overview({ rerender }: IProps): React.ReactElement {
<> <>
<StatsTable <StatsTable
rows={[ rows={[
["Total Funds:", <Money money={corp.funds.toNumber()} />], ["Total Funds:", <Money money={corp.funds} />],
["Total Revenue:", <MoneyRate money={corp.revenue.toNumber()} />], ["Total Revenue:", <MoneyRate money={corp.revenue} />],
["Total Expenses:", <MoneyRate money={corp.expenses.toNumber()} />], ["Total Expenses:", <MoneyRate money={corp.expenses} />],
["Publicly Traded:", corp.public ? "Yes" : "No"], ["Publicly Traded:", corp.public ? "Yes" : "No"],
["Owned Stock Shares:", numeralWrapper.format(corp.numShares, "0.000a")], ["Owned Stock Shares:", numeralWrapper.format(corp.numShares, "0.000a")],
["Stock Price:", corp.public ? <Money money={corp.sharePrice} /> : "N/A"], ["Stock Price:", corp.public ? <Money money={corp.sharePrice} /> : "N/A"],

View File

@ -25,15 +25,25 @@ function BulkPurchaseText(props: IBulkPurchaseTextProps): React.ReactElement {
const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize; const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize;
if (parsedAmt * matSize > maxAmount) { if (parsedAmt * matSize > maxAmount) {
return <><Typography color={"error"}>Not enough warehouse space to purchase this amount</Typography></>; return (
<>
<Typography color={"error"}>Not enough warehouse space to purchase this amount</Typography>
</>
);
} else if (isNaN(cost)) { } else if (isNaN(cost)) {
return <><Typography color={"error"}>Invalid put for Bulk Purchase amount</Typography></>; return (
<>
<Typography color={"error"}>Invalid put for Bulk Purchase amount</Typography>
</>
);
} else { } else {
return ( return (
<><Typography> <>
Purchasing {numeralWrapper.format(parsedAmt, "0,0.00")} of {props.mat.name} will cost{" "} <Typography>
{numeralWrapper.formatMoney(cost)}</Typography> Purchasing {numeralWrapper.format(parsedAmt, "0,0.00")} of {props.mat.name} will cost{" "}
</> {numeralWrapper.formatMoney(cost)}
</Typography>
</>
); );
} }
} }
@ -62,8 +72,8 @@ function BulkPurchase(props: IBPProps): React.ReactElement {
dialogBoxCreate("Invalid input amount"); dialogBoxCreate("Invalid input amount");
} else { } else {
const cost = amount * props.mat.bCost; const cost = amount * props.mat.bCost;
if (corp.funds.gt(cost)) { if (corp.funds >= cost) {
corp.funds = corp.funds.minus(cost); corp.funds = corp.funds - cost;
props.mat.qty += amount; props.mat.qty += amount;
} else { } else {
dialogBoxCreate(`You cannot afford this purchase.`); dialogBoxCreate(`You cannot afford this purchase.`);

View File

@ -23,7 +23,7 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
const [cost, setCost] = useState(0); const [cost, setCost] = useState(0);
const totalCost = cost * props.office.employees.length; const totalCost = cost * props.office.employees.length;
const canParty = corp.funds.gte(totalCost); const canParty = corp.funds >= totalCost;
function changeCost(event: React.ChangeEvent<HTMLInputElement>): void { function changeCost(event: React.ChangeEvent<HTMLInputElement>): void {
let x = parseFloat(event.target.value); let x = parseFloat(event.target.value);
if (isNaN(x)) x = 0; if (isNaN(x)) x = 0;

View File

@ -22,7 +22,7 @@ export function UnlockUpgrade(props: IProps): React.ReactElement {
const data = props.upgradeData; const data = props.upgradeData;
const tooltip = data[3]; const tooltip = data[3];
function onClick(): void { function onClick(): void {
if (corp.funds.lt(data[1])) return; if (corp.funds < data[1]) return;
try { try {
UU(corp, props.upgradeData); UU(corp, props.upgradeData);
} catch (err) { } catch (err) {
@ -34,7 +34,7 @@ export function UnlockUpgrade(props: IProps): React.ReactElement {
return ( return (
<Grid item xs={4}> <Grid item xs={4}>
<Box display="flex" alignItems="center" flexDirection="row-reverse"> <Box display="flex" alignItems="center" flexDirection="row-reverse">
<Button disabled={corp.funds.lt(data[1])} sx={{ mx: 1 }} onClick={onClick}> <Button disabled={corp.funds < data[1]} sx={{ mx: 1 }} onClick={onClick}>
<MoneyCost money={data[1]} corp={corp} /> <MoneyCost money={data[1]} corp={corp} />
</Button> </Button>
<Tooltip title={tooltip}> <Tooltip title={tooltip}>

View File

@ -23,7 +23,7 @@ interface IUpgradeButton {
function UpgradeSizeButton(props: IUpgradeButton): React.ReactElement { function UpgradeSizeButton(props: IUpgradeButton): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
function upgradeSize(cost: number, size: number): void { function upgradeSize(cost: number, size: number): void {
if (corp.funds.lt(cost)) { if (corp.funds < cost) {
return; return;
} }
@ -34,7 +34,7 @@ function UpgradeSizeButton(props: IUpgradeButton): React.ReactElement {
return ( return (
<Tooltip title={numeralWrapper.formatMoney(props.cost)}> <Tooltip title={numeralWrapper.formatMoney(props.cost)}>
<span> <span>
<Button disabled={corp.funds.lt(props.cost)} onClick={() => upgradeSize(props.cost, props.size)}> <Button disabled={corp.funds < props.cost} onClick={() => upgradeSize(props.cost, props.size)}>
+{props.size} +{props.size}
</Button> </Button>
</span> </span>
@ -63,7 +63,7 @@ export function UpgradeOfficeSizeModal(props: IProps): React.ReactElement {
const upgradeCost15 = CorporationConstants.OfficeInitialCost * mult; const upgradeCost15 = CorporationConstants.OfficeInitialCost * mult;
//Calculate max upgrade size and cost //Calculate max upgrade size and cost
const maxMult = corp.funds.dividedBy(CorporationConstants.OfficeInitialCost).toNumber(); const maxMult = corp.funds / CorporationConstants.OfficeInitialCost;
let maxNum = 1; let maxNum = 1;
mult = Math.pow(costMultiplier, initialPriceMult); mult = Math.pow(costMultiplier, initialPriceMult);
while (maxNum < 50) { while (maxNum < 50) {

View File

@ -54,7 +54,7 @@ export function buyDarkwebItem(itemName: string): void {
} }
// return if the player doesn't have enough money // return if the player doesn't have enough money
if (Player.money.lt(item.price)) { if (Player.money < item.price) {
Terminal.error("Not enough money to purchase " + item.program); Terminal.error("Not enough money to purchase " + item.program);
return; return;
} }

View File

@ -19,13 +19,13 @@ interface IProps {
export function Corporation(props: IProps): React.ReactElement { export function Corporation(props: IProps): React.ReactElement {
function addTonsCorporationFunds(): void { function addTonsCorporationFunds(): void {
if (props.player.corporation) { if (props.player.corporation) {
props.player.corporation.funds = props.player.corporation.funds.plus(1e99); props.player.corporation.funds = props.player.corporation.funds + 1e99;
} }
} }
function resetCorporationFunds(): void { function resetCorporationFunds(): void {
if (props.player.corporation) { if (props.player.corporation) {
props.player.corporation.funds = props.player.corporation.funds.minus(props.player.corporation.funds); props.player.corporation.funds = props.player.corporation.funds - props.player.corporation.funds;
} }
} }

View File

@ -87,7 +87,7 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
} else { } else {
dialogBoxCreate(txt); dialogBoxCreate(txt);
} }
} else if (aug.baseCost !== 0 && Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) { } else if (aug.baseCost !== 0 && Player.money < aug.baseCost * factionInfo.augmentationPriceMult) {
const txt = "You don't have enough money to purchase " + aug.name; const txt = "You don't have enough money to purchase " + aug.name;
if (sing) { if (sing) {
return txt; return txt;
@ -99,7 +99,7 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
return txt; return txt;
} }
dialogBoxCreate(txt); dialogBoxCreate(txt);
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) { } else if (aug.baseCost === 0 || Player.money >= aug.baseCost * factionInfo.augmentationPriceMult) {
const queuedAugmentation = new PlayerOwnedAugmentation(aug.name); const queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
if (aug.name == AugmentationNames.NeuroFluxGovernor) { if (aug.name == AugmentationNames.NeuroFluxGovernor) {
queuedAugmentation.level = getNextNeurofluxLevel(); queuedAugmentation.level = getNextNeurofluxLevel();

View File

@ -93,8 +93,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
const repCost = aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult; const repCost = aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult;
const hasReq = props.faction.playerReputation >= repCost; const hasReq = props.faction.playerReputation >= repCost;
const hasRep = hasAugmentationPrereqs(aug); const hasRep = hasAugmentationPrereqs(aug);
const hasCost = const hasCost = aug.baseCost !== 0 && player.money > aug.baseCost * props.faction.getInfo().augmentationPriceMult;
aug.baseCost !== 0 && player.money.gt(aug.baseCost * props.faction.getInfo().augmentationPriceMult);
return hasCost && hasReq && hasRep; return hasCost && hasReq && hasRep;
} }
const buy = augs.filter(canBuy).sort((augName1, augName2) => { const buy = augs.filter(canBuy).sort((augName1, augName2) => {

View File

@ -37,7 +37,7 @@ export function DonateOption(props: IProps): React.ReactElement {
function canDonate(): boolean { function canDonate(): boolean {
if (donateAmt === null) return false; if (donateAmt === null) return false;
if (isNaN(donateAmt) || donateAmt <= 0) return false; if (isNaN(donateAmt) || donateAmt <= 0) return false;
if (props.p.money.lt(donateAmt)) return false; if (props.p.money < donateAmt) return false;
return true; return true;
} }
@ -66,7 +66,7 @@ export function DonateOption(props: IProps): React.ReactElement {
function Status(): React.ReactElement { function Status(): React.ReactElement {
if (donateAmt === null) return <></>; if (donateAmt === null) return <></>;
if (!canDonate()) { if (!canDonate()) {
if (props.p.money.lt(donateAmt)) return <Typography>Insufficient funds</Typography>; if (props.p.money < donateAmt) return <Typography>Insufficient funds</Typography>;
return <Typography>Invalid donate amount entered!</Typography>; return <Typography>Invalid donate amount entered!</Typography>;
} }
return ( return (

View File

@ -88,7 +88,7 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement {
const repCost = aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult; const repCost = aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult;
const hasReq = hasAugmentationPrereqs(aug); const hasReq = hasAugmentationPrereqs(aug);
const hasRep = props.faction.playerReputation >= repCost; const hasRep = props.faction.playerReputation >= repCost;
const hasCost = aug.baseCost === 0 || props.p.money.gt(aug.baseCost * props.faction.getInfo().augmentationPriceMult); const hasCost = aug.baseCost === 0 || props.p.money > aug.baseCost * props.faction.getInfo().augmentationPriceMult;
// Determine UI properties // Determine UI properties
const color: "error" | "primary" = !hasReq || !hasRep || !hasCost ? "error" : "primary"; const color: "error" | "primary" = !hasReq || !hasRep || !hasCost ? "error" : "primary";

View File

@ -316,7 +316,7 @@ export class GangMember {
// Prevent purchasing of already-owned upgrades // Prevent purchasing of already-owned upgrades
if (this.augmentations.includes(upg.name) || this.upgrades.includes(upg.name)) return false; if (this.augmentations.includes(upg.name) || this.upgrades.includes(upg.name)) return false;
if (player.money.lt(gang.getUpgradeCost(upg))) return false; if (player.money < gang.getUpgradeCost(upg)) return false;
player.loseMoney(gang.getUpgradeCost(upg), "gang"); player.loseMoney(gang.getUpgradeCost(upg), "gang");
if (upg.type === "g") { if (upg.type === "g") {
this.augmentations.push(upg.name); this.augmentations.push(upg.name);

View File

@ -28,7 +28,7 @@ function NextReveal(props: INextRevealProps): React.ReactElement {
const upgrades = Object.keys(GangMemberUpgrades) const upgrades = Object.keys(GangMemberUpgrades)
.filter((upgName: string) => { .filter((upgName: string) => {
const upg = GangMemberUpgrades[upgName]; const upg = GangMemberUpgrades[upgName];
if (player.money.gt(gang.getUpgradeCost(upg))) return false; if (player.money > gang.getUpgradeCost(upg)) return false;
if (upg.type !== props.type) return false; if (upg.type !== props.type) return false;
if (props.upgrades.includes(upgName)) return false; if (props.upgrades.includes(upgName)) return false;
return true; return true;
@ -96,7 +96,7 @@ function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement {
return Object.keys(GangMemberUpgrades) return Object.keys(GangMemberUpgrades)
.filter((upgName: string) => { .filter((upgName: string) => {
const upg = GangMemberUpgrades[upgName]; const upg = GangMemberUpgrades[upgName];
if (player.money.lt(gang.getUpgradeCost(upg))) return false; if (player.money < gang.getUpgradeCost(upg)) return false;
if (upg.type !== type) return false; if (upg.type !== type) return false;
if (list.includes(upgName)) return false; if (list.includes(upgName)) return false;
return true; return true;

View File

@ -98,14 +98,14 @@ export function getMaxNumberLevelUpgrades(
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`); throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
} }
if (player.money.lt(nodeObj.calculateLevelUpgradeCost(1, player.hacknet_node_level_cost_mult))) { if (player.money < nodeObj.calculateLevelUpgradeCost(1, player.hacknet_node_level_cost_mult)) {
return 0; return 0;
} }
let min = 1; let min = 1;
let max = maxLevel - 1; let max = maxLevel - 1;
const levelsToMax = maxLevel - nodeObj.level; const levelsToMax = maxLevel - nodeObj.level;
if (player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, player.hacknet_node_level_cost_mult))) { if (player.money > nodeObj.calculateLevelUpgradeCost(levelsToMax, player.hacknet_node_level_cost_mult)) {
return levelsToMax; return levelsToMax;
} }
@ -113,13 +113,13 @@ export function getMaxNumberLevelUpgrades(
const curr = ((min + max) / 2) | 0; const curr = ((min + max) / 2) | 0;
if ( if (
curr !== maxLevel && curr !== maxLevel &&
player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult)) && player.money > nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult) &&
player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, player.hacknet_node_level_cost_mult)) player.money < nodeObj.calculateLevelUpgradeCost(curr + 1, player.hacknet_node_level_cost_mult)
) { ) {
return Math.min(levelsToMax, curr); return Math.min(levelsToMax, curr);
} else if (player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult))) { } else if (player.money < nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult)) {
max = curr - 1; max = curr - 1;
} else if (player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult))) { } else if (player.money > nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult)) {
min = curr + 1; min = curr + 1;
} else { } else {
return Math.min(levelsToMax, curr); return Math.min(levelsToMax, curr);
@ -138,7 +138,7 @@ export function getMaxNumberRamUpgrades(
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`); throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
} }
if (player.money.lt(nodeObj.calculateRamUpgradeCost(1, player.hacknet_node_ram_cost_mult))) { if (player.money < nodeObj.calculateRamUpgradeCost(1, player.hacknet_node_ram_cost_mult)) {
return 0; return 0;
} }
@ -148,13 +148,13 @@ export function getMaxNumberRamUpgrades(
} else { } else {
levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram)); levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram));
} }
if (player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, player.hacknet_node_ram_cost_mult))) { if (player.money > nodeObj.calculateRamUpgradeCost(levelsToMax, player.hacknet_node_ram_cost_mult)) {
return levelsToMax; return levelsToMax;
} }
//We'll just loop until we find the max //We'll just loop until we find the max
for (let i = levelsToMax - 1; i >= 0; --i) { for (let i = levelsToMax - 1; i >= 0; --i) {
if (player.money.gt(nodeObj.calculateRamUpgradeCost(i, player.hacknet_node_ram_cost_mult))) { if (player.money > nodeObj.calculateRamUpgradeCost(i, player.hacknet_node_ram_cost_mult)) {
return i; return i;
} }
} }
@ -171,14 +171,14 @@ export function getMaxNumberCoreUpgrades(
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`); throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
} }
if (player.money.lt(nodeObj.calculateCoreUpgradeCost(1, player.hacknet_node_core_cost_mult))) { if (player.money < nodeObj.calculateCoreUpgradeCost(1, player.hacknet_node_core_cost_mult)) {
return 0; return 0;
} }
let min = 1; let min = 1;
let max = maxLevel - 1; let max = maxLevel - 1;
const levelsToMax = maxLevel - nodeObj.cores; const levelsToMax = maxLevel - nodeObj.cores;
if (player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, player.hacknet_node_core_cost_mult))) { if (player.money > nodeObj.calculateCoreUpgradeCost(levelsToMax, player.hacknet_node_core_cost_mult)) {
return levelsToMax; return levelsToMax;
} }
@ -187,13 +187,13 @@ export function getMaxNumberCoreUpgrades(
const curr = ((min + max) / 2) | 0; const curr = ((min + max) / 2) | 0;
if ( if (
curr != maxLevel && curr != maxLevel &&
player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult)) && player.money > nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult) &&
player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, player.hacknet_node_core_cost_mult)) player.money < nodeObj.calculateCoreUpgradeCost(curr + 1, player.hacknet_node_core_cost_mult)
) { ) {
return Math.min(levelsToMax, curr); return Math.min(levelsToMax, curr);
} else if (player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult))) { } else if (player.money < nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult)) {
max = curr - 1; max = curr - 1;
} else if (player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult))) { } else if (player.money > nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult)) {
min = curr + 1; min = curr + 1;
} else { } else {
return Math.min(levelsToMax, curr); return Math.min(levelsToMax, curr);
@ -480,7 +480,7 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
player.hashManager.refundUpgrade(upgName); player.hashManager.refundUpgrade(upgName);
return false; return false;
} }
corp.funds = corp.funds.plus(upg.value); corp.funds = corp.funds + upg.value;
break; break;
} }
case "Reduce Minimum Security": { case "Reduce Minimum Security": {

View File

@ -20,8 +20,6 @@ import { createRandomIp } from "../utils/IPAddress";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
interface IConstructorParams { interface IConstructorParams {
adminRights?: boolean; adminRights?: boolean;
hostname: string; hostname: string;
@ -37,7 +35,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
// Number of cores. Improves hash production // Number of cores. Improves hash production
cores = 1; cores = 1;
// Number of hashes that can be stored by this Hacknet Server // Number of hashes that can be stored by this Hacknet Server
hashCapacity = 0; hashCapacity = 0;
@ -53,6 +51,9 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
// Total number of hashes earned by this server // Total number of hashes earned by this server
totalHashesGenerated = 0; totalHashesGenerated = 0;
// Flag indicating wehther this is a purchased server
purchasedByPlayer = true;
constructor(params: IConstructorParams = { hostname: "", ip: createRandomIp() }) { constructor(params: IConstructorParams = { hostname: "", ip: createRandomIp() }) {
super(params); super(params);
@ -95,7 +96,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
upgradeCore(levels: number, prodMult: number): void { upgradeCore(levels: number, prodMult: number): void {
this.cores = Math.min(HacknetServerConstants.MaxCores, Math.round(this.cores + levels)); this.cores = Math.min(HacknetServerConstants.MaxCores, Math.round(this.cores + levels));
this.updateHashRate(prodMult); this.updateHashRate(prodMult);
this.cpuCores=this.cores; this.cpuCores = this.cores;
} }
upgradeLevel(levels: number, prodMult: number): void { upgradeLevel(levels: number, prodMult: number): void {

View File

@ -155,7 +155,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
<Money money={upgradeCacheCost} player={props.player} /> <Money money={upgradeCacheCost} player={props.player} />
</> </>
); );
if (props.player.money.lt(upgradeCacheCost)) { if (props.player.money < upgradeCacheCost) {
} else { } else {
} }
} }

View File

@ -33,7 +33,7 @@ export function PlayerInfo(props: IProps): React.ReactElement {
<> <>
<Typography> <Typography>
Money: Money:
<Money money={props.player.money.toNumber()} /> <Money money={props.player.money} />
</Typography> </Typography>
{hasServers && ( {hasServers && (

View File

@ -2,18 +2,11 @@ import { CONSTANTS } from "../Constants";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
export function getHospitalizationCost(p: IPlayer): number { export function getHospitalizationCost(p: IPlayer): number {
let money; if (p.money < 0) {
if (typeof p.money === "number") {
money = p.money;
} else {
money = p.money.toNumber();
}
if (money < 0) {
return 0; return 0;
} }
return Math.min(money * 0.1, (p.max_hp - p.hp) * CONSTANTS.HospitalCostPerHp); return Math.min(p.money * 0.1, (p.max_hp - p.hp) * CONSTANTS.HospitalCostPerHp);
} }
export function calculateHospitalizationCost(p: IPlayer, damage: number): number { export function calculateHospitalizationCost(p: IPlayer, damage: number): number {

View File

@ -1294,9 +1294,9 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Return player's money // Return player's money
workerScript.log( workerScript.log(
"getServerMoneyAvailable", "getServerMoneyAvailable",
`returned player's money: ${numeralWrapper.formatMoney(Player.money.toNumber())}`, `returned player's money: ${numeralWrapper.formatMoney(Player.money)}`,
); );
return Player.money.toNumber(); return Player.money;
} }
workerScript.log( workerScript.log(
"getServerMoneyAvailable", "getServerMoneyAvailable",
@ -1522,7 +1522,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return ""; return "";
} }
if (Player.money.lt(cost)) { if (Player.money < cost) {
workerScript.log( workerScript.log(
"purchaseServer", "purchaseServer",
`Not enough money to purchase server. Need ${numeralWrapper.formatMoney(cost)}`, `Not enough money to purchase server. Need ${numeralWrapper.formatMoney(cost)}`,
@ -2126,7 +2126,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
company_rep_mult: Player.company_rep_mult, company_rep_mult: Player.company_rep_mult,
faction_rep_mult: Player.faction_rep_mult, faction_rep_mult: Player.faction_rep_mult,
numPeopleKilled: Player.numPeopleKilled, numPeopleKilled: Player.numPeopleKilled,
money: Player.money.toNumber(), money: Player.money,
city: Player.city, city: Player.city,
location: Player.location, location: Player.location,
companyName: Player.companyName, companyName: Player.companyName,

View File

@ -450,7 +450,7 @@ export function NetscriptSingularity(
case CityName.NewTokyo: case CityName.NewTokyo:
case CityName.Ishima: case CityName.Ishima:
case CityName.Volhaven: case CityName.Volhaven:
if (player.money.lt(CONSTANTS.TravelCost)) { if (player.money < CONSTANTS.TravelCost) {
throw helper.makeRuntimeErrorMsg("travelToCity", "Not enough money to travel."); throw helper.makeRuntimeErrorMsg("travelToCity", "Not enough money to travel.");
} }
player.loseMoney(CONSTANTS.TravelCost, "other"); player.loseMoney(CONSTANTS.TravelCost, "other");
@ -473,7 +473,7 @@ export function NetscriptSingularity(
return false; return false;
} }
if (player.money.lt(CONSTANTS.TorRouterCost)) { if (player.money < CONSTANTS.TorRouterCost) {
workerScript.log("purchaseTor", "You cannot afford to purchase a Tor router."); workerScript.log("purchaseTor", "You cannot afford to purchase a Tor router.");
return false; return false;
} }
@ -520,7 +520,7 @@ export function NetscriptSingularity(
return false; return false;
} }
if (player.money.lt(item.price)) { if (player.money < item.price) {
workerScript.log( workerScript.log(
"purchaseProgram", "purchaseProgram",
`Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`, `Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`,
@ -724,7 +724,7 @@ export function NetscriptSingularity(
} }
const cost = player.getUpgradeHomeCoresCost(); const cost = player.getUpgradeHomeCoresCost();
if (player.money.lt(cost)) { if (player.money < cost) {
workerScript.log("upgradeHomeCores", `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`); workerScript.log("upgradeHomeCores", `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`);
return false; return false;
} }
@ -757,7 +757,7 @@ export function NetscriptSingularity(
} }
const cost = player.getUpgradeHomeRamCost(); const cost = player.getUpgradeHomeRamCost();
if (player.money.lt(cost)) { if (player.money < cost) {
workerScript.log("upgradeHomeRam", `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`); workerScript.log("upgradeHomeRam", `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`);
return false; return false;
} }
@ -1107,7 +1107,7 @@ export function NetscriptSingularity(
workerScript.log("donateToFaction", `Invalid donation amount: '${amt}'.`); workerScript.log("donateToFaction", `Invalid donation amount: '${amt}'.`);
return false; return false;
} }
if (player.money.lt(amt)) { if (player.money < amt) {
workerScript.log( workerScript.log(
"donateToFaction", "donateToFaction",
`You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${name}'`, `You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${name}'`,

View File

@ -319,7 +319,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return true; return true;
} }
if (player.money.lt(getStockMarket4SDataCost())) { if (player.money < getStockMarket4SDataCost()) {
workerScript.log("purchase4SMarketData", "Not enough money to purchase 4S Market Data."); workerScript.log("purchase4SMarketData", "Not enough money to purchase 4S Market Data.");
return false; return false;
} }
@ -338,7 +338,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return true; return true;
} }
if (player.money.lt(getStockMarket4STixApiCost())) { if (player.money < getStockMarket4STixApiCost()) {
workerScript.log("purchase4SMarketDataTixApi", "Not enough money to purchase 4S Market Data TIX API"); workerScript.log("purchase4SMarketDataTixApi", "Not enough money to purchase 4S Market Data TIX API");
return false; return false;
} }

View File

@ -56,7 +56,7 @@ export interface IPlayer {
numPeopleKilled: number; numPeopleKilled: number;
location: LocationName; location: LocationName;
max_hp: number; max_hp: number;
readonly money: any; readonly money: number;
moneySourceA: MoneySourceTracker; moneySourceA: MoneySourceTracker;
moneySourceB: MoneySourceTracker; moneySourceB: MoneySourceTracker;
playtimeSinceLastAug: number; playtimeSinceLastAug: number;

View File

@ -35,8 +35,6 @@ import { CityName } from "../../Locations/data/CityNames";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../../utils/JSONReviver"; import { Reviver, Generic_toJSON, Generic_fromJSON } from "../../utils/JSONReviver";
import Decimal from "decimal.js";
export class PlayerObject implements IPlayer { export class PlayerObject implements IPlayer {
// Class members // Class members
augmentations: IPlayerOwnedAugmentation[]; augmentations: IPlayerOwnedAugmentation[];
@ -63,7 +61,7 @@ export class PlayerObject implements IPlayer {
numPeopleKilled: number; numPeopleKilled: number;
location: LocationName; location: LocationName;
max_hp: number; max_hp: number;
money: any; money: number;
moneySourceA: MoneySourceTracker; moneySourceA: MoneySourceTracker;
moneySourceB: MoneySourceTracker; moneySourceB: MoneySourceTracker;
playtimeSinceLastAug: number; playtimeSinceLastAug: number;
@ -336,7 +334,7 @@ export class PlayerObject implements IPlayer {
this.faction_rep_mult = 1; this.faction_rep_mult = 1;
//Money //Money
this.money = new Decimal(1000); this.money = 1000;
//Location information //Location information
this.city = CityName.Sector12; this.city = CityName.Sector12;

View File

@ -36,7 +36,7 @@ import {
import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers"; import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers";
import { Server } from "../../Server/Server"; import { Server } from "../../Server/Server";
import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers"; import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers";
import { Settings } from "../../Settings/Settings";
import { SpecialServers } from "../../Server/data/SpecialServers"; import { SpecialServers } from "../../Server/data/SpecialServers";
import { applySourceFile } from "../../SourceFile/applySourceFile"; import { applySourceFile } from "../../SourceFile/applySourceFile";
import { applyExploit } from "../../Exploits/applyExploits"; import { applyExploit } from "../../Exploits/applyExploits";
@ -47,8 +47,6 @@ import { getHospitalizationCost } from "../../Hospital/Hospital";
import { WorkerScript } from "../../Netscript/WorkerScript"; import { WorkerScript } from "../../Netscript/WorkerScript";
import { HacknetServer } from "../../Hacknet/HacknetServer"; import { HacknetServer } from "../../Hacknet/HacknetServer";
import Decimal from "decimal.js";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { IRouter } from "../../ui/Router"; import { IRouter } from "../../ui/Router";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
@ -102,7 +100,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.agility_exp = 0; this.agility_exp = 0;
this.charisma_exp = 0; this.charisma_exp = 0;
this.money = new Decimal(1000); this.money = 1000;
this.city = CityName.Sector12; this.city = CityName.Sector12;
this.location = LocationName.TravelAgency; this.location = LocationName.TravelAgency;
@ -325,7 +323,7 @@ export function setMoney(this: PlayerObject, money: number): void {
console.error("NaN passed into Player.setMoney()"); console.error("NaN passed into Player.setMoney()");
return; return;
} }
this.money = new Decimal(money); this.money = money;
} }
export function gainMoney(this: PlayerObject, money: number, source: string): void { export function gainMoney(this: PlayerObject, money: number, source: string): void {
@ -333,7 +331,8 @@ export function gainMoney(this: PlayerObject, money: number, source: string): vo
console.error("NaN passed into Player.gainMoney()"); console.error("NaN passed into Player.gainMoney()");
return; return;
} }
this.money = this.money.plus(money);
this.money = this.money + money;
this.recordMoneySource(money, source); this.recordMoneySource(money, source);
} }
@ -342,8 +341,8 @@ export function loseMoney(this: PlayerObject, money: number, source: string): vo
console.error("NaN passed into Player.loseMoney()"); console.error("NaN passed into Player.loseMoney()");
return; return;
} }
if (this.money.eq(Infinity) && money === Infinity) return; if (this.money === Infinity && money === Infinity) return;
this.money = this.money.minus(money); this.money = this.money - money;
this.recordMoneySource(-1 * money, source); this.recordMoneySource(-1 * money, source);
} }
@ -352,7 +351,7 @@ export function canAfford(this: IPlayer, cost: number): boolean {
console.error(`NaN passed into Player.canAfford()`); console.error(`NaN passed into Player.canAfford()`);
return false; return false;
} }
return this.money.gte(cost); return this.money >= cost;
} }
export function recordMoneySource(this: PlayerObject, amt: number, source: string): void { export function recordMoneySource(this: PlayerObject, amt: number, source: string): void {
@ -535,7 +534,6 @@ export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
const agiExpGain = focusBonus * this.workAgiExpGainRate * numCycles; const agiExpGain = focusBonus * this.workAgiExpGainRate * numCycles;
const chaExpGain = focusBonus * this.workChaExpGainRate * numCycles; const chaExpGain = focusBonus * this.workChaExpGainRate * numCycles;
const moneyGain = (this.workMoneyGainRate - this.workMoneyLossRate) * numCycles; const moneyGain = (this.workMoneyGainRate - this.workMoneyLossRate) * numCycles;
this.gainHackingExp(hackExpGain); this.gainHackingExp(hackExpGain);
this.gainStrengthExp(strExpGain); this.gainStrengthExp(strExpGain);
this.gainDefenseExp(defExpGain); this.gainDefenseExp(defExpGain);
@ -2070,7 +2068,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!illuminatiFac.isMember && !illuminatiFac.isMember &&
!illuminatiFac.alreadyInvited && !illuminatiFac.alreadyInvited &&
numAugmentations >= 30 && numAugmentations >= 30 &&
this.money.gte(150000000000) && this.money >= 150000000000 &&
this.hacking >= 1500 && this.hacking >= 1500 &&
this.strength >= 1200 && this.strength >= 1200 &&
this.defense >= 1200 && this.defense >= 1200 &&
@ -2087,7 +2085,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!daedalusFac.isMember && !daedalusFac.isMember &&
!daedalusFac.alreadyInvited && !daedalusFac.alreadyInvited &&
numAugmentations >= Math.round(30 * BitNodeMultipliers.DaedalusAugsRequirement) && numAugmentations >= Math.round(30 * BitNodeMultipliers.DaedalusAugsRequirement) &&
this.money.gte(100000000000) && this.money >= 100000000000 &&
(this.hacking >= 2500 || (this.hacking >= 2500 ||
(this.strength >= 1500 && this.defense >= 1500 && this.dexterity >= 1500 && this.agility >= 1500)) (this.strength >= 1500 && this.defense >= 1500 && this.dexterity >= 1500 && this.agility >= 1500))
) { ) {
@ -2101,7 +2099,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!covenantFac.isMember && !covenantFac.isMember &&
!covenantFac.alreadyInvited && !covenantFac.alreadyInvited &&
numAugmentations >= 20 && numAugmentations >= 20 &&
this.money.gte(75000000000) && this.money >= 75000000000 &&
this.hacking >= 850 && this.hacking >= 850 &&
this.strength >= 850 && this.strength >= 850 &&
this.defense >= 850 && this.defense >= 850 &&
@ -2280,7 +2278,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!chongqingFac.isBanned && !chongqingFac.isBanned &&
!chongqingFac.isMember && !chongqingFac.isMember &&
!chongqingFac.alreadyInvited && !chongqingFac.alreadyInvited &&
this.money.gte(20000000) && this.money >= 20000000 &&
this.city == CityName.Chongqing this.city == CityName.Chongqing
) { ) {
invitedFactions.push(chongqingFac); invitedFactions.push(chongqingFac);
@ -2292,7 +2290,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!sector12Fac.isBanned && !sector12Fac.isBanned &&
!sector12Fac.isMember && !sector12Fac.isMember &&
!sector12Fac.alreadyInvited && !sector12Fac.alreadyInvited &&
this.money.gte(15000000) && this.money >= 15000000 &&
this.city == CityName.Sector12 this.city == CityName.Sector12
) { ) {
invitedFactions.push(sector12Fac); invitedFactions.push(sector12Fac);
@ -2304,7 +2302,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!newtokyoFac.isBanned && !newtokyoFac.isBanned &&
!newtokyoFac.isMember && !newtokyoFac.isMember &&
!newtokyoFac.alreadyInvited && !newtokyoFac.alreadyInvited &&
this.money.gte(20000000) && this.money >= 20000000 &&
this.city == CityName.NewTokyo this.city == CityName.NewTokyo
) { ) {
invitedFactions.push(newtokyoFac); invitedFactions.push(newtokyoFac);
@ -2316,7 +2314,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!aevumFac.isBanned && !aevumFac.isBanned &&
!aevumFac.isMember && !aevumFac.isMember &&
!aevumFac.alreadyInvited && !aevumFac.alreadyInvited &&
this.money.gte(40000000) && this.money >= 40000000 &&
this.city == CityName.Aevum this.city == CityName.Aevum
) { ) {
invitedFactions.push(aevumFac); invitedFactions.push(aevumFac);
@ -2328,7 +2326,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!ishimaFac.isBanned && !ishimaFac.isBanned &&
!ishimaFac.isMember && !ishimaFac.isMember &&
!ishimaFac.alreadyInvited && !ishimaFac.alreadyInvited &&
this.money.gte(30000000) && this.money >= 30000000 &&
this.city == CityName.Ishima this.city == CityName.Ishima
) { ) {
invitedFactions.push(ishimaFac); invitedFactions.push(ishimaFac);
@ -2340,7 +2338,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!volhavenFac.isBanned && !volhavenFac.isBanned &&
!volhavenFac.isMember && !volhavenFac.isMember &&
!volhavenFac.alreadyInvited && !volhavenFac.alreadyInvited &&
this.money.gte(50000000) && this.money >= 50000000 &&
this.city == CityName.Volhaven this.city == CityName.Volhaven
) { ) {
invitedFactions.push(volhavenFac); invitedFactions.push(volhavenFac);
@ -2397,7 +2395,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
this.dexterity >= 200 && this.dexterity >= 200 &&
this.agility >= 200 && this.agility >= 200 &&
(this.city == CityName.Aevum || this.city == CityName.Sector12) && (this.city == CityName.Aevum || this.city == CityName.Sector12) &&
this.money.gte(10000000) && this.money >= 10000000 &&
this.karma <= -90 && this.karma <= -90 &&
!allCompanies.includes(LocationName.Sector12CIA) && !allCompanies.includes(LocationName.Sector12CIA) &&
!allCompanies.includes(LocationName.Sector12NSA) !allCompanies.includes(LocationName.Sector12NSA)
@ -2414,7 +2412,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
(allPositions.includes("Chief Technology Officer") || (allPositions.includes("Chief Technology Officer") ||
allPositions.includes("Chief Financial Officer") || allPositions.includes("Chief Financial Officer") ||
allPositions.includes("Chief Executive Officer")) && allPositions.includes("Chief Executive Officer")) &&
this.money.gte(15000000) && this.money >= 15000000 &&
this.karma <= -22 this.karma <= -22
) { ) {
invitedFactions.push(silhouetteFac); invitedFactions.push(silhouetteFac);
@ -2447,7 +2445,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
this.dexterity >= 30 && this.dexterity >= 30 &&
this.agility >= 30 && this.agility >= 30 &&
this.karma <= -9 && this.karma <= -9 &&
this.money.gte(1000000) this.money >= 1000000
) { ) {
invitedFactions.push(slumsnakesFac); invitedFactions.push(slumsnakesFac);
} }
@ -2490,7 +2488,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
!tiandihuiFac.isBanned && !tiandihuiFac.isBanned &&
!tiandihuiFac.isMember && !tiandihuiFac.isMember &&
!tiandihuiFac.alreadyInvited && !tiandihuiFac.alreadyInvited &&
this.money.gte(1000000) && this.money >= 1000000 &&
this.hacking >= 50 && this.hacking >= 50 &&
(this.city == CityName.Chongqing || this.city == CityName.NewTokyo || this.city == CityName.Ishima) (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || this.city == CityName.Ishima)
) { ) {

View File

@ -18,7 +18,7 @@ export function hasTorRouter(this: IPlayer): boolean {
export function getCurrentServer(this: IPlayer): BaseServer { export function getCurrentServer(this: IPlayer): BaseServer {
const server = GetServer(this.currentServer); const server = GetServer(this.currentServer);
if (server === null) throw new Error("somehow connected to a server that does not exist."); if (server === null) throw new Error(`somehow connected to a server that does not exist. ${this.currentServer}`);
return server; return server;
} }

View File

@ -64,7 +64,7 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
return ( return (
<TableRow key={aug.name}> <TableRow key={aug.name}>
<TableCell> <TableCell>
<Button onClick={() => purchaseAugmentation(aug)} disabled={player.money.lt(aug.startingCost)}> <Button onClick={() => purchaseAugmentation(aug)} disabled={player.money < aug.startingCost}>
Buy Buy
</Button> </Button>
</TableCell> </TableCell>

View File

@ -174,9 +174,9 @@ export function SleeveElem(props: IProps): React.ReactElement {
<Grid item xs={3}> <Grid item xs={3}>
<StatsElement sleeve={props.sleeve} /> <StatsElement sleeve={props.sleeve} />
<Button onClick={() => setStatsOpen(true)}>More Stats</Button> <Button onClick={() => setStatsOpen(true)}>More Stats</Button>
<Tooltip title={player.money.lt(CONSTANTS.TravelCost) ? <Typography>Insufficient funds</Typography> : ""}> <Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
<span> <span>
<Button onClick={() => setTravelOpen(true)} disabled={player.money.lt(CONSTANTS.TravelCost)}> <Button onClick={() => setTravelOpen(true)} disabled={player.money < CONSTANTS.TravelCost}>
Travel Travel
</Button> </Button>
</span> </span>

View File

@ -3,29 +3,11 @@ import { PlayerObject } from "./PersonObjects/Player/PlayerObject";
import { sanitizeExploits } from "./Exploits/Exploit"; import { sanitizeExploits } from "./Exploits/Exploit";
import { Reviver } from "./utils/JSONReviver"; import { Reviver } from "./utils/JSONReviver";
import Decimal from "decimal.js";
export let Player = new PlayerObject(); export let Player = new PlayerObject();
export function loadPlayer(saveString: string): void { export function loadPlayer(saveString: string): void {
Player = JSON.parse(saveString, Reviver); Player = JSON.parse(saveString, Reviver);
Player.money = parseFloat(Player.money as any);
// Parse Decimal.js objects
Player.money = new Decimal(Player.money);
if (Player.corporation instanceof Corporation) {
Player.corporation.funds = new Decimal(Player.corporation.funds);
Player.corporation.revenue = new Decimal(Player.corporation.revenue);
Player.corporation.expenses = new Decimal(Player.corporation.expenses);
for (let i = 0; i < Player.corporation.divisions.length; ++i) {
const ind = Player.corporation.divisions[i];
ind.lastCycleRevenue = new Decimal(ind.lastCycleRevenue);
ind.lastCycleExpenses = new Decimal(ind.lastCycleExpenses);
ind.thisCycleRevenue = new Decimal(ind.thisCycleRevenue);
ind.thisCycleExpenses = new Decimal(ind.thisCycleExpenses);
}
}
Player.exploits = sanitizeExploits(Player.exploits); Player.exploits = sanitizeExploits(Player.exploits);
} }

View File

@ -26,7 +26,6 @@ import { Terminal } from "./Terminal";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
import Decimal from "decimal.js";
import { ProgramsSeen } from "./Programs/ui/ProgramsRoot"; import { ProgramsSeen } from "./Programs/ui/ProgramsRoot";
import { InvitationsSeen } from "./Faction/ui/FactionsRoot"; import { InvitationsSeen } from "./Faction/ui/FactionsRoot";
@ -120,7 +119,7 @@ export function prestigeAugmentation(): void {
// BitNode 8: Ghost of Wall Street // BitNode 8: Ghost of Wall Street
if (Player.bitNodeN === 8) { if (Player.bitNodeN === 8) {
Player.money = new Decimal(BitNode8StartingMoney); Player.money = BitNode8StartingMoney;
} }
if (Player.bitNodeN === 8 || SourceFileFlags[8] > 0) { if (Player.bitNodeN === 8 || SourceFileFlags[8] > 0) {
Player.hasWseAccount = true; Player.hasWseAccount = true;
@ -235,7 +234,7 @@ export function prestigeSourceFile(flume: boolean): void {
// BitNode 8: Ghost of Wall Street // BitNode 8: Ghost of Wall Street
if (Player.bitNodeN === 8) { if (Player.bitNodeN === 8) {
Player.money = new Decimal(BitNode8StartingMoney); Player.money = BitNode8StartingMoney;
} }
if (Player.bitNodeN === 8 || SourceFileFlags[8] > 0) { if (Player.bitNodeN === 8 || SourceFileFlags[8] > 0) {
Player.hasWseAccount = true; Player.hasWseAccount = true;

View File

@ -306,10 +306,10 @@ export const programsMetadata: IProgramCreationParams[] = [
create: null, create: null,
run: (router: IRouter, terminal: ITerminal, player: IPlayer): void => { run: (router: IRouter, terminal: ITerminal, player: IPlayer): void => {
const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement * 30); const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement * 30);
const fulfilled = player.augmentations.length >= numAugReq && player.money.gt(1e11) && player.hacking >= 2500; const fulfilled = player.augmentations.length >= numAugReq && player.money > 1e11 && player.hacking >= 2500;
if (!fulfilled) { if (!fulfilled) {
terminal.print(`Augmentations: ${player.augmentations.length} / ${numAugReq}`); terminal.print(`Augmentations: ${player.augmentations.length} / ${numAugReq}`);
terminal.print(`Money: ${numeralWrapper.formatMoney(player.money.toNumber())} / $100b`); terminal.print(`Money: ${numeralWrapper.formatMoney(player.money)} / $100b`);
terminal.print(`Hacking skill: ${player.hacking} / 2500`); terminal.print(`Hacking skill: ${player.hacking} / 2500`);
return; return;
} }

View File

@ -354,8 +354,7 @@ export function Root(props: IProps): React.ReactElement {
.find((l: any) => l.id === "javascript") .find((l: any) => l.id === "javascript")
.loader(); .loader();
l.language.tokenizer.root.unshift(["ns", { token: "ns" }]); l.language.tokenizer.root.unshift(["ns", { token: "ns" }]);
for (const symbol of symbols) for (const symbol of symbols) l.language.tokenizer.root.unshift([symbol, { token: "netscriptfunction" }]);
l.language.tokenizer.root.unshift(["[^a-zA-Z0-9]" + symbol + "[^a-zA-Z0-9]", { token: "netscriptfunction" }]);
const otherKeywords = ["let", "const", "var", "function"]; const otherKeywords = ["let", "const", "var", "function"];
const otherKeyvars = ["true", "false", "null", "undefined"]; const otherKeyvars = ["true", "false", "null", "undefined"];
otherKeywords.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeywords" }])); otherKeywords.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeywords" }]));

View File

@ -94,6 +94,9 @@ export class BaseServer {
// Text files on this server // Text files on this server
textFiles: TextFile[] = []; textFiles: TextFile[] = [];
// Flag indicating wehther this is a purchased server
purchasedByPlayer = false;
constructor(params: IConstructorParams = { hostname: "", ip: createRandomIp() }) { constructor(params: IConstructorParams = { hostname: "", ip: createRandomIp() }) {
this.ip = params.ip ? params.ip : createRandomIp(); this.ip = params.ip ? params.ip : createRandomIp();

View File

@ -48,9 +48,6 @@ export class Server extends BaseServer {
// How many ports are currently opened on the server // How many ports are currently opened on the server
openPortCount = 0; openPortCount = 0;
// Flag indicating wehther this is a purchased server
purchasedByPlayer = false;
// Hacking level required to hack this server // Hacking level required to hack this server
requiredHackingSkill = 1; requiredHackingSkill = 1;

View File

@ -166,7 +166,7 @@ export const defaultSettings: IDefaultSettings = {
DisableHotkeys: false, DisableHotkeys: false,
DisableTextEffects: false, DisableTextEffects: false,
EnableBashHotkeys: false, EnableBashHotkeys: false,
TimestampsFormat: "YYYY-MM-DD HH:MM:SS", TimestampsFormat: "",
Locale: "en", Locale: "en",
MaxLogCapacity: 50, MaxLogCapacity: 50,
MaxPortCapacity: 50, MaxPortCapacity: 50,

View File

@ -64,7 +64,7 @@ export function buyStock(
if (totalPrice == null) { if (totalPrice == null) {
return false; return false;
} }
if (Player.money.lt(totalPrice)) { if (Player.money < totalPrice) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"buyStock", "buyStock",
@ -241,7 +241,7 @@ export function shortStock(
if (totalPrice == null) { if (totalPrice == null) {
return false; return false;
} }
if (Player.money.lt(totalPrice)) { if (Player.money < totalPrice) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"shortStock", "shortStock",

View File

@ -173,7 +173,7 @@ export function StockTicker(props: IProps): React.ReactElement {
} }
function handleBuyMaxButtonClick(): void { function handleBuyMaxButtonClick(): void {
const playerMoney: number = props.p.money.toNumber(); const playerMoney: number = props.p.money;
const stock = props.stock; const stock = props.stock;
let maxShares = calculateBuyMaxAmount(stock, position, playerMoney); let maxShares = calculateBuyMaxAmount(stock, position, playerMoney);

View File

@ -27,7 +27,11 @@ export function download(
const file = new Blob([server.scripts[i].code], { const file = new Blob([server.scripts[i].code], {
type: "text/plain", type: "text/plain",
}); });
zip.file(server.scripts[i].filename + ".js", file); let name = server.scripts[i].filename;
if (name.startsWith("/")) {
name = name.slice(1);
}
zip.file(name + ".js", file);
} }
} }
if (fn === "*" || fn === "*.txt") { if (fn === "*" || fn === "*.txt") {

View File

@ -1 +0,0 @@
declare module "decimal.js";

View File

@ -251,9 +251,25 @@ const Engine: {
const timeOffline = Engine._lastUpdate - lastUpdate; const timeOffline = Engine._lastUpdate - lastUpdate;
const numCyclesOffline = Math.floor(timeOffline / CONSTANTS._idleSpeed); const numCyclesOffline = Math.floor(timeOffline / CONSTANTS._idleSpeed);
// Generate coding contracts
// let numContracts = 0;
// if (numCyclesOffline < 3000 * 100) {
// // if we have less than 100 rolls, just roll them exactly.
// for (let i = 0; i < numCyclesOffline / 3000; i++) {
// if (Math.random() < 0.25) numContracts++;
// }
// } else {
// // just average it.
// numContracts = (numCyclesOffline / 3000) * 0.25;
// }
// console.log(`${numCyclesOffline} ${numContracts}`);
// for (let i = 0; i < numContracts; i++) {
// generateRandomContract();
// }
let offlineReputation = 0; let offlineReputation = 0;
const offlineHackingIncome = (Player.moneySourceA.hacking / Player.playtimeSinceLastAug) * timeOffline * 0.75; const offlineHackingIncome = (Player.moneySourceA.hacking / Player.playtimeSinceLastAug) * timeOffline * 0.75;
Player.gainMoney(offlineHackingIncome, "hacknet"); Player.gainMoney(offlineHackingIncome, "hacking");
// Process offline progress // Process offline progress
loadAllRunningScripts(); // This also takes care of offline production for those scripts loadAllRunningScripts(); // This also takes care of offline production for those scripts
if (Player.isWorking) { if (Player.isWorking) {

View File

@ -290,7 +290,7 @@ export function CharacterStats(): React.ReactElement {
<Employers /> <Employers />
<Typography> <Typography>
Money: <Money money={player.money.toNumber()} /> Money: <Money money={player.money} />
<IconButton onClick={() => setMoneyOpen(true)}> <IconButton onClick={() => setMoneyOpen(true)}>
<MoreHorizIcon color="info" /> <MoreHorizIcon color="info" />
</IconButton> </IconButton>

View File

@ -176,9 +176,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
<Typography classes={{ root: classes.money }}>Money&nbsp;</Typography> <Typography classes={{ root: classes.money }}>Money&nbsp;</Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.money }}> <Typography classes={{ root: classes.money }}>{numeralWrapper.formatMoney(player.money)}</Typography>
{numeralWrapper.formatMoney(player.money.toNumber())}
</Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-money-hook" classes={{ root: classes.money }}> <Typography id="overview-money-hook" classes={{ root: classes.money }}>

View File

@ -19,6 +19,7 @@ import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem"; import ListItem from "@mui/material/ListItem";
import Link from "@mui/material/Link"; import Link from "@mui/material/Link";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
import TextField from "@mui/material/TextField";
import DownloadIcon from "@mui/icons-material/Download"; import DownloadIcon from "@mui/icons-material/Download";
import UploadIcon from "@mui/icons-material/Upload"; import UploadIcon from "@mui/icons-material/Upload";
@ -30,6 +31,7 @@ import { ThemeEditorModal } from "./ThemeEditorModal";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { save, deleteGame } from "../../db"; import { save, deleteGame } from "../../db";
import { formatTime } from "../../utils/helpers/formatTime";
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
@ -73,7 +75,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
const [disableASCIIArt, setDisableASCIIArt] = useState(Settings.DisableASCIIArt); const [disableASCIIArt, setDisableASCIIArt] = useState(Settings.DisableASCIIArt);
const [disableTextEffects, setDisableTextEffects] = useState(Settings.DisableTextEffects); const [disableTextEffects, setDisableTextEffects] = useState(Settings.DisableTextEffects);
const [enableBashHotkeys, setEnableBashHotkeys] = useState(Settings.EnableBashHotkeys); const [enableBashHotkeys, setEnableBashHotkeys] = useState(Settings.EnableBashHotkeys);
const [enableTimestamps, setEnableTimestamps] = useState(!!Settings.TimestampsFormat); const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
const [saveGameOnFileSave, setSaveGameOnFileSave] = useState(Settings.SaveGameOnFileSave); const [saveGameOnFileSave, setSaveGameOnFileSave] = useState(Settings.SaveGameOnFileSave);
const [locale, setLocale] = useState(Settings.Locale); const [locale, setLocale] = useState(Settings.Locale);
@ -154,9 +156,9 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
setEnableBashHotkeys(event.target.checked); setEnableBashHotkeys(event.target.checked);
Settings.EnableBashHotkeys = event.target.checked; Settings.EnableBashHotkeys = event.target.checked;
} }
function handleEnableTimestampsChange(event: React.ChangeEvent<HTMLInputElement>): void { function handleTimestampFormatChange(event: React.ChangeEvent<HTMLInputElement>): void {
setEnableTimestamps(event.target.checked); setTimestampFormat(event.target.value);
Settings.TimestampsFormat = event.target.checked ? "YYYY-MM-DD HH:MM:SS" : ""; Settings.TimestampsFormat = event.target.value;
} }
function handleSaveGameOnFile(event: React.ChangeEvent<HTMLInputElement>): void { function handleSaveGameOnFile(event: React.ChangeEvent<HTMLInputElement>): void {
setSaveGameOnFileSave(event.target.checked); setSaveGameOnFileSave(event.target.checked);
@ -466,21 +468,28 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
/> />
</ListItem> </ListItem>
<ListItem> <ListItem>
<FormControlLabel <Tooltip
control={<Switch checked={enableTimestamps} onChange={handleEnableTimestampsChange} />} title={
label={ <Typography>
<Tooltip Terminal commands and log entries will be timestamped. See
title={ https://date-fns.org/docs/Getting-Started/
<Typography> </Typography>
Terminal commands and log entries will be timestamped. The timestamp will have the format: M/D
h:m
</Typography>
}
>
<Typography>Enable timestamps</Typography>
</Tooltip>
} }
/> >
<span>
<TextField
InputProps={{
startAdornment: (
<Typography color={formatTime(timestampFormat) === "format error" ? "error" : "success"}>
Timestamp&nbsp;format:&nbsp;
</Typography>
),
}}
value={timestampFormat}
onChange={handleTimestampFormatChange}
/>
</span>
</Tooltip>
</ListItem> </ListItem>
<ListItem> <ListItem>

View File

@ -1,3 +1,10 @@
export function formatTime(format: string): string { import { format } from "date-fns";
return "";
export function formatTime(fmt: string): string {
try {
return format(new Date(), fmt);
} catch (err: any) {
console.error(err);
return "format error";
}
} }

View File

@ -856,7 +856,7 @@ describe("Stock Market Tests", function () {
expect(buyStock(stock, shares, null, suppressDialogOpt)).equal(true); expect(buyStock(stock, shares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShares).equal(shares); expect(stock.playerShares).equal(shares);
expect(stock.playerAvgPx).greaterThan(0); expect(stock.playerAvgPx).greaterThan(0);
expect(Player.money.toNumber()).equal(0); expect(Player.money).equal(0);
}); });
}); });
@ -888,7 +888,7 @@ describe("Stock Market Tests", function () {
expect(sellStock(stock, shares, null, suppressDialogOpt)).equal(true); expect(sellStock(stock, shares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShares).equal(0); expect(stock.playerShares).equal(0);
expect(stock.playerAvgPx).equal(0); expect(stock.playerAvgPx).equal(0);
expect(Player.money.toNumber()).equal(gain); expect(Player.money).equal(gain);
}); });
it("should cap the number of sharse sold to however many the player owns", function () { it("should cap the number of sharse sold to however many the player owns", function () {
@ -902,7 +902,7 @@ describe("Stock Market Tests", function () {
expect(sellStock(stock, attemptedShares, null, suppressDialogOpt)).equal(true); expect(sellStock(stock, attemptedShares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShares).equal(0); expect(stock.playerShares).equal(0);
expect(stock.playerAvgPx).equal(0); expect(stock.playerAvgPx).equal(0);
expect(Player.money.toNumber()).equal(gain); expect(Player.money).equal(gain);
}); });
it("should properly update stock properties for partial transactions", function () { it("should properly update stock properties for partial transactions", function () {
@ -916,7 +916,7 @@ describe("Stock Market Tests", function () {
expect(sellStock(stock, shares, null, suppressDialogOpt)).equal(true); expect(sellStock(stock, shares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShares).equal(shares); expect(stock.playerShares).equal(shares);
expect(stock.playerAvgPx).equal(origPrice); expect(stock.playerAvgPx).equal(origPrice);
expect(Player.money.toNumber()).equal(gain); expect(Player.money).equal(gain);
}); });
}); });
@ -950,7 +950,7 @@ describe("Stock Market Tests", function () {
expect(shortStock(stock, shares, null, suppressDialogOpt)).equal(true); expect(shortStock(stock, shares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShortShares).equal(shares); expect(stock.playerShortShares).equal(shares);
expect(stock.playerAvgShortPx).greaterThan(0); expect(stock.playerAvgShortPx).greaterThan(0);
expect(Player.money.toNumber()).equal(0); expect(Player.money).equal(0);
}); });
}); });
@ -982,7 +982,7 @@ describe("Stock Market Tests", function () {
expect(sellShort(stock, shares, null, suppressDialogOpt)).equal(true); expect(sellShort(stock, shares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShortShares).equal(0); expect(stock.playerShortShares).equal(0);
expect(stock.playerAvgShortPx).equal(0); expect(stock.playerAvgShortPx).equal(0);
expect(Player.money.toNumber()).equal(gain); expect(Player.money).equal(gain);
}); });
it("should cap the number of sharse sold to however many the player owns", function () { it("should cap the number of sharse sold to however many the player owns", function () {
@ -996,7 +996,7 @@ describe("Stock Market Tests", function () {
expect(sellShort(stock, attemptedShares, null, suppressDialogOpt)).equal(true); expect(sellShort(stock, attemptedShares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShortShares).equal(0); expect(stock.playerShortShares).equal(0);
expect(stock.playerAvgShortPx).equal(0); expect(stock.playerAvgShortPx).equal(0);
expect(Player.money.toNumber()).equal(gain); expect(Player.money).equal(gain);
}); });
it("should properly update stock properties for partial transactions", function () { it("should properly update stock properties for partial transactions", function () {
@ -1010,7 +1010,7 @@ describe("Stock Market Tests", function () {
expect(sellShort(stock, shares, null, suppressDialogOpt)).equal(true); expect(sellShort(stock, shares, null, suppressDialogOpt)).equal(true);
expect(stock.playerShortShares).equal(shares); expect(stock.playerShortShares).equal(shares);
expect(stock.playerAvgShortPx).equal(origPrice); expect(stock.playerAvgShortPx).equal(origPrice);
expect(Player.money.toNumber()).equal(gain); expect(Player.money).equal(gain);
}); });
}); });
}); });