Implemented Corporation Market-TA Research (untested). Implemented Corporation dividends. Fixed new Corp mechanic bugs.

This commit is contained in:
danielyxie 2018-12-22 02:27:04 -08:00
parent 9f98603e63
commit 63895fce6d
14 changed files with 9214 additions and 2597 deletions

@ -95,72 +95,6 @@ a:visited {
padding: 0; padding: 0;
} }
/* Tool tips (when hovering over an element */
.tooltip {
display: inline-block;
position: relative;
.tooltiptext {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
}
/* Positioned to left of element rather than right */
.tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99;
}
}
/* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
bottom: -25%;
position: absolute;
z-index: 99;
}
.tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft {
visibility: visible;
}
/* help tip. Question mark that opens popup with info/details */ /* help tip. Question mark that opens popup with info/details */
.help-tip { .help-tip {
background-color: black; background-color: black;

87
css/tooltips.scss Normal file

@ -0,0 +1,87 @@
@import "theme";
/* Styling for tooltip-style elements */
/* Tool tips (when hovering over an element */
.tooltip {
display: inline-block;
position: relative;
.tooltiptext {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
}
/* Positioned to left of element rather than right */
.tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99;
}
/* Tooltip goes below cursor instead of above */
.tooltiptextlow {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
bottom: 25%;
}
}
/* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
bottom: -25%;
position: absolute;
z-index: 99;
}
.tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft,
.tooltip:hover .tooltiptextlow {
visibility: visible;
}

9859
dist/engine.bundle.js vendored

File diff suppressed because it is too large Load Diff

128
dist/engine.css vendored

@ -91,61 +91,6 @@ a:visited {
border-radius: 0; border-radius: 0;
padding: 0; } padding: 0; }
/* Tool tips (when hovering over an element */
.tooltip {
display: inline-block;
position: relative;
/* Positioned to left of element rather than right */ }
.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99; }
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99; }
/* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
bottom: -25%;
position: absolute;
z-index: 99; }
.tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft {
visibility: visible; }
/* help tip. Question mark that opens popup with info/details */ /* help tip. Question mark that opens popup with info/details */
.help-tip { .help-tip {
background-color: black; background-color: black;
@ -390,6 +335,79 @@ a:visited {
.smallfont { .smallfont {
font-size: 13px; } font-size: 13px; }
/* COLORS */
/* Attributes */
/* Styling for tooltip-style elements */
/* Tool tips (when hovering over an element */
.tooltip {
display: inline-block;
position: relative;
/* Positioned to left of element rather than right */
/* Tooltip goes below cursor instead of above */ }
.tooltip .tooltiptext {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99; }
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99; }
.tooltip .tooltiptextlow {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
bottom: 25%; }
/* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
bottom: -25%;
position: absolute;
z-index: 99; }
.tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft,
.tooltip:hover .tooltiptextlow {
visibility: visible; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/** /**

1303
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -510,6 +510,15 @@ export let CONSTANTS: IMap<any> = {
** Changed initial market prices for many materials ** Changed initial market prices for many materials
** Changed the way a material's demand, competition, and market price change over time ** Changed the way a material's demand, competition, and market price change over time
** The sale price of materials can no longer be marked-up as high ** The sale price of materials can no longer be marked-up as high
** Added a Research Tree mechanic. Spend Scientific Research on permanent upgrades for
each industry
** You can now redistribute earnings to shareholders (including yourself) as dividends
** Cost of "Smart Supply" upgraded reduced from $50b to $25b
** Now has offline progress, which works similarly to the Gang/Bladeburner mechanics
** Slightly reduced the amount of money offered to you by investment firms
** Employee salaries now slowly increase over time
* Stock Market, Travel, and Corporation main menu links are now properly styled
` `
} }

@ -1,7 +1,7 @@
import { AllCorporationStates, import { AllCorporationStates,
CorporationState } from "./CorporationState"; CorporationState } from "./CorporationState";
import { CorporationUnlockUpgrades } from "./CorporationUnlockUpgrades"; import { CorporationUnlockUpgrades } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrades } from "./CorporationUpgrades"; import { CorporationUpgrades } from "./data/CorporationUpgrades";
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
import { Industries, import { Industries,
IndustryStartingCosts, IndustryStartingCosts,
@ -14,6 +14,7 @@ import { Product } from "./Product";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { BitNodeMultipliers } from "../BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { showLiterature } from "../Literature"; import { showLiterature } from "../Literature";
import { Locations } from "../Locations"; import { Locations } from "../Locations";
@ -68,6 +69,11 @@ export const BribeToRepRatio = 1e9; //Bribe Value divided by this
export const ProductProductionCostRatio = 5; //Ratio of material cost of a product to its production cost export const ProductProductionCostRatio = 5; //Ratio of material cost of a product to its production cost
export const DividendMaxPercentage = 99;
export const CyclesPerEmployeeRaise = 400; // All employees get a raise every X market cycles
export const EmployeeRaiseAmount = 50; // Employee salary increases by this (additive)
// Delete Research Popup Box when clicking outside of it // Delete Research Popup Box when clicking outside of it
$(document).mousedown(function(event) { $(document).mousedown(function(event) {
const boxId = "corporation-research-popup-box"; const boxId = "corporation-research-popup-box";
@ -725,7 +731,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
} }
//Calculate how much of the material sells (per second) //Calculate how much of the material sells (per second)
let markup = 1, markupLimit = mat.qlt / mat.mku; let markup = 1, markupLimit = mat.getMarkupLimit();
if (sCost > mat.bCost) { if (sCost > mat.bCost) {
//Penalty if difference between sCost and bCost is greater than markup limit //Penalty if difference between sCost and bCost is greater than markup limit
if ((sCost - mat.bCost) > markupLimit) { if ((sCost - mat.bCost) > markupLimit) {
@ -1093,7 +1099,7 @@ Industry.prototype.upgrade = function(upgrade, refs) {
switch (upgN) { switch (upgN) {
case 0: //Coffee, 5% energy per employee case 0: //Coffee, 5% energy per employee
for (let i = 0; i < office.employees.length; ++i) { for (let i = 0; i < office.employees.length; ++i) {
office.employees[i].ene = Math.min(office.employees[i].ene * 1.05, office.employees[i].maxEne); office.employees[i].ene = Math.min(office.employees[i].ene * 1.05, office.maxEne);
} }
break; break;
case 1: //AdVert.Inc, case 1: //AdVert.Inc,
@ -1207,9 +1213,12 @@ Industry.prototype.createResearchBox = function() {
researchTreeBox = null; researchTreeBox = null;
} }
// New popup box
const researchTree = IndustryResearchTrees[this.type]; const researchTree = IndustryResearchTrees[this.type];
// Create the popup first, so that the tree diagram can be added to it
// This is handled by Treant
researchTreeBox = createPopup(boxId, [], { backgroundColor: "black" });
// Get the tree's markup (i.e. config) for Treant // Get the tree's markup (i.e. config) for Treant
const markup = researchTree.createTreantMarkup(); const markup = researchTree.createTreantMarkup();
markup.chart.container = "#" + boxId + "-content"; markup.chart.container = "#" + boxId + "-content";
@ -1225,10 +1234,6 @@ Industry.prototype.createResearchBox = function() {
}, },
} }
// Create the popup first, so that the tree diagram can be added to it
// This is handled by Treant
researchTreeBox = createPopup(boxId, [], { backgroundColor: "black" });
// Construct the tree with Treant // Construct the tree with Treant
const treantTree = new Treant(markup); const treantTree = new Treant(markup);
@ -1240,7 +1245,7 @@ Industry.prototype.createResearchBox = function() {
// Get the DOM Element to add a click listener to it // Get the DOM Element to add a click listener to it
const sanitizedName = allResearch[i].replace(/\s/g, ''); const sanitizedName = allResearch[i].replace(/\s/g, '');
const div = document.getElementById(sanitizedName + "-click-listener"); const div = document.getElementById(sanitizedName + "-corp-research-click-listener");
if (div == null) { if (div == null) {
console.warn(`Could not find Research Tree div for ${sanitizedName}`); console.warn(`Could not find Research Tree div for ${sanitizedName}`);
continue; continue;
@ -1254,13 +1259,45 @@ Industry.prototype.createResearchBox = function() {
const node = researchTree.findNode(allResearch[i]); const node = researchTree.findNode(allResearch[i]);
node.researched = true; node.researched = true;
return createResearchBox(); return this.createResearchBox();
} else { } else {
dialogBoxCreate(`You do not have enough Scientific Research for ${research.name}`); dialogBoxCreate(`You do not have enough Scientific Research for ${research.name}`);
} }
}); });
} }
const boxContent = document.getElementById(`${boxId}-content`);
if (boxContent != null) {
// Add information about multipliers from research at the bottom of the popup
appendLineBreaks(boxContent, 2);
boxContent.appendChild(createElement("pre", {
display: "block",
innerText: `Multipliers from research:\n` +
` * Advertising Multiplier: x${researchTree.getAdvertisingMultiplier()}\n` +
` * Employee Charisma Multiplier: x${researchTree.getEmployeeChaMultiplier()}\n` +
` * Employee Creativity Multiplier: x${researchTree.getEmployeeCreMultiplier()}\n` +
` * Employee Efficiency Multiplier: x${researchTree.getEmployeeEffMultiplier()}\n` +
` * Employee Intelligence Multiplier: x${researchTree.getEmployeeIntMultiplier()}\n` +
` * Production Multiplier: x${researchTree.getProductionMultiplier()}\n` +
` * Sales Multiplier: x${researchTree.getSalesMultiplier()}\n` +
` * Scientific Research Multiplier: x${researchTree.getScientificResearchMultiplier()}\n` +
` * Storage Multiplier: x${researchTree.getStorageMultiplier()}`,
}));
// Close button
boxContent.appendChild(createElement("button", {
class: "std-button",
clickListener: () => {
if (researchTreeBox != null) {
removeElement(researchTreeBox);
}
},
display: "block",
innerText: "Close",
}));
}
researchTreeBoxOpened = true; researchTreeBoxOpened = true;
} }
@ -1294,6 +1331,8 @@ function Employee(params={}) {
this.sal = params.salary ? params.salary : getRandomInt(0.1, 5); this.sal = params.salary ? params.salary : getRandomInt(0.1, 5);
this.pro = 0; //Productivity, This is calculated this.pro = 0; //Productivity, This is calculated
this.cyclesUntilRaise = CyclesPerEmployeeRaise;
this.loc = params.loc ? params.loc : ""; this.loc = params.loc ? params.loc : "";
this.pos = EmployeePositions.Unassigned; this.pos = EmployeePositions.Unassigned;
} }
@ -1310,6 +1349,13 @@ Employee.prototype.process = function(marketCycles=1, office) {
this.cha -= det; this.cha -= det;
} }
// Employee salaries slowly go up over time
this.cyclesUntilRaise -= marketCycles;
if (this.cyclesUntilRaise <= 0) {
this.salary += EmployeeRaiseAmount;
this.cyclesUntilRaise += CyclesPerEmployeeRaise;
}
//Training //Training
var trainingEff = gain * Math.random(); var trainingEff = gain * Math.random();
if (this.pos === EmployeePositions.Training) { if (this.pos === EmployeePositions.Training) {
@ -1854,16 +1900,14 @@ Warehouse.prototype.createUI = function(parentRefs) {
reqText += " and " + industry.getProductDescriptionText(); reqText += " and " + industry.getProductDescriptionText();
} }
} else if (industry.makesProducts) { } else if (industry.makesProducts) {
reqText += industry.getProductDescriptionText(); reqText += (industry.getProductDescriptionText() + ".");
} }
reqText += "<br><br>To get started with production, purchase your required " +
"materials or import them from another of your company's divisions.<br><br>";
//Material ratio text for tooltip //Material ratio text for tooltip
var reqRatioText = "The exact requirements for production are:<br>"; var reqRatioText = ". The exact requirements for production are:<br>";
for (var matName in industry.reqMats) { for (var matName in industry.reqMats) {
if (industry.reqMats.hasOwnProperty(matName)) { if (industry.reqMats.hasOwnProperty(matName)) {
reqRatioText += (industry.reqMats[matName] + " " + matName + "<br>"); reqRatioText += ([" *", industry.reqMats[matName], matName].join(" ") + "<br>");
} }
} }
reqRatioText += "in order to create "; reqRatioText += "in order to create ";
@ -1876,9 +1920,12 @@ Warehouse.prototype.createUI = function(parentRefs) {
reqRatioText += "one of its Products"; reqRatioText += "one of its Products";
} }
industryWarehousePanel.appendChild(createElement("p", { reqText += reqRatioText;
innerHTML:reqText, tooltipleft:reqRatioText
})); reqText += "<br><br>To get started with production, purchase your required " +
"materials or import them from another of your company's divisions.<br><br>";
industryWarehousePanel.appendChild(createElement("p", { innerHTML: reqText }));
//Current state //Current state
industryWarehouseStateText = createElement("p"); industryWarehouseStateText = createElement("p");
@ -2351,6 +2398,69 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
} }
})); }));
// Button to use Market-TA research, if you have it
if (industry.hasResearch("Market-TA.I")) {
let marketTaClickListener = () => {
const popupId = "cmpy-mgmt-marketta-popup";
const markupLimit = mat.getMarkupLimit();
const ta1 = createElemenet("p", {
innerText: "The maximum sale price you can mark this up to is " +
numeralWrapper.format(mat.bCost + markupLimit, '$0.000a') +
". This means that if you set the sale price higher than this, " +
"you will begin to experience a loss in number of sales",
});
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: mat.sCost,
});
// Function that updates the text in ta2Text element
updateTa2Text = () => {
const sCost = parseFloat(ta2Input.value);
let markup = 1;
if (sCost > mat.bCost) {
//Penalty if difference between sCost and bCost is greater than markup limit
if ((sCost - mat.bCost) > markupLimit) {
markup = Math.pow(markupLimit / (sCost - mat.bCost), 2);
}
} else if (sCost < mat.bCost) {
if (sCost <= 0) {
markup = 1e12; //Sell everything, essentially discard
} else {
//Lower prices than market increases sales
markup = mat.bCost / sCost;
}
}
ta2Text.innerText = `If you sell at ${numeralWrapper.format(sCost, "$0.0001")}, ` +
`then you will sell ${formatNumber(markup, 2)}x as much compared `
`to if you sold at market price.`;
}
updateTa2Text();
createPopup(popupId, [ta1, ta2Input, ta2Text]);
} else {
// Market-TA.I only
createPopup(popupId, [ta1]);
}
};
buttonPanel.appendChild(createElement("a", {
class: "a-link-button",
clickListener:() => { marketTaClickListener(); },
display: "inline-block",
innerText: "Market-TA",
}))
}
return div; return div;
} }
@ -2642,6 +2752,8 @@ function Corporation(params={}) {
this.fundingRound = 0; this.fundingRound = 0;
this.public = false; //Publicly traded this.public = false; //Publicly traded
this.numShares = TOTALSHARES; this.numShares = TOTALSHARES;
this.dividendPercentage = 0;
this.dividendTaxPercentage = 50;
this.issuedShares = 0; this.issuedShares = 0;
this.sharePrice = 0; this.sharePrice = 0;
this.storedCycles = 0; this.storedCycles = 0;
@ -2681,14 +2793,30 @@ Corporation.prototype.process = function() {
this.expenses = this.expenses.plus(ind.lastCycleExpenses); this.expenses = this.expenses.plus(ind.lastCycleExpenses);
}); });
var profit = this.revenue.minus(this.expenses); var profit = this.revenue.minus(this.expenses);
var cycleProfit = profit.times(marketCycles * SecsPerMarketCycle); const cycleProfit = profit.times(marketCycles * SecsPerMarketCycle);
if (isNaN(this.funds)) { if (isNaN(this.funds)) {
dialogBoxCreate("There was an error calculating your Corporations funds and they got reset to 0. " + dialogBoxCreate("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 = new Decimal(150e9);
} }
// Process dividends
if (this.dividendPercentage > 0 && cycleProfit > 0) {
// Validate input again, just to be safe
if (isNaN(this.dividendPercentage) || this.dividendPercentage < 0 || this.dividendPercentage > DividendMaxPercentage) {
console.error(`Invalid Corporation dividend percentage: ${this.dividendPercentage}`);
} else {
const totalDividends = (this.dividendPercentage / 100) * cycleProfit;
const retainedEarnings = cycleProfit - totalDividends;
const dividendsPerShare = totalDividends / TOTALSHARES;
Player.gainMoney(this.numShares * dividendsPerShare * (this.dividendTaxPercentage / 100));
this.funds = this.funds.plus(retainedEarnings);
}
} else {
this.funds = this.funds.plus(cycleProfit); this.funds = this.funds.plus(cycleProfit);
}
this.updateSharePrice(); this.updateSharePrice();
} }
@ -2706,13 +2834,18 @@ Corporation.prototype.process = function() {
Corporation.prototype.determineValuation = function() { Corporation.prototype.determineValuation = function() {
var val, profit = (this.revenue.minus(this.expenses)).toNumber(); var val, profit = (this.revenue.minus(this.expenses)).toNumber();
if (this.public) { if (this.public) {
// Account for dividends
if (this.dividendPercentage > 0) {
profit *= ((100 - this.dividendPercentage) / 100);
}
val = this.funds.toNumber() + (profit * 85e3); val = this.funds.toNumber() + (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.toNumber(), 0) / 3; //Base valuation
if (profit > 0) { if (profit > 0) {
val += (profit * 320e3); val += (profit * 300e3);
val *= (Math.pow(1.1, this.divisions.length)); val *= (Math.pow(1.1, this.divisions.length));
} else { } else {
val = 10e9 * Math.pow(1.1, this.divisions.length); val = 10e9 * Math.pow(1.1, this.divisions.length);
@ -2759,7 +2892,8 @@ Corporation.prototype.getInvestment = function() {
yesNoBoxCreate("An investment firm has offered you " + numeralWrapper.format(funding, '$0.000a') + yesNoBoxCreate("An investment firm has offered you " + numeralWrapper.format(funding, '$0.000a') +
" in funding in exchange for a " + numeralWrapper.format(percShares*100, "0.000a") + " in funding in exchange for a " + numeralWrapper.format(percShares*100, "0.000a") +
"% stake in the company (" + numeralWrapper.format(investShares, '0.000a') + " shares).<br><br>" + "% stake in the company (" + numeralWrapper.format(investShares, '0.000a') + " shares).<br><br>" +
"Do you accept or reject this offer?"); "Do you accept or reject this offer?<br><br>" +
"Hint: Investment firms will offer more money if your corporation is turning a profit");
} }
Corporation.prototype.goPublic = function() { Corporation.prototype.goPublic = function() {
@ -3213,8 +3347,9 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
//Sell share buttons //Sell share buttons
var sellShares = createElement("a", { var sellShares = createElement("a", {
class:"a-link-button", innerText:"Sell Shares", display:"inline-block", class:"a-link-button", innerText:"Sell Shares", display:"inline-block",
tooltip:"Sell your shares in the company. This is the only way to " + tooltip: "Sell your shares in the company. The money earned from selling your " +
"profit from your business venture.", "shares goes into your personal account, not the Corporation's. " +
"This is one of the only ways to profit from your business venture.",
clickListener:()=>{ clickListener:()=>{
var popupId = "cmpy-mgmt-sell-shares-popup"; var popupId = "cmpy-mgmt-sell-shares-popup";
var currentStockPrice = this.sharePrice; var currentStockPrice = this.sharePrice;
@ -3470,6 +3605,68 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
} }
}); });
companyManagementPanel.appendChild(bribeFactions); companyManagementPanel.appendChild(bribeFactions);
// Set Stock Dividends
const issueDividends = createElement("a", {
class: "a-link-button",
display: "inline-block",
innerText: "Issue Dividends",
tooltip: "Manage the dividends that are paid out to shareholders (including yourself)",
clickListener: () => {
const popupId = "cmpy-mgmt-issue-dividends-popup";
const descText = "Dividends are a distribution of a portion of the corporation's " +
"profits to the shareholders. This includes yourself, as well.<br><br>" +
"In order to issue dividends, simply allocate some percentage " +
"of your corporation's profits to dividends. This percentage must be an " +
`integer between 0 and ${DividendMaxPercentage}. (A percentage of 0 means no dividends will be ` +
"issued<br><br>" +
"Two important things to note:<br>" +
" * Issuing dividends will negatively affect your corporation's stock price<br>" +
" * Dividends are taxed. Taxes start at 50%, but can be decreased<br><br>" +
"Example: Assume your corporation makes $100m / sec in profit and you allocate " +
"40% of that towards dividends. That means your corporation will gain $60m / sec " +
"in funds and the remaining $40m / sec will be paid as dividends. Since your " +
"corporation starts with 1 billion shares, every shareholder will be paid $0.04 per share " +
"per second before taxes.";
const txt = createElement("p", { innerHTML: descText, });
const dividendPercentInput = createElement("input", {
margin: "5px",
placeholder: "Dividend %",
type: "number",
});
const allocateBtn = createElement("button", {
class: "std-button",
display: "inline-block",
innerText: "Allocate Dividend Percentage",
clickListener: () => {
const percentage = Math.round(parseInt(dividendPercentInput.value));
if (isNaN(percentage) || percentage < 0 || percentage > DividendMaxPercentage) {
return dialogBoxCreate(`Invalid value. Must be an integer between 0 and ${DividendMaxPercentage}`);
}
this.dividendPercentage = percentage;
removeElementById(popupId);
return false;
}
});
const cancelBtn = createElement("button", {
class: "std-button",
display: "inline-block",
innerText: "Cancel",
clickListener: () => {
removeElementById(popupId);
return false;
}
})
createPopup(popupId, [txt, dividendPercentInput, allocateBtn, cancelBtn]);
},
});
companyManagementPanel.appendChild(issueDividends);
} else { } else {
var findInvestors = createElement("a", { var findInvestors = createElement("a", {
class: this.fundingRound >= 4 ? "a-link-button-inactive" : "a-link-button tooltip", class: this.fundingRound >= 4 ? "a-link-button-inactive" : "a-link-button tooltip",
@ -3604,17 +3801,39 @@ Corporation.prototype.updateCorporationOverviewContent = function() {
totalRevenue = new Decimal(0), totalRevenue = new Decimal(0),
totalExpenses = new Decimal(0); totalExpenses = new Decimal(0);
// Formatted text for profit
var profit = this.revenue.minus(this.expenses).toNumber(), var profit = this.revenue.minus(this.expenses).toNumber(),
profitStr = profit >= 0 ? numeralWrapper.format(profit, "$0.000a") : "-" + numeralWrapper.format(-1 * profit, "$0.000a"); profitStr = profit >= 0 ? numeralWrapper.format(profit, "$0.000a") : "-" + numeralWrapper.format(-1 * profit, "$0.000a");
// Formatted text for dividend information, if applicable
let dividendStr = "";
if (this.dividendPercentage > 0 && profit > 0) {
const totalDividends = (this.dividendPercentage / 100) * profit;
const retainedEarnings = profit - totalDividends;
const dividendsPerShare = totalDividends / TOTALSHARES;
const playerEarnings = this.numShares * dividendsPerShare;
dividendStr = `Retained Profits (after dividends): ${numeralWrapper.format(retainedEarnings, "$0.000a")} / s<br>` +
`Dividends per share: ${numeralWrapper.format(dividendsPerShare, "$0.000a")} / s<br>` +
`Your earnings (Pre-Tax): ${numeralWrapper.format(playerEarnings, "$0.000a")} / s<br>` +
`Your earnings (Post-Tax): ${numeralWrapper.format(playerEarnings * (this.dividendTaxPercentage / 100), "$0.000a")} / s<br>`;
}
var txt = "Total Funds: " + numeralWrapper.format(totalFunds.toNumber(), '$0.000a') + "<br>" + var txt = "Total Funds: " + numeralWrapper.format(totalFunds.toNumber(), '$0.000a') + "<br>" +
"Total Revenue: " + numeralWrapper.format(this.revenue.toNumber(), "$0.000a") + " / s<br>" + "Total Revenue: " + numeralWrapper.format(this.revenue.toNumber(), "$0.000a") + " / s<br>" +
"Total Expenses: " + numeralWrapper.format(this.expenses.toNumber(), "$0.000a") + "/ s<br>" + "Total Expenses: " + numeralWrapper.format(this.expenses.toNumber(), "$0.000a") + "/ s<br>" +
"Total Profits: " + profitStr + " / s<br>" + "Total Profits: " + profitStr + " / s<br>" +
dividendStr +
"Publicly Traded: " + (this.public ? "Yes" : "No") + "<br>" + "Publicly Traded: " + (this.public ? "Yes" : "No") + "<br>" +
"Owned Stock Shares: " + numeralWrapper.format(this.numShares, '0.000a') + "<br>" + "Owned Stock Shares: " + numeralWrapper.format(this.numShares, '0.000a') + "<br>" +
"Stock Price: " + (this.public ? "$" + formatNumber(this.sharePrice, 2) : "N/A") + "<br><br>"; "Stock Price: " + (this.public ? "$" + formatNumber(this.sharePrice, 2) : "N/A") + "<br><br>";
const storedTime = this.storedCycles * CONSTANTS.MilliPerCycle / 1000;
if (storedTime > 15) {
txt += `Bonus Time: ${storedTime} seconds<br><br>`;
}
var prodMult = this.getProductionMultiplier(), var prodMult = this.getProductionMultiplier(),
storageMult = this.getStorageMultiplier(), storageMult = this.getStorageMultiplier(),
advMult = this.getAdvertisingMultiplier(), advMult = this.getAdvertisingMultiplier(),
@ -4257,7 +4476,7 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
for (var i = 0; i < positions.length; ++i) { for (var i = 0; i < positions.length; ++i) {
(function(corp, i) { (function(corp, i) {
var info = createElement("h2", { var info = createElement("h2", {
display:"inline-block", width:"40%", fontSize:"15px", display:"inline-block", width:"50%", fontSize:"15px",
innerText: positions[i] + "(" + counts[i] + ")", innerText: positions[i] + "(" + counts[i] + ")",
tooltip: descriptions[i] tooltip: descriptions[i]
}); });

@ -14,7 +14,7 @@ export class Material {
// Name of material // Name of material
name: string = ""; name: string = "InitName";
// Amount of material owned // Amount of material owned
qty: number = 0; qty: number = 0;
@ -69,6 +69,10 @@ export class Material {
this.init(); this.init();
} }
getMarkupLimit(): number {
return this.qlt / this.mku;
}
init(): void { init(): void {
switch(this.name) { switch(this.name) {
case "Water": case "Water":
@ -138,9 +142,10 @@ export class Material {
this.mku = 0.5; this.mku = 0.5;
break; break;
case "Scientific Research": case "Scientific Research":
case "InitName":
break; break;
default: default:
console.log("Invalid material type in init(): " + this.name); console.error(`Invalid material type in init(): ${this.name}`);
break; break;
} }
} }
@ -155,7 +160,7 @@ export class Material {
//This 1st random check determines whether competition increases or decreases //This 1st random check determines whether competition increases or decreases
const compVolatility: number = (Math.random() * this.mv) / 100; const compVolatility: number = (Math.random() * this.mv) / 100;
const compChange: number = 1 + compVolatility; const compChange: number = 1 + compVolatility;
if (Math.random() < 5) { if (Math.random() < 0.5) {
this.cmp *= compChange; this.cmp *= compChange;
if (this.cmp > this.cmpR[1]) {this.cmp = this.cmpR[1]}; if (this.cmp > this.cmpR[1]) {this.cmp = this.cmpR[1]};
this.bCost *= (1 / priceChange); // Competition increases, so price goes down this.bCost *= (1 / priceChange); // Competition increases, so price goes down

@ -7,6 +7,8 @@
import { Research } from "./Research"; import { Research } from "./Research";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { IMap } from "../types";
interface IConstructorParams { interface IConstructorParams {
children?: Node[]; children?: Node[];
cost: number; cost: number;
@ -75,11 +77,17 @@ export class Node {
htmlClass = "unlocked"; htmlClass = "unlocked";
} }
const research: Research | null = ResearchMap[this.text];
const sanitizedName: string = this.text.replace(/\s/g, ''); const sanitizedName: string = this.text.replace(/\s/g, '');
return { return {
children: childrenArray, children: childrenArray,
HTMLclass: htmlClass, HTMLclass: htmlClass,
innerHTML: `<div id="${sanitizedName}-click-listener">${this.text}<br>${this.cost} Scientific Research</div>`, innerHTML: `<div id="${sanitizedName}-corp-research-click-listener" class="tooltip">` +
`${this.text}<br>${this.cost} Scientific Research` +
`<span class="tooltiptext">` +
`${research.desc}` +
`</span>` +
`</div>` ,
text: { name: this.text }, text: { name: this.text },
} }
} }
@ -108,7 +116,7 @@ export class Node {
// The root node in a Research Tree must always be the "Hi-Tech R&D Laboratory" // The root node in a Research Tree must always be the "Hi-Tech R&D Laboratory"
export class ResearchTree { export class ResearchTree {
// Object containing names of all acquired Research by name // Object containing names of all acquired Research by name
researched: object = {}; researched: IMap<boolean> = {};
// Root Node // Root Node
root: Node | null = null; root: Node | null = null;

@ -1,4 +1,4 @@
import { IMap } from "../types"; import { IMap } from "../../types";
// Corporation Unlock Upgrades // Corporation Unlock Upgrades
// Upgrades for entire corporation, unlocks features, either you have it or you dont // Upgrades for entire corporation, unlocks features, either you have it or you dont
@ -11,7 +11,7 @@ export const CorporationUnlockUpgrades: IMap<any[]> = {
"This allows you to move materials around between different divisions and cities."], "This allows you to move materials around between different divisions and cities."],
//Lets you buy exactly however many required materials you need for production //Lets you buy exactly however many required materials you need for production
"1": [1, 50e9, "Smart Supply", "Use advanced AI to anticipate your supply needs. " + "1": [1, 25e9, "Smart Supply", "Use advanced AI to anticipate your supply needs. " +
"This allows you to purchase exactly however many materials you need for production."], "This allows you to purchase exactly however many materials you need for production."],
//Displays each material/product's demand //Displays each material/product's demand

@ -1,4 +1,4 @@
import { IMap } from "../types"; import { IMap } from "../../types";
// Corporation Upgrades // Corporation Upgrades
// Upgrades for entire corporation, levelable upgrades // Upgrades for entire corporation, levelable upgrades

@ -78,6 +78,7 @@ function initLiterature() {
"find investors. Instead, your Corporation will be publicly traded and its stock price will change based on how well " + "find investors. Instead, your Corporation will be publicly traded and its stock price will change based on how well " +
"it's performing financially. You can then sell your stock shares in order to make money.<br><br>" + "it's performing financially. You can then sell your stock shares in order to make money.<br><br>" +
"<u>Tips/Pointers</u><br>" + "<u>Tips/Pointers</u><br>" +
"-The 'Smart Supply' upgrade is extremely useful. Consider purchasing it as soon as possible.<br><br>" +
"-Purchasing Hardware, Robots, AI Cores, and Real Estate can potentially increase your production. " + "-Purchasing Hardware, Robots, AI Cores, and Real Estate can potentially increase your production. " +
"The effects of these depend on what industry you are in.<br><br>" + "The effects of these depend on what industry you are in.<br><br>" +
"-In order to optimize your production, you will need a good balance of Operators, Managers, and Engineers<br><br>" + "-In order to optimize your production, you will need a good balance of Operators, Managers, and Engineers<br><br>" +

@ -78,6 +78,7 @@ import {Page, routing} from "./ui/navigationTra
// cascade order, we'll pull them all in here. // cascade order, we'll pull them all in here.
import 'normalize.css'; import 'normalize.css';
import "../css/styles.scss"; import "../css/styles.scss";
import "../css/tooltips.scss";
import "../css/buttons.scss"; import "../css/buttons.scss";
import "../css/mainmenu.scss"; import "../css/mainmenu.scss";
import "../css/characteroverview.scss"; import "../css/characteroverview.scss";
@ -520,6 +521,8 @@ const Engine = {
document.getElementById("augmentations-menu-link").classList.remove("active"); document.getElementById("augmentations-menu-link").classList.remove("active");
document.getElementById("hacknet-nodes-menu-link").classList.remove("active"); document.getElementById("hacknet-nodes-menu-link").classList.remove("active");
document.getElementById("city-menu-link").classList.remove("active"); document.getElementById("city-menu-link").classList.remove("active");
document.getElementById("travel-menu-link").classList.remove("active");
document.getElementById("stock-market-menu-link").classList.remove("active");
document.getElementById("tutorial-menu-link").classList.remove("active"); document.getElementById("tutorial-menu-link").classList.remove("active");
document.getElementById("options-menu-link").classList.remove("active"); document.getElementById("options-menu-link").classList.remove("active");
document.getElementById("dev-menu-link").classList.remove("active"); document.getElementById("dev-menu-link").classList.remove("active");
@ -1264,6 +1267,11 @@ const Engine = {
Player.gang.process(numCyclesOffline, Player); Player.gang.process(numCyclesOffline, Player);
} }
// Corporation offline progress
if (Player.corporation instanceof Corporation) {
Player.corporation.storeCycles(numCyclesOffline);
}
// Bladeburner offline progress // Bladeburner offline progress
if (Player.bladeburner instanceof Bladeburner) { if (Player.bladeburner instanceof Bladeburner) {
Player.bladeburner.storeCycles(numCyclesOffline); Player.bladeburner.storeCycles(numCyclesOffline);
@ -1653,6 +1661,7 @@ const Engine = {
Engine.Clickables.travelMainMenuButton = clearEventListeners("travel-menu-link"); Engine.Clickables.travelMainMenuButton = clearEventListeners("travel-menu-link");
Engine.Clickables.travelMainMenuButton.addEventListener("click", function() { Engine.Clickables.travelMainMenuButton.addEventListener("click", function() {
Engine.loadTravelContent(); Engine.loadTravelContent();
Engine.Clickables.travelMainMenuButton.classList.add("active");
return false; return false;
}); });
@ -1665,6 +1674,7 @@ const Engine = {
Engine.Clickables.stockmarketMainMenuButton = clearEventListeners("stock-market-menu-link"); Engine.Clickables.stockmarketMainMenuButton = clearEventListeners("stock-market-menu-link");
Engine.Clickables.stockmarketMainMenuButton.addEventListener("click", function() { Engine.Clickables.stockmarketMainMenuButton.addEventListener("click", function() {
Engine.loadStockMarketContent(); Engine.loadStockMarketContent();
Engine.Clickables.stockmarketMainMenuButton.classList.add("active");
return false; return false;
}); });
@ -1701,6 +1711,7 @@ const Engine = {
Engine.Clickables.corporationMenuButton = clearEventListeners("corporation-menu-link"); Engine.Clickables.corporationMenuButton = clearEventListeners("corporation-menu-link");
Engine.Clickables.corporationMenuButton.addEventListener("click", function() { Engine.Clickables.corporationMenuButton.addEventListener("click", function() {
Engine.loadCorporationContent(); Engine.loadCorporationContent();
Engine.Clickables.corporationMenuButton.classList.add("active");
return false; return false;
}); });
Engine.Clickables.gangMenuButton = clearEventListeners("gang-menu-link"); Engine.Clickables.gangMenuButton = clearEventListeners("gang-menu-link");

@ -68,6 +68,7 @@ interface ICreateElementTooltipOptions {
tooltip?: string; tooltip?: string;
tooltipleft?: string; tooltipleft?: string;
tooltipsmall?: string; tooltipsmall?: string;
tooltiplow?: string;
} }
/** /**
@ -226,7 +227,13 @@ function setElementTooltip(el: HTMLElement, params: ICreateElementTooltipOptions
el.appendChild(createElement("span", { el.appendChild(createElement("span", {
class: "tooltiptext smallfont", class: "tooltiptext smallfont",
innerHTML: params.tooltipsmall, innerHTML: params.tooltipsmall,
})) }));
} else if (params.tooltiplow !== undefined) {
el.className += "tooltip";
el.appendChild(createElement("span", {
class: "tooltiptextlow",
innerHTML: params.tooltiplow,
}));
} }
} }