mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-29 19:13:49 +01:00
Fixed more bugs with new Corporation UI. Minor rebalancing on Corp UI. Changed the Market TA researches to allow you to automatically set price
This commit is contained in:
parent
a28fe7ab9f
commit
e6c5ff7ab7
@ -10,7 +10,8 @@
|
||||
|
||||
#cmpy-mgmt-container p,
|
||||
#cmpy-mgmt-container a,
|
||||
#cmpy-mgmt-container div {
|
||||
#cmpy-mgmt-container div,
|
||||
#cmpy-mgmt-container br {
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
}
|
||||
|
||||
|
@ -297,9 +297,11 @@ export let CONSTANTS: IMap<any> = {
|
||||
** Significantly changed the effects of the different employee positions. See updated descriptions
|
||||
** Reduced the amount of money you gain from private investors
|
||||
** Training employees is now 3x more effective
|
||||
** Bug Fix: An industry's products are now properly separated between different cities
|
||||
|
||||
* Rebalanced BitNode-3 to make it slightly harder
|
||||
* Bug Fix: Bladeburner's Hyperbolic Regeneration Chamber should no longer instantly refill all stamina
|
||||
* Bug Fix: The cost of purchasing Augmentations for Duplicate Sleeves no longer scales with how many Augs you've purchased for yourself
|
||||
`
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import { CONSTANTS } from "../Constants";
|
||||
import { Factions } from "../Faction/Factions";
|
||||
import { showLiterature } from "../Literature";
|
||||
import { Locations } from "../Locations";
|
||||
import { createCityMap } from "../Locations/Cities";
|
||||
import { Player } from "../Player";
|
||||
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
@ -590,7 +591,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
|
||||
//At the start of the export state, set the imports of everything to 0
|
||||
if (this.state === "EXPORT") {
|
||||
for (var i = 0; i < Cities.length; ++i) {
|
||||
for (let i = 0; i < Cities.length; ++i) {
|
||||
var city = Cities[i], office = this.offices[city];
|
||||
if (!(this.warehouses[city] instanceof Warehouse)) {
|
||||
continue;
|
||||
@ -605,7 +606,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < Cities.length; ++i) {
|
||||
for (let i = 0; i < Cities.length; ++i) {
|
||||
var city = Cities[i], office = this.offices[city];
|
||||
|
||||
if (this.warehouses[city] instanceof Warehouse) {
|
||||
@ -665,18 +666,16 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
prod = maxProd;
|
||||
}
|
||||
prod *= (SecsPerMarketCycle * marketCycles); //Convert production from per second to per market cycle
|
||||
//Calculate net change in warehouse storage making
|
||||
//the produced materials will cost
|
||||
|
||||
// Calculate net change in warehouse storage making the produced materials will cost
|
||||
var totalMatSize = 0;
|
||||
for (var tmp = 0; tmp < this.prodMats.length; ++tmp) {
|
||||
for (let tmp = 0; tmp < this.prodMats.length; ++tmp) {
|
||||
totalMatSize += (MaterialSizes[this.prodMats[tmp]]);
|
||||
}
|
||||
for (var reqMatName in this.reqMats) {
|
||||
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
||||
for (const reqMatName in this.reqMats) {
|
||||
var normQty = this.reqMats[reqMatName];
|
||||
totalMatSize -= (MaterialSizes[reqMatName] * normQty);
|
||||
}
|
||||
}
|
||||
// If not enough space in warehouse, limit the amount of produced materials
|
||||
if (totalMatSize > 0) {
|
||||
var maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / totalMatSize);
|
||||
@ -702,15 +701,13 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
|
||||
// Make our materials if they are producable
|
||||
if (producableFrac > 0 && prod > 0) {
|
||||
for (var reqMatName in this.reqMats) {
|
||||
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
||||
for (const reqMatName in this.reqMats) {
|
||||
var reqMatQtyNeeded = (this.reqMats[reqMatName] * prod * producableFrac);
|
||||
warehouse.materials[reqMatName].qty -= reqMatQtyNeeded;
|
||||
warehouse.materials[reqMatName].prd = 0;
|
||||
warehouse.materials[reqMatName].prd -= reqMatQtyNeeded / (SecsPerMarketCycle * marketCycles);
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < this.prodMats.length; ++j) {
|
||||
for (let j = 0; j < this.prodMats.length; ++j) {
|
||||
warehouse.materials[this.prodMats[j]].qty += (prod * producableFrac);
|
||||
warehouse.materials[this.prodMats[j]].qlt =
|
||||
(office.employeeProd[EmployeePositions.Engineer] / 90 +
|
||||
@ -718,7 +715,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
Math.pow(warehouse.materials["AICores"].qty, this.aiFac) / 10e3);
|
||||
}
|
||||
} else {
|
||||
for (var reqMatName in this.reqMats) {
|
||||
for (const reqMatName in this.reqMats) {
|
||||
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
||||
warehouse.materials[reqMatName].prd = 0;
|
||||
}
|
||||
@ -726,20 +723,18 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
}
|
||||
|
||||
//Per second
|
||||
var fooProd = prod * producableFrac / (SecsPerMarketCycle * marketCycles);
|
||||
for (var fooI = 0; fooI < this.prodMats.length; ++fooI) {
|
||||
const fooProd = prod * producableFrac / (SecsPerMarketCycle * marketCycles);
|
||||
for (let fooI = 0; fooI < this.prodMats.length; ++fooI) {
|
||||
warehouse.materials[this.prodMats[fooI]].prd = fooProd;
|
||||
}
|
||||
} else {
|
||||
//If this doesn't produce any materials, then it only creates
|
||||
//Products. Creating products will consume materials. The
|
||||
//Production of all consumed materials must be set to 0
|
||||
for (var reqMatName in this.reqMats) {
|
||||
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
||||
for (const reqMatName in this.reqMats) {
|
||||
warehouse.materials[reqMatName].prd = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "SALE":
|
||||
@ -751,12 +746,39 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
mat.sll = 0;
|
||||
continue;
|
||||
}
|
||||
var mat = warehouse.materials[matName];
|
||||
|
||||
// Calculate sale cost
|
||||
// Sale multipliers
|
||||
const businessFactor = this.getBusinessFactor(office); //Business employee productivity
|
||||
const advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
|
||||
const marketFactor = this.getMarketFactor(mat); //Competition + demand
|
||||
|
||||
// Determine the cost that the material will be sold at
|
||||
const markupLimit = mat.getMarkupLimit();
|
||||
var sCost;
|
||||
if (mat.marketTa1) {
|
||||
if (mat.marketTa2) {
|
||||
const prod = mat.prd;
|
||||
|
||||
// Reverse engineer the 'maxSell' formula
|
||||
// 1. Set 'maxSell' = prod
|
||||
// 2. Substitute formula for 'markup'
|
||||
// 3. Solve for 'sCost'
|
||||
const numerator = markupLimit;
|
||||
const sqrtNumerator = prod;
|
||||
const sqrtDenominator = ((mat.qlt + .001)
|
||||
* marketFactor
|
||||
* businessFactor
|
||||
* company.getSalesMultiplier()
|
||||
* advertisingFactor
|
||||
* this.getSalesMultiplier());
|
||||
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
|
||||
const optimalPrice = (numerator / denominator) + mat.bCost;
|
||||
|
||||
// We'll store this "Optimal Price" in a property so that we don't have
|
||||
// to re-calculate it for the UI
|
||||
mat.marketTa2Price = optimalPrice;
|
||||
|
||||
sCost = optimalPrice;
|
||||
} else if (mat.marketTa1) {
|
||||
sCost = mat.bCost + markupLimit;
|
||||
} else if (isString(mat.sCost)) {
|
||||
sCost = mat.sCost.replace(/MP/g, mat.bCost);
|
||||
@ -780,9 +802,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
markup = mat.bCost / sCost;
|
||||
}
|
||||
}
|
||||
var businessFactor = this.getBusinessFactor(office); //Business employee productivity
|
||||
var advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
|
||||
var marketFactor = this.getMarketFactor(mat); //Competition + demand
|
||||
|
||||
var maxSell = (mat.qlt + .001)
|
||||
* marketFactor
|
||||
* markup
|
||||
@ -905,8 +925,8 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
//Produce Scientific Research based on R&D employees
|
||||
//Scientific Research can be produced without a warehouse
|
||||
if (office instanceof OfficeSpace) {
|
||||
this.sciResearch.qty += (.005
|
||||
* Math.pow(office.employeeProd[EmployeePositions.RandD], 0.55)
|
||||
this.sciResearch.qty += (.004
|
||||
* Math.pow(office.employeeProd[EmployeePositions.RandD], 0.5)
|
||||
* company.getScientificResearchMultiplier()
|
||||
* this.getScientificResearchMultiplier());
|
||||
}
|
||||
@ -962,9 +982,9 @@ Industry.prototype.processProducts = function(marketCycles=1, corporation) {
|
||||
|
||||
//Processes FINISHED products
|
||||
Industry.prototype.processProduct = function(marketCycles=1, product, corporation) {
|
||||
var totalProfit = 0;
|
||||
for (var i = 0; i < Cities.length; ++i) {
|
||||
var city = Cities[i], office = this.offices[city], warehouse = this.warehouses[city];
|
||||
let totalProfit = 0;
|
||||
for (let i = 0; i < Cities.length; ++i) {
|
||||
let city = Cities[i], office = this.offices[city], warehouse = this.warehouses[city];
|
||||
if (warehouse instanceof Warehouse) {
|
||||
switch(this.state) {
|
||||
|
||||
@ -1043,24 +1063,57 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
|
||||
// Since its a product, its production cost is increased for labor
|
||||
product.pCost *= ProductProductionCostRatio;
|
||||
|
||||
// Sale multipliers
|
||||
const businessFactor = this.getBusinessFactor(office); //Business employee productivity
|
||||
const advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
|
||||
const marketFactor = this.getMarketFactor(product); //Competition + demand
|
||||
|
||||
// Calculate Sale Cost (sCost), which could be dynamically evaluated
|
||||
const markupLimit = product.rat / product.mku;
|
||||
var sCost;
|
||||
if (isString(product.sCost)) {
|
||||
if (product.marketTa2) {
|
||||
const prod = product.data[city][1];
|
||||
|
||||
// Reverse engineer the 'maxSell' formula
|
||||
// 1. Set 'maxSell' = prod
|
||||
// 2. Substitute formula for 'markup'
|
||||
// 3. Solve for 'sCost'roduct.pCost = sCost
|
||||
const numerator = markupLimit;
|
||||
const sqrtNumerator = prod;
|
||||
const sqrtDenominator = (0.5
|
||||
* Math.pow(product.rat, 0.65)
|
||||
* marketFactor
|
||||
* corporation.getSalesMultiplier()
|
||||
* businessFactor
|
||||
* advertisingFactor
|
||||
* this.getSalesMultiplier());
|
||||
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
|
||||
let optimalPrice;
|
||||
if (sqrtDenominator === 0 || denominator === 0) {
|
||||
optimalPrice = 0;
|
||||
} else {
|
||||
optimalPrice = (numerator / denominator) + product.pCost;
|
||||
}
|
||||
|
||||
// Store this "optimal Price" in a property so we don't have to re-calculate for UI
|
||||
product.marketTa2Price[city] = optimalPrice;
|
||||
sCost = optimalPrice;
|
||||
} else if (product.marketTa1) {
|
||||
sCost = product.pCost + markupLimit;
|
||||
} else if (isString(product.sCost)) {
|
||||
sCost = product.sCost.replace(/MP/g, product.pCost + product.rat / product.mku);
|
||||
sCost = eval(sCost);
|
||||
} else {
|
||||
sCost = product.sCost;
|
||||
}
|
||||
|
||||
var markup = 1, markupLimit = product.rat / product.mku;
|
||||
var markup = 1;
|
||||
if (sCost > product.pCost) {
|
||||
if ((sCost - product.pCost) > markupLimit) {
|
||||
markup = markupLimit / (sCost - product.pCost);
|
||||
}
|
||||
}
|
||||
var businessFactor = this.getBusinessFactor(office); //Business employee productivity
|
||||
var advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
|
||||
var marketFactor = this.getMarketFactor(product); //Competition + demand
|
||||
|
||||
var maxSell = 0.5
|
||||
* Math.pow(product.rat, 0.65)
|
||||
* marketFactor
|
||||
@ -1085,8 +1138,9 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
|
||||
} else if (product.sllman[city][0] && product.sllman[city][1] > 0) {
|
||||
//Sell amount is manually limited
|
||||
sellAmt = Math.min(maxSell, product.sllman[city][1]);
|
||||
} else if (product.sllman[city][0] === false){
|
||||
sellAmt = 0;
|
||||
} else {
|
||||
//Backwards compatibility, -1 = 0
|
||||
sellAmt = maxSell;
|
||||
}
|
||||
if (sellAmt < 0) { sellAmt = 0; }
|
||||
@ -1114,8 +1168,7 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
|
||||
return totalProfit;
|
||||
}
|
||||
|
||||
Industry.prototype.discontinueProduct = function(product, parentRefs) {
|
||||
var company = parentRefs.company, industry = parentRefs.industry;
|
||||
Industry.prototype.discontinueProduct = function(product) {
|
||||
for (var productName in this.products) {
|
||||
if (this.products.hasOwnProperty(productName)) {
|
||||
if (product === this.products[productName]) {
|
||||
|
@ -66,6 +66,7 @@ export class Material {
|
||||
// Flags that signal whether automatic sale pricing through Market TA is enabled
|
||||
marketTa1: boolean = false;
|
||||
marketTa2: boolean = false;
|
||||
marketTa2Price: number = 0;
|
||||
|
||||
constructor(params: IConstructorParams = {}) {
|
||||
if (params.name) { this.name = params.name; }
|
||||
|
@ -13,4 +13,6 @@ export const MaterialSizes: IMap<number> = {
|
||||
Robots: 0.5,
|
||||
AICores: 0.1,
|
||||
RealEstate: 0,
|
||||
"Real Estate": 0,
|
||||
"AI Cores": 0,
|
||||
}
|
||||
|
@ -4,8 +4,10 @@ import { ProductRatingWeights,
|
||||
IProductRatingWeight } from "./ProductRatingWeights";
|
||||
|
||||
import { Cities } from "../Locations/Cities";
|
||||
import { createCityMap } from "../Locations/createCityMap";
|
||||
import { IMap } from "../types";
|
||||
|
||||
|
||||
import { Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver } from "../../utils/JSONReviver";
|
||||
@ -89,14 +91,7 @@ export class Product {
|
||||
// Data refers to the production, sale, and quantity of the products
|
||||
// These values are specific to a city
|
||||
// For each city, the data is [qty, prod, sell]
|
||||
data: IMap<number[]> = {
|
||||
[Cities.Aevum]: [0, 0, 0],
|
||||
[Cities.Chongqing]: [0, 0, 0],
|
||||
[Cities.Sector12]: [0, 0, 0],
|
||||
[Cities.NewTokyo]: [0, 0, 0],
|
||||
[Cities.Ishima]: [0, 0, 0],
|
||||
[Cities.Volhaven]: [0, 0, 0],
|
||||
}
|
||||
data: IMap<number[]> = createCityMap<number[]>([0, 0, 0]);
|
||||
|
||||
// Location of this Product
|
||||
// Only applies for location-based products like restaurants/hospitals
|
||||
@ -113,23 +108,13 @@ export class Product {
|
||||
// Data to keep track of whether production/sale of this Product is
|
||||
// manually limited. These values are specific to a city
|
||||
// [Whether production/sale is limited, limit amount]
|
||||
prdman: IMap<any[]> = {
|
||||
[Cities.Aevum]: [false, 0],
|
||||
[Cities.Chongqing]: [false, 0],
|
||||
[Cities.Sector12]: [false, 0],
|
||||
[Cities.NewTokyo]: [false, 0],
|
||||
[Cities.Ishima]: [false, 0],
|
||||
[Cities.Volhaven]: [false, 0],
|
||||
}
|
||||
prdman: IMap<any[]> = createCityMap<any[]>([false, 0]);
|
||||
sllman: IMap<any[]> = createCityMap<any[]>([false, 0]);
|
||||
|
||||
sllman: IMap<any[]> = {
|
||||
[Cities.Aevum]: [false, 0],
|
||||
[Cities.Chongqing]: [false, 0],
|
||||
[Cities.Sector12]: [false, 0],
|
||||
[Cities.NewTokyo]: [false, 0],
|
||||
[Cities.Ishima]: [false, 0],
|
||||
[Cities.Volhaven]: [false, 0],
|
||||
}
|
||||
// Flags that signal whether automatic sale pricing through Market TA is enabled
|
||||
marketTa1: boolean = false;
|
||||
marketTa2: boolean = false;
|
||||
marketTa2Price: IMap<number> = createCityMap<number>(0);
|
||||
|
||||
constructor(params: IConstructorParams={}) {
|
||||
this.name = params.name ? params.name : "";
|
||||
|
@ -46,6 +46,10 @@ export class Warehouse {
|
||||
// Whether Smart Supply is enabled for this Industry (the Industry that this Warehouse is for)
|
||||
smartSupplyEnabled: boolean = false;
|
||||
|
||||
// Flag that indicates whether Smart Supply accounts for imports when calculating
|
||||
// the amount fo purchase
|
||||
smartSupplyConsiderExports: boolean = false;
|
||||
|
||||
// Stores the amount of product to be produced. Used for Smart Supply unlock.
|
||||
// The production tracked by smart supply is always based on the previous cycle,
|
||||
// so it will always trail the "true" production by 1 cycle
|
||||
|
@ -94,11 +94,13 @@ export const researchMetadata: IConstructorParams[] = [
|
||||
},
|
||||
{
|
||||
name: "Market-TA.II",
|
||||
cost: 40e3,
|
||||
cost: 50e3,
|
||||
desc: "Develop double-advanced AI software that uses technical analysis to " +
|
||||
"help you understand and exploit the market. This research " +
|
||||
"allows you to know how many sales of a Material/Product you lose or gain " +
|
||||
"from having too high or too low or a sale price.",
|
||||
"from having too high or too low or a sale price. It also lets you automatically " +
|
||||
"set the sale price of your Materials/Products at the optimal price such that " +
|
||||
"the amount sold matches the amount produced.",
|
||||
},
|
||||
{
|
||||
name: "Overclock",
|
||||
|
@ -17,10 +17,14 @@ import { Industries,
|
||||
IndustryDescriptions,
|
||||
IndustryResearchTrees } from "../IndustryData";
|
||||
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
|
||||
import { Product } from "../Product";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
@ -81,7 +85,7 @@ export class CorporationEventHandler {
|
||||
|
||||
var totalAmount = Number(money) + (stockShares * stockPrice);
|
||||
var repGain = totalAmount / BribeToRepRatio;
|
||||
repGainText.innerText = "You will gain " + numeralWrapper.formatNumber(repGain, "0,0") +
|
||||
repGainText.innerText = "You will gain " + numeralWrapper.format(repGain, "0,0") +
|
||||
" reputation with " +
|
||||
factionSelector.options[factionSelector.selectedIndex].value +
|
||||
" with this bribe";
|
||||
@ -104,7 +108,7 @@ export class CorporationEventHandler {
|
||||
var totalAmount = money + (stockShares * stockPrice);
|
||||
var repGain = totalAmount / BribeToRepRatio;
|
||||
console.log("repGain: " + repGain);
|
||||
repGainText.innerText = "You will gain " + numeralWrapper.formatNumber(repGain, "0,0") +
|
||||
repGainText.innerText = "You will gain " + numeralWrapper.format(repGain, "0,0") +
|
||||
" reputation with " +
|
||||
factionSelector.options[factionSelector.selectedIndex].value +
|
||||
" with this bribe";
|
||||
@ -131,7 +135,7 @@ export class CorporationEventHandler {
|
||||
} else {
|
||||
var totalAmount = money + (stockShares * stockPrice);
|
||||
var repGain = totalAmount / BribeToRepRatio;
|
||||
dialogBoxCreate("You gained " + formatNumber(repGain, 0) +
|
||||
dialogBoxCreate("You gained " + numeralWrapper.format(repGain, "0,0") +
|
||||
" reputation with " + fac.name + " by bribing them.");
|
||||
fac.playerReputation += repGain;
|
||||
this.corp.funds = this.corp.funds.minus(money);
|
||||
@ -170,7 +174,6 @@ export class CorporationEventHandler {
|
||||
type:"number", placeholder:"Shares to buyback", margin:"5px",
|
||||
inputListener: ()=> {
|
||||
var numShares = Math.round(input.value);
|
||||
//TODO add conditional for if player doesn't have enough money
|
||||
if (isNaN(numShares) || numShares <= 0) {
|
||||
costIndicator.innerText = "ERROR: Invalid value entered for number of shares to buyback"
|
||||
} else if (numShares > this.corp.issuedShares) {
|
||||
@ -228,7 +231,7 @@ export class CorporationEventHandler {
|
||||
}
|
||||
|
||||
// Create a popup that lets the player discontinue a product
|
||||
createDiscontinueProductPopup(product) {
|
||||
createDiscontinueProductPopup(product, industry) {
|
||||
const popupId = "cmpy-mgmt-discontinue-product-popup";
|
||||
const txt = createElement("p", {
|
||||
innerText:"Are you sure you want to do this? Discontinuing a product " +
|
||||
@ -237,9 +240,9 @@ export class CorporationEventHandler {
|
||||
"removed and left unsold",
|
||||
});
|
||||
const confirmBtn = createElement("button", {
|
||||
class:"a-link-button",innerText:"Discontinue",
|
||||
class:"popup-box-button",innerText:"Discontinue",
|
||||
clickListener: () => {
|
||||
industry.discontinueProduct(product, parentRefs);
|
||||
industry.discontinueProduct(product);
|
||||
removeElementById(popupId);
|
||||
this.rerender();
|
||||
return false;
|
||||
@ -247,7 +250,7 @@ export class CorporationEventHandler {
|
||||
});
|
||||
const cancelBtn = createPopupCloseButton(popupId, { innerText: "Cancel" });
|
||||
|
||||
createPopup(popupId, [txt, confirmBtn, cancelBtn]);
|
||||
createPopup(popupId, [txt, cancelBtn, confirmBtn]);
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage exports
|
||||
@ -669,8 +672,8 @@ export class CorporationEventHandler {
|
||||
productNameInput.focus();
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research
|
||||
createMarketTaPopup(mat, industry) {
|
||||
// Create a popup that lets the player use the Market TA research for Materials
|
||||
createMaterialMarketTaPopup(mat, industry) {
|
||||
const corp = this.corp;
|
||||
|
||||
const popupId = "cmpy-mgmt-marketta-popup";
|
||||
@ -694,19 +697,21 @@ export class CorporationEventHandler {
|
||||
"be sold at the price identified by Market-TA.I (i.e. the price shown above)"
|
||||
})
|
||||
const useTa1AutoSaleCheckbox = createElement("input", {
|
||||
checked: mat.marketTa1,
|
||||
id: useTa1AutoSaleId,
|
||||
margin: "3px",
|
||||
type: "checkbox",
|
||||
value: mat.marketTa1,
|
||||
changeListener: (e) => {
|
||||
mat.marketTa1 = e.target.value;
|
||||
mat.marketTa1 = e.target.checked;
|
||||
}
|
||||
});
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleCheckbox);
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleLabel);
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleCheckbox);
|
||||
|
||||
const closeBtn = createPopupCloseButton(popupId, {
|
||||
class: "std-button",
|
||||
display: "block",
|
||||
innerText: "Close",
|
||||
});
|
||||
|
||||
if (industry.hasResearch("Market-TA.II")) {
|
||||
@ -741,11 +746,36 @@ export class CorporationEventHandler {
|
||||
}
|
||||
ta2Text.innerHTML = `<br><u><strong>Market-TA.II</strong></u><br>` +
|
||||
`If you sell at ${numeralWrapper.formatMoney(sCost)}, ` +
|
||||
`then you will sell ${formatNumber(markup, 5)}x as much compared ` +
|
||||
`then you will sell ${numeralWrapper.format(markup, "0.00000")}x as much compared ` +
|
||||
`to if you sold at market price.`;
|
||||
}
|
||||
updateTa2Text();
|
||||
createPopup(popupId, [ta1, ta2Text, ta2Input, closeBtn]);
|
||||
|
||||
// Enable using Market-TA2 for automatically setting sale price
|
||||
const useTa2AutoSaleId = "cmpy-mgmt-marketa2-checkbox";
|
||||
const useTa2AutoSaleDiv = createElement("div", { display: "block" });
|
||||
const useTa2AutoSaleLabel = createElement("label", {
|
||||
color: "white",
|
||||
for: useTa2AutoSaleId,
|
||||
innerText: "Use Market-TA.II for Auto-Sale Price",
|
||||
tooltip: "If this is enabled, then this Material will automatically " +
|
||||
"be sold at the optimal price such that the amount sold matches the " +
|
||||
"amount produced. (i.e. the highest possible price, while still ensuring " +
|
||||
" that all produced materials will be sold)"
|
||||
})
|
||||
const useTa2AutoSaleCheckbox = createElement("input", {
|
||||
checked: mat.marketTa2,
|
||||
id: useTa2AutoSaleId,
|
||||
margin: "3px",
|
||||
type: "checkbox",
|
||||
changeListener: (e) => {
|
||||
mat.marketTa2 = e.target.checked;
|
||||
}
|
||||
});
|
||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
||||
|
||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, closeBtn]);
|
||||
} else {
|
||||
// Market-TA.I only
|
||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
||||
@ -775,6 +805,7 @@ export class CorporationEventHandler {
|
||||
display:"inline-block",
|
||||
innerText: "Confirm",
|
||||
clickListener: () => {
|
||||
if (citySelector.length <= 0) { return false; }
|
||||
let city = citySelector.options[citySelector.selectedIndex].value;
|
||||
if (this.corp.funds.lt(OfficeInitialCost)) {
|
||||
dialogBoxCreate("You don't have enough company funds to open a new office!");
|
||||
@ -921,8 +952,110 @@ export class CorporationEventHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Products
|
||||
createProductMarketTaPopup(product, industry) {
|
||||
const corp = this.corp;
|
||||
|
||||
const popupId = "cmpy-mgmt-marketta-popup";
|
||||
const markupLimit = product.rat / product.mku;
|
||||
const ta1 = createElement("p", {
|
||||
innerHTML: "<u><strong>Market-TA.I</strong></u><br>" +
|
||||
"The maximum sale price you can mark this up to is " +
|
||||
numeralWrapper.formatMoney(product.pCost + markupLimit) +
|
||||
". This means that if you set the sale price higher than this, " +
|
||||
"you will begin to experience a loss in number of sales",
|
||||
});
|
||||
|
||||
// Enable using Market-TA1 for automatically setting sale price
|
||||
const useTa1AutoSaleId = "cmpy-mgmt-marketa1-checkbox";
|
||||
const useTa1AutoSaleDiv = createElement("div", { display: "block" });
|
||||
const useTa1AutoSaleLabel = createElement("label", {
|
||||
color: "white",
|
||||
for: useTa1AutoSaleId,
|
||||
innerText: "Use Market-TA.I for Auto-Sale Price",
|
||||
tooltip: "If this is enabled, then this Product will automatically " +
|
||||
"be sold at the price identified by Market-TA.I (i.e. the price shown above)"
|
||||
})
|
||||
const useTa1AutoSaleCheckbox = createElement("input", {
|
||||
checked: product.marketTa1,
|
||||
id: useTa1AutoSaleId,
|
||||
margin: "3px",
|
||||
type: "checkbox",
|
||||
changeListener: (e) => {
|
||||
product.marketTa1 = e.target.checked;
|
||||
}
|
||||
});
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleLabel);
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleCheckbox);
|
||||
|
||||
const closeBtn = createPopupCloseButton(popupId, {
|
||||
class: "std-button",
|
||||
display: "block",
|
||||
innerText: "Close",
|
||||
});
|
||||
|
||||
if (industry.hasResearch("Market-TA.II")) {
|
||||
let updateTa2Text;
|
||||
const ta2Text = createElement("p");
|
||||
const ta2Input = createElement("input", {
|
||||
marginTop: "4px",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
updateTa2Text();
|
||||
},
|
||||
type: "number",
|
||||
value: product.pCost,
|
||||
});
|
||||
|
||||
// Function that updates the text in ta2Text element
|
||||
updateTa2Text = function() {
|
||||
const sCost = parseFloat(ta2Input.value);
|
||||
let markup = 1;
|
||||
if (sCost > product.pCost) {
|
||||
if ((sCost - product.pCost) > markupLimit) {
|
||||
markup = markupLimit / (sCost - product.pCost);
|
||||
}
|
||||
}
|
||||
ta2Text.innerHTML = `<br><u><strong>Market-TA.II</strong></u><br>` +
|
||||
`If you sell at ${numeralWrapper.formatMoney(sCost)}, ` +
|
||||
`then you will sell ${numeralWrapper.format(markup, "0.00000")}x as much compared ` +
|
||||
`to if you sold at market price.`;
|
||||
}
|
||||
updateTa2Text();
|
||||
|
||||
// Enable using Market-TA2 for automatically setting sale price
|
||||
const useTa2AutoSaleId = "cmpy-mgmt-marketa2-checkbox";
|
||||
const useTa2AutoSaleDiv = createElement("div", { display: "block" });
|
||||
const useTa2AutoSaleLabel = createElement("label", {
|
||||
color: "white",
|
||||
for: useTa2AutoSaleId,
|
||||
innerText: "Use Market-TA.II for Auto-Sale Price",
|
||||
tooltip: "If this is enabled, then this Product will automatically " +
|
||||
"be sold at the optimal price such that the amount sold matches the " +
|
||||
"amount produced. (i.e. the highest possible price, while still ensuring " +
|
||||
" that all produced materials will be sold)"
|
||||
})
|
||||
const useTa2AutoSaleCheckbox = createElement("input", {
|
||||
checked: product.marketTa2,
|
||||
id: useTa2AutoSaleId,
|
||||
margin: "3px",
|
||||
type: "checkbox",
|
||||
changeListener: (e) => {
|
||||
product.marketTa2 = e.target.checked;
|
||||
}
|
||||
});
|
||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
||||
|
||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, closeBtn]);
|
||||
} else {
|
||||
// Market-TA.I only
|
||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a popup that lets the player purchase a Material
|
||||
createPurchaseMaterialPopup(mat, industry) {
|
||||
createPurchaseMaterialPopup(mat, industry, warehouse) {
|
||||
const corp = this.corp;
|
||||
|
||||
const purchasePopupId = "cmpy-mgmt-material-purchase-popup";
|
||||
@ -980,16 +1113,21 @@ export class CorporationEventHandler {
|
||||
|
||||
let bulkPurchaseCostTxt = createElement("p");
|
||||
function updateBulkPurchaseText(amount) {
|
||||
const cost = parseFloat(amount) * mat.bCost;
|
||||
if (isNaN(cost)) {
|
||||
dialogBoxCreate(`Bulk Purchase Cost calculated to be NaN. This is either due to ` +
|
||||
`invalid input, or it is a bug (in which case you should report to dev)`);
|
||||
return;
|
||||
}
|
||||
const parsedAmt = parseFloat(amount);
|
||||
const cost = parsedAmt * mat.bCost;
|
||||
|
||||
bulkPurchaseCostTxt.innerText = `Purchasing ${numeralWrapper.format(amt, "0,0.00")} of ` +
|
||||
const matSize = MaterialSizes[mat.name];
|
||||
const maxAmount = ((warehouse.size - warehouse.sizeUsed) / matSize);
|
||||
|
||||
if (parsedAmt * matSize > maxAmount) {
|
||||
bulkPurchaseCostTxt.innerText = "Not enough warehouse space to purchase this amount";
|
||||
} else if (isNaN(cost)) {
|
||||
bulkPurchaseCostTxt.innerText = "Invalid put for Bulk Purchase amount";
|
||||
} else {
|
||||
bulkPurchaseCostTxt.innerText = `Purchasing ${numeralWrapper.format(parsedAmt, "0,0.00")} of ` +
|
||||
`${mat.name} will cost ${numeralWrapper.formatMoney(cost)}`;
|
||||
}
|
||||
}
|
||||
|
||||
let bulkPurchaseConfirmBtn;
|
||||
const bulkPurchaseInput = createElement("input", {
|
||||
@ -998,7 +1136,7 @@ export class CorporationEventHandler {
|
||||
type: "number",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
updateBulkPurchaseText();
|
||||
updateBulkPurchaseText(e.target.value);
|
||||
if (e.keyCode === KEY.ENTER) {bulkPurchaseConfirmBtn.click();}
|
||||
}
|
||||
});
|
||||
@ -1007,7 +1145,15 @@ export class CorporationEventHandler {
|
||||
class: "std-button",
|
||||
innerText: "Confirm Bulk Purchase",
|
||||
clickListener: () => {
|
||||
const amount = parseFloat(input.value);
|
||||
const amount = parseFloat(bulkPurchaseInput.value);
|
||||
|
||||
const matSize = MaterialSizes[mat.name];
|
||||
const maxAmount = ((warehouse.size - warehouse.sizeUsed) / matSize);
|
||||
if (amount * matSize > maxAmount) {
|
||||
dialogBoxCreate(`You do not have enough warehouse size to fit this purchase`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNaN(amount)) {
|
||||
dialogBoxCreate("Invalid input amount");
|
||||
} else {
|
||||
@ -1065,9 +1211,18 @@ export class CorporationEventHandler {
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
}
|
||||
});
|
||||
|
||||
let inputButtonInitValue = mat.sCost ? mat.sCost : null;
|
||||
if (mat.marketTa2) {
|
||||
inputButtonInitValue += " (Market-TA.II)";
|
||||
} else if (mat.marketTa1) {
|
||||
inputButtonInitValue += " (Market-TA.I)";
|
||||
}
|
||||
|
||||
const inputPx = createElement("input", {
|
||||
type: "text", marginTop: "4px",
|
||||
value: mat.sCost ? mat.sCost : null, placeholder: "Sell price",
|
||||
value: inputButtonInitValue,
|
||||
placeholder: "Sell price",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
@ -1179,16 +1334,41 @@ export class CorporationEventHandler {
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
}
|
||||
});
|
||||
|
||||
let inputButtonInitValue = product.sCost ? product.sCost : null;
|
||||
if (product.marketTa2) {
|
||||
inputButtonInitValue += " (Market-TA.II)";
|
||||
} else if (product.marketTa1) {
|
||||
inputButtonInitValue += " (Market-TA.I)";
|
||||
}
|
||||
|
||||
const inputPx = createElement("input", {
|
||||
margin: "5px 0px 5px 0px",
|
||||
placeholder: "Sell price",
|
||||
type: "text",
|
||||
value: product.sCost ? product.sCost : null,
|
||||
value: inputButtonInitValue,
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
}
|
||||
});
|
||||
const checkboxDiv = createElement("div", {
|
||||
border: "1px solid white",
|
||||
display: "inline-block",
|
||||
})
|
||||
const checkboxLabel = createElement("label", {
|
||||
for: popupId + "-checkbox",
|
||||
innerText: "Use same 'Sell Amount' for all cities",
|
||||
});
|
||||
const checkbox = createElement("input", {
|
||||
checked: true,
|
||||
id: popupId + "-checkbox",
|
||||
margin: "2px",
|
||||
type: "checkbox",
|
||||
});
|
||||
checkboxDiv.appendChild(checkboxLabel);
|
||||
checkboxDiv.appendChild(checkbox);
|
||||
|
||||
confirmBtn = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Confirm",
|
||||
@ -1220,6 +1400,9 @@ export class CorporationEventHandler {
|
||||
product.sCost = cost;
|
||||
}
|
||||
|
||||
// Array of all cities. Used later
|
||||
const cities = Object.values(Cities);
|
||||
|
||||
// Parse quantity
|
||||
if (inputQty.value.includes("MAX") || inputQty.value.includes("PROD")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
@ -1238,8 +1421,16 @@ export class CorporationEventHandler {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return false;
|
||||
}
|
||||
if (checkbox.checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = true;
|
||||
product.sllman[tempCity][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else {
|
||||
product.sllman[city][0] = true;
|
||||
product.sllman[city][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else if (isNaN(inputQty.value)) {
|
||||
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric");
|
||||
return false;
|
||||
@ -1247,21 +1438,39 @@ export class CorporationEventHandler {
|
||||
var qty = parseFloat(inputQty.value);
|
||||
if (isNaN(qty)) {qty = 0;}
|
||||
if (qty === 0) {
|
||||
if (checkbox.checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = false;
|
||||
}
|
||||
} else {
|
||||
product.sllman[city][0] = false;
|
||||
}
|
||||
} else {
|
||||
if (checkbox.checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = true;
|
||||
product.sllman[tempCity][1] = qty;
|
||||
}
|
||||
} else {
|
||||
product.sllman[city][0] = true;
|
||||
product.sllman[city][1] = qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeElementById(popupId);
|
||||
this.rerender();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
const cancelBtn = createPopupCloseButton(popupId, { innerText: "Cancel" });
|
||||
const cancelBtn = createPopupCloseButton(popupId, { class: "std-button" });
|
||||
|
||||
createPopup(popupId, [txt, inputQty, inputPx, confirmBtn, cancelBtn]);
|
||||
const linebreak1 = createElement("br");
|
||||
|
||||
createPopup(popupId, [txt, inputQty, inputPx, confirmBtn, cancelBtn, linebreak1,
|
||||
checkboxDiv]);
|
||||
inputQty.focus();
|
||||
}
|
||||
|
||||
|
@ -305,7 +305,7 @@ export class IndustryOffice extends BaseReactComponent {
|
||||
<p>Total Employee Salary: {numeralWrapper.formatMoney(totalSalary)}</p>
|
||||
{
|
||||
vechain &&
|
||||
<p className={"tooltip"} style={{display: "block"}}>
|
||||
<p className={"tooltip"} style={{display: "inline-block"}}>
|
||||
Material Production: {numeralWrapper.format(division.getOfficeProductivity(office), "0.000")}
|
||||
<span className={"tooltiptext"}>
|
||||
The base amount of material this office can produce. Does not include
|
||||
@ -314,9 +314,12 @@ export class IndustryOffice extends BaseReactComponent {
|
||||
</span>
|
||||
</p>
|
||||
}
|
||||
{
|
||||
vechain && <br />
|
||||
}
|
||||
{
|
||||
vechain &&
|
||||
<p className={"tooltip"} style={{display: "block"}}>
|
||||
<p className={"tooltip"} style={{display: "inline-block"}}>
|
||||
Product Production: {numeralWrapper.format(division.getOfficeProductivity(office, {forProduct:true}), "0.000")}
|
||||
<span className={"tooltiptext"}>
|
||||
The base amount of any given Product this office can produce. Does not include
|
||||
@ -325,15 +328,21 @@ export class IndustryOffice extends BaseReactComponent {
|
||||
</span>
|
||||
</p>
|
||||
}
|
||||
{
|
||||
vechain && <br />
|
||||
}
|
||||
{
|
||||
vechain &&
|
||||
<p className={"tooltip"} style={{display: "block"}}>
|
||||
<p className={"tooltip"} style={{display: "inline-block"}}>
|
||||
Business Multiplier: x{numeralWrapper.format(division.getBusinessFactor(office), "0.000")}
|
||||
<span className={"tooltiptext"}>
|
||||
The effect this office's 'Business' employees has on boosting sales
|
||||
</span>
|
||||
</p>
|
||||
}
|
||||
{
|
||||
vechain && <br />
|
||||
}
|
||||
|
||||
<h2 className={"tooltip"} style={positionHeaderStyle}>
|
||||
{EmployeePositions.Operations} ({this.state.numOperations})
|
||||
|
@ -3,13 +3,13 @@
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
|
||||
import { Material } from "../Material";
|
||||
import { Product } from "../Product";
|
||||
|
||||
import { Warehouse,
|
||||
import { OfficeSpace,
|
||||
WarehouseInitialCost,
|
||||
WarehouseUpgradeBaseCost,
|
||||
ProductProductionCostRatio } from "../Corporation";
|
||||
import { Material } from "../Material";
|
||||
import { Product } from "../Product";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
@ -45,7 +45,12 @@ function ProductComponent(props) {
|
||||
sellButtonText = "Sell (0.000/0.000)";
|
||||
}
|
||||
|
||||
if (product.sCost) {
|
||||
if (product.marketTa2) {
|
||||
sellButtonText += (" @ " + numeralWrapper.formatMoney(product.marketTa2Price[city]));
|
||||
} else if (product.marketTa1) {
|
||||
const markupLimit = product.rat / product.mku;
|
||||
sellButtonText += (" @ " + numeralWrapper.formatMoney(product.pCost + markupLimit));
|
||||
} else if (product.sCost) {
|
||||
if (isString(product.sCost)) {
|
||||
sellButtonText += (" @ " + product.sCost);
|
||||
} else {
|
||||
@ -55,14 +60,17 @@ function ProductComponent(props) {
|
||||
const sellButtonOnClick = eventHandler.createSellProductPopup.bind(eventHandler, product, city);
|
||||
|
||||
// Limit Production button
|
||||
const limitProductionButtonText = "Limit Production";
|
||||
let limitProductionButtonText = "Limit Production";
|
||||
if (product.prdman[city][0]) {
|
||||
limitProductionButtonText += " (" + numeralWrapper.format(product.prdman[city][1], nf) + ")";
|
||||
}
|
||||
const limitProductionButtonOnClick = eventHandler.createLimitProductProdutionPopup.bind(eventHandler, product, city);
|
||||
|
||||
// Discontinue Button
|
||||
const discontinueButtonOnClick = eventHandler.createDiscontinueProductPopup.bind(eventHandler, product);
|
||||
const discontinueButtonOnClick = eventHandler.createDiscontinueProductPopup.bind(eventHandler, product, division);
|
||||
|
||||
// Market TA button
|
||||
const marketTaButtonOnClick = eventHandler.createProductMarketTaPopup.bind(eventHandler, product, division);
|
||||
|
||||
// Unfinished Product
|
||||
if (!product.fin) {
|
||||
@ -83,6 +91,12 @@ function ProductComponent(props) {
|
||||
<button className={"std-button"} onClick={discontinueButtonOnClick}>
|
||||
Discontinue
|
||||
</button>
|
||||
{
|
||||
division.hasResearch("Market-TA.I") &&
|
||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
||||
Market-TA
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -139,7 +153,7 @@ function ProductComponent(props) {
|
||||
</span>
|
||||
</p><br />
|
||||
<p className={"tooltip"}>
|
||||
Est. Market Price: {numeralWrapper.formatMoney(product.pCost + product.rat / product.mku)}
|
||||
Est. Market Price: {numeralWrapper.formatMoney(product.pCost)}
|
||||
<span className={"tooltiptext"}>
|
||||
An estimate of how much consumers are willing to pay for this product.
|
||||
Setting the sale price above this may result in less sales. Setting the sale price below this may result
|
||||
@ -157,6 +171,12 @@ function ProductComponent(props) {
|
||||
<button className={"std-button"} onClick={discontinueButtonOnClick}>
|
||||
Discontinue
|
||||
</button>
|
||||
{
|
||||
division.hasResearch("Market-TA.I") &&
|
||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
||||
Market-TA
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -167,9 +187,14 @@ function MaterialComponent(props) {
|
||||
const corp = props.corp;
|
||||
const division = props.division;
|
||||
const warehouse = props.warehouse;
|
||||
const city = props.city;
|
||||
const mat = props.mat;
|
||||
const eventHandler = props.eventHandler;
|
||||
const markupLimit = mat.getMarkupLimit();
|
||||
const office = division.offices[city];
|
||||
if (!(office instanceof OfficeSpace)) {
|
||||
throw new Error(`Could not get OfficeSpace object for this city (${city})`);
|
||||
}
|
||||
|
||||
// Numeraljs formatter
|
||||
const nf = "0.000";
|
||||
@ -195,7 +220,7 @@ function MaterialComponent(props) {
|
||||
// Purchase material button
|
||||
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nf)})`;
|
||||
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
||||
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division);
|
||||
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division, warehouse);
|
||||
|
||||
// Export material button
|
||||
const exportButtonOnClick = eventHandler.createExportMaterialPopup.bind(eventHandler, mat);
|
||||
@ -209,10 +234,12 @@ function MaterialComponent(props) {
|
||||
sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nf)}/${numeralWrapper.format(mat.sllman[1], nf)})`;
|
||||
}
|
||||
|
||||
if (mat.sCost) {
|
||||
if (mat.marketTa1) {
|
||||
if (mat.marketTa2) {
|
||||
sellButtonText += " @ " + numeralWrapper.formatMoney(mat.marketTa2Price);
|
||||
} else if (mat.marketTa1) {
|
||||
sellButtonText += " @ " + numeralWrapper.formatMoney(mat.bCost + markupLimit);
|
||||
} else if (isString(mat.sCost)) {
|
||||
} else if (mat.sCost) {
|
||||
if (isString(mat.sCost)) {
|
||||
var sCost = mat.sCost.replace(/MP/g, mat.bCost);
|
||||
sellButtonText += " @ " + numeralWrapper.formatMoney(eval(sCost));
|
||||
} else {
|
||||
@ -225,7 +252,7 @@ function MaterialComponent(props) {
|
||||
const sellButtonOnClick = eventHandler.createSellMaterialPopup.bind(eventHandler, mat);
|
||||
|
||||
// Market TA button
|
||||
const marketTaButtonOnClick = eventHandler.createMarketTaPopup.bind(eventHandler, mat, division);
|
||||
const marketTaButtonOnClick = eventHandler.createMaterialMarketTaPopup.bind(eventHandler, mat, division);
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-warehouse-material-div"} key={props.key}>
|
||||
@ -411,6 +438,7 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
// Only create UI for materials that are relevant for the industry
|
||||
if (isRelevantMaterial(matName)) {
|
||||
mats.push(MaterialComponent({
|
||||
city: this.props.currentCity,
|
||||
corp: corp,
|
||||
division: division,
|
||||
eventHandler: this.eventHandler(),
|
||||
|
18
src/Locations/createCityMap.ts
Normal file
18
src/Locations/createCityMap.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Utility function that creates a "city map", which is an object where
|
||||
* each city is a key (property).
|
||||
*
|
||||
* This map uses the official name of the city, NOT its key in the 'Cities' object
|
||||
*/
|
||||
import { Cities } from "./Cities";
|
||||
import { IMap } from "../types";
|
||||
|
||||
export function createCityMap<T>(initValue: T): IMap<T> {
|
||||
const map: IMap<any> = {};
|
||||
const cities = Object.values(Cities);
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
map[cities[i]] = initValue;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
@ -105,13 +105,13 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer) {
|
||||
innerHTML:
|
||||
[
|
||||
`<h2>${aug.name}</h2><br>`,
|
||||
`Cost: ${numeralWrapper.formatMoney(aug.baseCost)}<br><br>`,
|
||||
`Cost: ${numeralWrapper.formatMoney(aug.startingCost)}<br><br>`,
|
||||
`${aug.info}`
|
||||
].join(" "),
|
||||
padding: "2px",
|
||||
clickListener: () => {
|
||||
if (p.canAfford(aug.baseCost)) {
|
||||
p.loseMoney(aug.baseCost);
|
||||
if (p.canAfford(aug.startingCost)) {
|
||||
p.loseMoney(aug.startingCost);
|
||||
sleeve.installAugmentation(aug);
|
||||
dialogBoxCreate(`Installed ${aug.name} on Duplicate Sleeve!`, false)
|
||||
removeElementById(popupId);
|
||||
|
@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl" : ".",
|
||||
"jsx": "react",
|
||||
"lib" : ["es2016", "dom"],
|
||||
"lib" : ["es2016", "dom", "es2017.object"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
|
Loading…
Reference in New Issue
Block a user