CORPORATION: Fix NaN Total Assets caused by bug in bulkPurchase API (#1573)

This commit is contained in:
catloversg 2024-08-15 12:09:41 +07:00 committed by GitHub
parent 1d9e026b6e
commit dbeaef94a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 24 additions and 16 deletions

@ -332,8 +332,10 @@ export function buyMaterial(division: Division, material: Material, amt: number)
if (!isRelevantMaterial(material.name, division)) { if (!isRelevantMaterial(material.name, division)) {
throw new Error(`${material.name} is not a relevant material for industry ${division.type}`); throw new Error(`${material.name} is not a relevant material for industry ${division.type}`);
} }
if (isNaN(amt) || amt < 0) { if (!Number.isFinite(amt) || amt < 0) {
throw new Error(`Invalid amount '${amt}' to buy material '${material.name}'`); throw new Error(
`Invalid amount '${amt}' to buy material '${material.name}'. Must be numeric and greater than or equal to 0`,
);
} }
material.buyAmount = amt; material.buyAmount = amt;
} }
@ -350,22 +352,27 @@ export function bulkPurchase(
} }
const matSize = MaterialInfo[material.name].size; const matSize = MaterialInfo[material.name].size;
const maxAmount = (warehouse.size - warehouse.sizeUsed) / matSize; const maxAmount = (warehouse.size - warehouse.sizeUsed) / matSize;
if (isNaN(amt) || amt < 0) { if (!Number.isFinite(amt) || amt < 0) {
throw new Error(`Invalid input amount`); throw new Error(
`Invalid amount '${amt}' to buy material '${material.name}'. Must be numeric and greater than or equal to 0`,
);
} }
if (amt > maxAmount) { if (amt > maxAmount) {
throw new Error(`You do not have enough warehouse size to fit this purchase`); throw new Error(`You do not have enough warehouse size to fit this purchase`);
} }
// Special case: if "amount" is 0, this is a no-op.
if (amt === 0) {
return;
}
const cost = amt * material.marketPrice; const cost = amt * material.marketPrice;
if (corp.funds >= cost) { if (corp.funds < cost) {
throw new Error(`You cannot afford this purchase.`);
}
corp.loseFunds(cost, "materials"); corp.loseFunds(cost, "materials");
material.averagePrice = material.averagePrice =
(material.averagePrice * material.stored + material.marketPrice * amt) / (material.stored + amt); (material.averagePrice * material.stored + material.marketPrice * amt) / (material.stored + amt);
material.stored += amt; material.stored += amt;
warehouse.sizeUsed = warehouse.sizeUsed + amt * matSize; warehouse.sizeUsed = warehouse.sizeUsed + amt * matSize;
} else {
throw new Error(`You cannot afford this purchase.`);
}
} }
export function sellShares(corporation: Corporation, numShares: number): number { export function sellShares(corporation: Corporation, numShares: number): number {

@ -375,7 +375,7 @@ export class Division {
// buy them // buy them
for (const [matName, [buyAmt]] of getRecordEntries(smartBuy)) { for (const [matName, [buyAmt]] of getRecordEntries(smartBuy)) {
const mat = warehouse.materials[matName]; const mat = warehouse.materials[matName];
if (mat.stored + buyAmt != 0) { if (mat.stored + buyAmt !== 0) {
mat.quality = (mat.quality * mat.stored + 1 * buyAmt) / (mat.stored + buyAmt); mat.quality = (mat.quality * mat.stored + 1 * buyAmt) / (mat.stored + buyAmt);
mat.averagePrice = (mat.averagePrice * mat.stored + mat.marketPrice * buyAmt) / (mat.stored + buyAmt); mat.averagePrice = (mat.averagePrice * mat.stored + mat.marketPrice * buyAmt) / (mat.stored + buyAmt);
} else { } else {

@ -139,8 +139,11 @@ export class Material {
if (isNaN(material.quality)) { if (isNaN(material.quality)) {
material.quality = 1; material.quality = 1;
} }
// averagePrice has not been initialized properly, so if it is 0 (wrong initial value), we set it to marketPrice. /**
if (material.averagePrice === 0) { * averagePrice has not been calculated properly, so if it is an invalid value (Number.isFinite returns false) or 0
* (wrong initial value), we set it to marketPrice.
*/
if (!Number.isFinite(material.averagePrice) || material.averagePrice === 0) {
material.averagePrice = material.marketPrice; material.averagePrice = material.marketPrice;
} }
return material; return material;

@ -336,8 +336,6 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
const cityName = getEnumHelper("CityName").nsGetMember(ctx, _cityName); const cityName = getEnumHelper("CityName").nsGetMember(ctx, _cityName);
const materialName = getEnumHelper("CorpMaterialName").nsGetMember(ctx, _materialName, "materialName"); const materialName = getEnumHelper("CorpMaterialName").nsGetMember(ctx, _materialName, "materialName");
const amt = helpers.number(ctx, "amt", _amt); const amt = helpers.number(ctx, "amt", _amt);
if (amt < 0 || !Number.isFinite(amt))
throw new Error("Invalid value for amount field! Must be numeric and greater than or equal to 0");
const material = getMaterial(divisionName, cityName, materialName); const material = getMaterial(divisionName, cityName, materialName);
buyMaterial(division, material, amt); buyMaterial(division, material, amt);
}, },