Corporation Research Trees are now properly saved

This commit is contained in:
danielyxie 2018-12-26 18:38:07 -08:00
parent c654a53025
commit f2353dc052
8 changed files with 581 additions and 497 deletions

@ -21,7 +21,9 @@
} }
.Treant > .researched { .Treant > .researched {
background-color: #444; background-color: #666;
pointer-events: none;
font-size: 16px;
} }
.Treant > .locked > div { .Treant > .locked > div {

762
dist/engine.bundle.js vendored

File diff suppressed because it is too large Load Diff

4
dist/engine.css vendored

@ -2169,7 +2169,9 @@ button {
font-size: 12px; } font-size: 12px; }
.Treant > .researched { .Treant > .researched {
background-color: #444; } background-color: #666;
pointer-events: none;
font-size: 16px; }
.Treant > .locked > div { .Treant > .locked > div {
color: red; color: red;

@ -119,6 +119,7 @@ function Industry(params={}) {
this.type = params.type ? params.type : 0; this.type = params.type ? params.type : 0;
this.sciResearch = new Material({name: "Scientific Research"}); this.sciResearch = new Material({name: "Scientific Research"});
this.researched = {}; // Object of acquired Research. Keys = research name
//A map of the NAME of materials required to create produced materials to //A map of the NAME of materials required to create produced materials to
//how many are needed to produce 1 unit of produced materials //how many are needed to produce 1 unit of produced materials
@ -1163,44 +1164,65 @@ Industry.prototype.getMarketFactor = function(mat) {
// Returns a boolean indicating whether this Industry has the specified Research // Returns a boolean indicating whether this Industry has the specified Research
Industry.prototype.hasResearch = function(name) { Industry.prototype.hasResearch = function(name) {
return (this.researched[name] === true);
}
Industry.prototype.updateResearchTree = function() {
const researchTree = IndustryResearchTrees[this.type]; const researchTree = IndustryResearchTrees[this.type];
return (researchTree.researched[name] != null);
// Since ResearchTree data isnt saved, we'll update the Research Tree data
// based on the stored 'researched' property in the Industry object
if (Object.keys(researchTree.researched).length !== Object.keys(this.researched).length) {
console.log("Updating Corporation Research Tree Data");
for (let research in this.researched) {
researchTree.research(research);
}
}
} }
// Get multipliers from Research // Get multipliers from Research
Industry.prototype.getAdvertisingMultiplier = function() { Industry.prototype.getAdvertisingMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getAdvertisingMultiplier(); return IndustryResearchTrees[this.type].getAdvertisingMultiplier();
} }
Industry.prototype.getEmployeeChaMultiplier = function() { Industry.prototype.getEmployeeChaMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeChaMultiplier(); return IndustryResearchTrees[this.type].getEmployeeChaMultiplier();
} }
Industry.prototype.getEmployeeCreMultiplier = function() { Industry.prototype.getEmployeeCreMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeCreMultiplier(); return IndustryResearchTrees[this.type].getEmployeeCreMultiplier();
} }
Industry.prototype.getEmployeeEffMultiplier = function() { Industry.prototype.getEmployeeEffMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeEffMultiplier(); return IndustryResearchTrees[this.type].getEmployeeEffMultiplier();
} }
Industry.prototype.getEmployeeIntMultiplier = function() { Industry.prototype.getEmployeeIntMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeIntMultiplier(); return IndustryResearchTrees[this.type].getEmployeeIntMultiplier();
} }
Industry.prototype.getProductionMultiplier = function() { Industry.prototype.getProductionMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getProductionMultiplier(); return IndustryResearchTrees[this.type].getProductionMultiplier();
} }
Industry.prototype.getSalesMultiplier = function() { Industry.prototype.getSalesMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getSalesMultiplier(); return IndustryResearchTrees[this.type].getSalesMultiplier();
} }
Industry.prototype.getScientificResearchMultiplier = function() { Industry.prototype.getScientificResearchMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getScientificResearchMultiplier(); return IndustryResearchTrees[this.type].getScientificResearchMultiplier();
} }
Industry.prototype.getStorageMultiplier = function() { Industry.prototype.getStorageMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getStorageMultiplier(); return IndustryResearchTrees[this.type].getStorageMultiplier();
} }
@ -1214,8 +1236,10 @@ Industry.prototype.createResearchBox = function() {
researchTreeBox = null; researchTreeBox = null;
} }
this.updateResearchTree();
const researchTree = IndustryResearchTrees[this.type]; const researchTree = IndustryResearchTrees[this.type];
// Create the popup first, so that the tree diagram can be added to it // Create the popup first, so that the tree diagram can be added to it
// This is handled by Treant // This is handled by Treant
researchTreeBox = createPopup(boxId, [], { backgroundColor: "black" }); researchTreeBox = createPopup(boxId, [], { backgroundColor: "black" });
@ -1257,8 +1281,8 @@ Industry.prototype.createResearchBox = function() {
this.sciResearch.qty -= research.cost; this.sciResearch.qty -= research.cost;
// Get the Node from the Research Tree and set its 'researched' property // Get the Node from the Research Tree and set its 'researched' property
const node = researchTree.findNode(allResearch[i]); researchTree.research(allResearch[i]);
node.researched = true; this.researched[allResearch[i]] = true;
return this.createResearchBox(); return this.createResearchBox();
} else { } else {
@ -3630,13 +3654,18 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
"per second before taxes."; "per second before taxes.";
const txt = createElement("p", { innerHTML: descText, }); const txt = createElement("p", { innerHTML: descText, });
let allocateBtn;
const dividendPercentInput = createElement("input", { const dividendPercentInput = createElement("input", {
margin: "5px", margin: "5px",
placeholder: "Dividend %", placeholder: "Dividend %",
type: "number", type: "number",
onkeyup: (e) => {
e.preventDefault();
if (e.keyCode === 13) {allocateBtn.click();}
}
}); });
const allocateBtn = createElement("button", { allocateBtn = createElement("button", {
class: "std-button", class: "std-button",
display: "inline-block", display: "inline-block",
innerText: "Allocate Dividend Percentage", innerText: "Allocate Dividend Percentage",
@ -3653,17 +3682,14 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
} }
}); });
const cancelBtn = createElement("button", { const cancelBtn = createPopupCloseButton(popupId, {
class: "std-button", class: "std-button",
display: "inline-block", display: "inline-block",
innerText: "Cancel", innerText: "Cancel",
clickListener: () => { });
removeElementById(popupId);
return false;
}
})
createPopup(popupId, [txt, dividendPercentInput, allocateBtn, cancelBtn]); createPopup(popupId, [txt, dividendPercentInput, allocateBtn, cancelBtn]);
dividendPercentInput.focus();
}, },
}); });
companyManagementPanel.appendChild(issueDividends); companyManagementPanel.appendChild(issueDividends);
@ -3971,7 +3997,10 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
fontSize:"14px", fontSize:"14px",
})); }));
industryOverviewUpgrades.appendChild(createElement("br", {})); industryOverviewUpgrades.appendChild(createElement("br", {}));
for (var i = 0; i < numUpgrades; ++i) { for (let i = 0; i < numUpgrades; ++i) {
if (division.hasResearch("AutoBrew") && i == 0) {
continue; // AutoBrew disables Coffee upgrades, which is index 0
}
(function(i, corp, division, office) { (function(i, corp, division, office) {
var upgrade = IndustryUpgrades[i.toString()]; var upgrade = IndustryUpgrades[i.toString()];
if (upgrade == null) { if (upgrade == null) {
@ -4300,72 +4329,74 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
industryEmployeePanel.appendChild(industryOfficeUpgradeSizeButton); industryEmployeePanel.appendChild(industryOfficeUpgradeSizeButton);
//Throw Office Party //Throw Office Party
industryEmployeePanel.appendChild(createElement("a", { if (!division.hasResearch("AutoPartyManager")) {
class:"a-link-button", display:"inline-block", innerText:"Throw Party", industryEmployeePanel.appendChild(createElement("a", {
fontSize:"13px", class:"a-link-button", display:"inline-block", innerText:"Throw Party",
tooltip:"Throw an office party to increase your employee's morale and happiness", fontSize:"13px",
clickListener:()=>{ tooltip:"Throw an office party to increase your employee's morale and happiness",
var popupId = "cmpy-mgmt-throw-office-party-popup"; clickListener:()=>{
var txt = createElement("p", { var popupId = "cmpy-mgmt-throw-office-party-popup";
innerText:"Enter the amount of money you would like to spend PER EMPLOYEE " + var txt = createElement("p", {
"on this office party" innerText:"Enter the amount of money you would like to spend PER EMPLOYEE " +
}); "on this office party"
var totalCostTxt = createElement("p", { });
innerText:"Throwing this party will cost a total of $0" var totalCostTxt = createElement("p", {
}); innerText:"Throwing this party will cost a total of $0"
var confirmBtn; });
var input = createElement("input", { var confirmBtn;
type:"number", margin:"5px", placeholder:"$ / employee", var input = createElement("input", {
inputListener:()=>{ type:"number", margin:"5px", placeholder:"$ / employee",
if (isNaN(input.value) || input.value < 0) { inputListener:()=>{
totalCostTxt.innerText = "Invalid value entered!" if (isNaN(input.value) || input.value < 0) {
} else { totalCostTxt.innerText = "Invalid value entered!"
var totalCost = input.value * office.employees.length;
totalCostTxt.innerText = "Throwing this party will cost a total of " + numeralWrapper.format(totalCost, '$0.000a');
}
},
onkeyup:(e)=>{
e.preventDefault();
if (e.keyCode === 13) {confirmBtn.click();}
}
});
confirmBtn = createElement("a", {
class:"a-link-button",
display:"inline-block",
innerText:"Throw Party",
clickListener:()=>{
if (isNaN(input.value) || input.value < 0) {
dialogBoxCreate("Invalid value entered");
} else {
var totalCost = input.value * office.employees.length;
if (this.funds.lt(totalCost)) {
dialogBoxCreate("You don't have enough company funds to throw this party!");
} else { } else {
this.funds = this.funds.minus(totalCost); var totalCost = input.value * office.employees.length;
var mult; totalCostTxt.innerText = "Throwing this party will cost a total of " + numeralWrapper.format(totalCost, '$0.000a');
for (var fooit = 0; fooit < office.employees.length; ++fooit) {
mult = office.employees[fooit].throwParty(input.value);
}
dialogBoxCreate("You threw a party for the office! The morale and happiness " +
"of each employee increased by " + formatNumber((mult-1) * 100, 2) + "%.");
removeElementById(popupId);
} }
},
onkeyup:(e)=>{
e.preventDefault();
if (e.keyCode === 13) {confirmBtn.click();}
} }
return false; });
} confirmBtn = createElement("a", {
}); class:"a-link-button",
var cancelBtn = createElement("a", { display:"inline-block",
class:"a-link-button", innerText:"Throw Party",
display:"inline-block", clickListener:()=>{
innerText:"Cancel", if (isNaN(input.value) || input.value < 0) {
clickListener:()=>{ dialogBoxCreate("Invalid value entered");
removeElementById(popupId); } else {
return false; var totalCost = input.value * office.employees.length;
} if (this.funds.lt(totalCost)) {
}); dialogBoxCreate("You don't have enough company funds to throw this party!");
createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]); } else {
} this.funds = this.funds.minus(totalCost);
})); var mult;
for (var fooit = 0; fooit < office.employees.length; ++fooit) {
mult = office.employees[fooit].throwParty(input.value);
}
dialogBoxCreate("You threw a party for the office! The morale and happiness " +
"of each employee increased by " + formatNumber((mult-1) * 100, 2) + "%.");
removeElementById(popupId);
}
}
return false;
}
});
var cancelBtn = createElement("a", {
class:"a-link-button",
display:"inline-block",
innerText:"Cancel",
clickListener:()=>{
removeElementById(popupId);
return false;
}
});
createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]);
}
}));
}
industryEmployeeManagementUI = createElement("div", {}); industryEmployeeManagementUI = createElement("div", {});
industryEmployeeInfo = createElement("p", {margin:"4px", padding:"4px"}); industryEmployeeInfo = createElement("p", {margin:"4px", padding:"4px"});

@ -1,9 +1,10 @@
import { ResearchTree } from "./ResearchTree"; import { ResearchTree } from "./ResearchTree";
import { BaseResearchTree, import { getBaseResearchTreeCopy } from "./data/BaseResearchTree";
getBaseResearchTreeCopy } from "./data/BaseResearchTree";
import { numeralWrapper } from "../ui/numeralFormat"; import { numeralWrapper } from "../ui/numeralFormat";
import { Reviver } from "../../utils/JSONReviver";
interface IIndustryMap<T> { interface IIndustryMap<T> {
Energy: T; Energy: T;
Utilities: T; Utilities: T;
@ -105,7 +106,7 @@ export const IndustryDescriptions: IIndustryMap<string> = {
// Map of available Research for each Industry. This data is held in a // Map of available Research for each Industry. This data is held in a
// ResearchTree object // ResearchTree object
export const IndustryResearchTrees: IIndustryMap<ResearchTree> = { export let IndustryResearchTrees: IIndustryMap<ResearchTree> = {
Energy: getBaseResearchTreeCopy(), Energy: getBaseResearchTreeCopy(),
Utilities: getBaseResearchTreeCopy(), Utilities: getBaseResearchTreeCopy(),
Agriculture: getBaseResearchTreeCopy(), Agriculture: getBaseResearchTreeCopy(),
@ -121,3 +122,7 @@ export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
Healthcare: getBaseResearchTreeCopy(), Healthcare: getBaseResearchTreeCopy(),
RealEstate: getBaseResearchTreeCopy(), RealEstate: getBaseResearchTreeCopy(),
} }
export function loadIndustryResearchTrees(saveString: string): void {
IndustryResearchTrees = JSON.parse(saveString, Reviver);
}

@ -3,7 +3,6 @@
// Each Node in the Research Trees only holds the name(s) of Research, // Each Node in the Research Trees only holds the name(s) of Research,
// not an actual Research object. The name can be used to obtain a reference // not an actual Research object. The name can be used to obtain a reference
// to the corresponding Research object using the ResearchMap // to the corresponding Research object using the ResearchMap
import { Research } from "./Research"; import { Research } from "./Research";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
@ -17,6 +16,7 @@ interface IConstructorParams {
} }
export class Node { export class Node {
// All child Nodes in the tree // All child Nodes in the tree
// The Research held in this Node is a prerequisite for all Research in // The Research held in this Node is a prerequisite for all Research in
// child Nodes // child Nodes
@ -37,7 +37,7 @@ export class Node {
// Name of the Research held in this Node // Name of the Research held in this Node
text: string = ""; text: string = "";
constructor(p: IConstructorParams) { constructor(p: IConstructorParams = {cost: 0, text: ""}) {
if (ResearchMap[p.text] == null) { if (ResearchMap[p.text] == null) {
throw new Error(`Invalid Research name used when constructing ResearchTree Node: ${p.text}`); throw new Error(`Invalid Research name used when constructing ResearchTree Node: ${p.text}`);
} }
@ -112,6 +112,7 @@ export class Node {
} }
} }
// A ResearchTree defines all available Research in an Industry // A ResearchTree defines all available Research in an Industry
// 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 {

@ -5,9 +5,6 @@ import { ResearchMap } from "../ResearchMap";
import { ResearchTree, import { ResearchTree,
Node } from "../ResearchTree"; Node } from "../ResearchTree";
export const BaseResearchTree: ResearchTree = new ResearchTree();
function makeNode(name: string): Node { function makeNode(name: string): Node {
const research: Research | null = ResearchMap[name]; const research: Research | null = ResearchMap[name];
if (research == null) { if (research == null) {
@ -17,43 +14,46 @@ function makeNode(name: string): Node {
return new Node({ text: research.name, cost: research.cost }); return new Node({ text: research.name, cost: research.cost });
} }
const rootNode: Node = makeNode("Hi-Tech R&D Laboratory");
const autoBrew: Node = makeNode("AutoBrew");
const autoParty: Node = makeNode("AutoPartyManager");
const autoDrugs: Node = makeNode("Automatic Drug Administration");
const cph4: Node = makeNode("CPH4 Injections");
const drones: Node = makeNode("Drones");
const dronesAssembly: Node = makeNode("Drones - Assembly");
const dronesTransport: Node = makeNode("Drones - Transport");
const goJuice: Node = makeNode("Go-Juice");
const joywire: Node = makeNode("JoyWire");
const marketta1: Node = makeNode("Market-TA.I");
const marketta2: Node = makeNode("Market-TA.II");
const overclock: Node = makeNode("Overclock");
const scAssemblers: Node = makeNode("Self-Correcting Assemblers");
const stimu: Node = makeNode("Sti.mu");
autoDrugs.addChild(goJuice);
autoDrugs.addChild(cph4);
drones.addChild(dronesAssembly);
drones.addChild(dronesTransport);
marketta1.addChild(marketta2);
overclock.addChild(stimu);
rootNode.addChild(autoBrew);
rootNode.addChild(autoParty);
rootNode.addChild(autoDrugs);
rootNode.addChild(drones);
rootNode.addChild(joywire);
rootNode.addChild(marketta1);
rootNode.addChild(overclock);
rootNode.addChild(scAssemblers);
BaseResearchTree.setRoot(rootNode);
export function getBaseResearchTreeCopy(): ResearchTree { export function getBaseResearchTreeCopy(): ResearchTree {
return Object.assign(Object.create(Object.getPrototypeOf(BaseResearchTree)), BaseResearchTree); const baseResearchTree: ResearchTree = new ResearchTree();
const rootNode: Node = makeNode("Hi-Tech R&D Laboratory");
const autoBrew: Node = makeNode("AutoBrew");
const autoParty: Node = makeNode("AutoPartyManager");
const autoDrugs: Node = makeNode("Automatic Drug Administration");
const cph4: Node = makeNode("CPH4 Injections");
const drones: Node = makeNode("Drones");
const dronesAssembly: Node = makeNode("Drones - Assembly");
const dronesTransport: Node = makeNode("Drones - Transport");
const goJuice: Node = makeNode("Go-Juice");
const joywire: Node = makeNode("JoyWire");
const marketta1: Node = makeNode("Market-TA.I");
const marketta2: Node = makeNode("Market-TA.II");
const overclock: Node = makeNode("Overclock");
const scAssemblers: Node = makeNode("Self-Correcting Assemblers");
const stimu: Node = makeNode("Sti.mu");
autoDrugs.addChild(goJuice);
autoDrugs.addChild(cph4);
drones.addChild(dronesAssembly);
drones.addChild(dronesTransport);
marketta1.addChild(marketta2);
overclock.addChild(stimu);
rootNode.addChild(autoBrew);
rootNode.addChild(autoParty);
rootNode.addChild(autoDrugs);
rootNode.addChild(drones);
rootNode.addChild(joywire);
rootNode.addChild(marketta1);
rootNode.addChild(overclock);
rootNode.addChild(scAssemblers);
baseResearchTree.setRoot(rootNode);
return baseResearchTree;
} }

@ -2,6 +2,8 @@ import {loadAliases, loadGlobalAliases,
Aliases, GlobalAliases} from "./Alias"; Aliases, GlobalAliases} from "./Alias";
import {Companies, loadCompanies} from "./Company/Companies"; import {Companies, loadCompanies} from "./Company/Companies";
import {CompanyPosition} from "./Company/CompanyPosition"; import {CompanyPosition} from "./Company/CompanyPosition";
import { IndustryResearchTrees,
loadIndustryResearchTrees } from "./Corporation/IndustryData";
import {CONSTANTS} from "./Constants"; import {CONSTANTS} from "./Constants";
import {Engine} from "./engine"; import {Engine} from "./engine";
import { Factions, import { Factions,
@ -36,19 +38,20 @@ import Decimal from "decimal.js";
let saveObject = new BitburnerSaveObject(); let saveObject = new BitburnerSaveObject();
function BitburnerSaveObject() { function BitburnerSaveObject() {
this.PlayerSave = ""; this.PlayerSave = "";
this.AllServersSave = ""; this.AllServersSave = "";
this.CompaniesSave = ""; this.CompaniesSave = "";
this.FactionsSave = ""; this.FactionsSave = "";
this.SpecialServerIpsSave = ""; this.SpecialServerIpsSave = "";
this.AliasesSave = ""; this.AliasesSave = "";
this.GlobalAliasesSave = ""; this.GlobalAliasesSave = "";
this.MessagesSave = ""; this.MessagesSave = "";
this.StockMarketSave = ""; this.StockMarketSave = "";
this.SettingsSave = ""; this.SettingsSave = "";
this.FconfSettingsSave = ""; this.FconfSettingsSave = "";
this.VersionSave = ""; this.VersionSave = "";
this.AllGangsSave = ""; this.AllGangsSave = "";
this.CorporationResearchTreesSave = "";
} }
BitburnerSaveObject.prototype.saveGame = function(db) { BitburnerSaveObject.prototype.saveGame = function(db) {
@ -260,6 +263,7 @@ function loadImportedGame(saveObj, saveString) {
var tempMessages = null; var tempMessages = null;
var tempStockMarket = null; var tempStockMarket = null;
var tempAllGangs = null; var tempAllGangs = null;
let tempCorporationResearchTrees = null;
//Check to see if the imported save file can be parsed. If any //Check to see if the imported save file can be parsed. If any
//errors are caught it will fail //errors are caught it will fail
@ -332,7 +336,8 @@ function loadImportedGame(saveObj, saveString) {
try { try {
loadAllGangs(tempSaveObj.AllGangsSave); loadAllGangs(tempSaveObj.AllGangsSave);
} catch(e) { } catch(e) {
console.log("ERROR: Failed to parse AllGangsSave: " + e); console.error(`Failed to parse AllGangsSave: {e}`);
throw e;
} }
} }
} catch(e) { } catch(e) {