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 {
background-color: #444;
background-color: #666;
pointer-events: none;
font-size: 16px;
}
.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; }
.Treant > .researched {
background-color: #444; }
background-color: #666;
pointer-events: none;
font-size: 16px; }
.Treant > .locked > div {
color: red;

@ -119,6 +119,7 @@ function Industry(params={}) {
this.type = params.type ? params.type : 0;
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
//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
Industry.prototype.hasResearch = function(name) {
return (this.researched[name] === true);
}
Industry.prototype.updateResearchTree = function() {
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
Industry.prototype.getAdvertisingMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getAdvertisingMultiplier();
}
Industry.prototype.getEmployeeChaMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeChaMultiplier();
}
Industry.prototype.getEmployeeCreMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeCreMultiplier();
}
Industry.prototype.getEmployeeEffMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeEffMultiplier();
}
Industry.prototype.getEmployeeIntMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getEmployeeIntMultiplier();
}
Industry.prototype.getProductionMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getProductionMultiplier();
}
Industry.prototype.getSalesMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getSalesMultiplier();
}
Industry.prototype.getScientificResearchMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getScientificResearchMultiplier();
}
Industry.prototype.getStorageMultiplier = function() {
this.updateResearchTree();
return IndustryResearchTrees[this.type].getStorageMultiplier();
}
@ -1214,8 +1236,10 @@ Industry.prototype.createResearchBox = function() {
researchTreeBox = null;
}
this.updateResearchTree();
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" });
@ -1257,8 +1281,8 @@ Industry.prototype.createResearchBox = function() {
this.sciResearch.qty -= research.cost;
// Get the Node from the Research Tree and set its 'researched' property
const node = researchTree.findNode(allResearch[i]);
node.researched = true;
researchTree.research(allResearch[i]);
this.researched[allResearch[i]] = true;
return this.createResearchBox();
} else {
@ -3630,13 +3654,18 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
"per second before taxes.";
const txt = createElement("p", { innerHTML: descText, });
let allocateBtn;
const dividendPercentInput = createElement("input", {
margin: "5px",
placeholder: "Dividend %",
type: "number",
onkeyup: (e) => {
e.preventDefault();
if (e.keyCode === 13) {allocateBtn.click();}
}
});
const allocateBtn = createElement("button", {
allocateBtn = createElement("button", {
class: "std-button",
display: "inline-block",
innerText: "Allocate Dividend Percentage",
@ -3653,17 +3682,14 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
}
});
const cancelBtn = createElement("button", {
const cancelBtn = createPopupCloseButton(popupId, {
class: "std-button",
display: "inline-block",
innerText: "Cancel",
clickListener: () => {
removeElementById(popupId);
return false;
}
})
});
createPopup(popupId, [txt, dividendPercentInput, allocateBtn, cancelBtn]);
dividendPercentInput.focus();
},
});
companyManagementPanel.appendChild(issueDividends);
@ -3971,7 +3997,10 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
fontSize:"14px",
}));
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) {
var upgrade = IndustryUpgrades[i.toString()];
if (upgrade == null) {
@ -4300,72 +4329,74 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
industryEmployeePanel.appendChild(industryOfficeUpgradeSizeButton);
//Throw Office Party
industryEmployeePanel.appendChild(createElement("a", {
class:"a-link-button", display:"inline-block", innerText:"Throw Party",
fontSize:"13px",
tooltip:"Throw an office party to increase your employee's morale and happiness",
clickListener:()=>{
var popupId = "cmpy-mgmt-throw-office-party-popup";
var txt = createElement("p", {
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 confirmBtn;
var input = createElement("input", {
type:"number", margin:"5px", placeholder:"$ / employee",
inputListener:()=>{
if (isNaN(input.value) || input.value < 0) {
totalCostTxt.innerText = "Invalid value entered!"
} else {
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!");
if (!division.hasResearch("AutoPartyManager")) {
industryEmployeePanel.appendChild(createElement("a", {
class:"a-link-button", display:"inline-block", innerText:"Throw Party",
fontSize:"13px",
tooltip:"Throw an office party to increase your employee's morale and happiness",
clickListener:()=>{
var popupId = "cmpy-mgmt-throw-office-party-popup";
var txt = createElement("p", {
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 confirmBtn;
var input = createElement("input", {
type:"number", margin:"5px", placeholder:"$ / employee",
inputListener:()=>{
if (isNaN(input.value) || input.value < 0) {
totalCostTxt.innerText = "Invalid value entered!"
} 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);
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();}
}
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]);
}
}));
});
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 {
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", {});
industryEmployeeInfo = createElement("p", {margin:"4px", padding:"4px"});

@ -1,9 +1,10 @@
import { ResearchTree } from "./ResearchTree";
import { BaseResearchTree,
getBaseResearchTreeCopy } from "./data/BaseResearchTree";
import { getBaseResearchTreeCopy } from "./data/BaseResearchTree";
import { numeralWrapper } from "../ui/numeralFormat";
import { Reviver } from "../../utils/JSONReviver";
interface IIndustryMap<T> {
Energy: 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
// ResearchTree object
export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
export let IndustryResearchTrees: IIndustryMap<ResearchTree> = {
Energy: getBaseResearchTreeCopy(),
Utilities: getBaseResearchTreeCopy(),
Agriculture: getBaseResearchTreeCopy(),
@ -121,3 +122,7 @@ export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
Healthcare: 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,
// not an actual Research object. The name can be used to obtain a reference
// to the corresponding Research object using the ResearchMap
import { Research } from "./Research";
import { ResearchMap } from "./ResearchMap";
@ -17,6 +16,7 @@ interface IConstructorParams {
}
export class Node {
// All child Nodes in the tree
// The Research held in this Node is a prerequisite for all Research in
// child Nodes
@ -37,7 +37,7 @@ export class Node {
// Name of the Research held in this Node
text: string = "";
constructor(p: IConstructorParams) {
constructor(p: IConstructorParams = {cost: 0, text: ""}) {
if (ResearchMap[p.text] == null) {
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
// The root node in a Research Tree must always be the "Hi-Tech R&D Laboratory"
export class ResearchTree {

@ -5,9 +5,6 @@ import { ResearchMap } from "../ResearchMap";
import { ResearchTree,
Node } from "../ResearchTree";
export const BaseResearchTree: ResearchTree = new ResearchTree();
function makeNode(name: string): Node {
const research: Research | null = ResearchMap[name];
if (research == null) {
@ -17,43 +14,46 @@ function makeNode(name: string): Node {
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 {
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";
import {Companies, loadCompanies} from "./Company/Companies";
import {CompanyPosition} from "./Company/CompanyPosition";
import { IndustryResearchTrees,
loadIndustryResearchTrees } from "./Corporation/IndustryData";
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
import { Factions,
@ -36,19 +38,20 @@ import Decimal from "decimal.js";
let saveObject = new BitburnerSaveObject();
function BitburnerSaveObject() {
this.PlayerSave = "";
this.AllServersSave = "";
this.CompaniesSave = "";
this.FactionsSave = "";
this.SpecialServerIpsSave = "";
this.AliasesSave = "";
this.GlobalAliasesSave = "";
this.MessagesSave = "";
this.StockMarketSave = "";
this.SettingsSave = "";
this.FconfSettingsSave = "";
this.VersionSave = "";
this.AllGangsSave = "";
this.PlayerSave = "";
this.AllServersSave = "";
this.CompaniesSave = "";
this.FactionsSave = "";
this.SpecialServerIpsSave = "";
this.AliasesSave = "";
this.GlobalAliasesSave = "";
this.MessagesSave = "";
this.StockMarketSave = "";
this.SettingsSave = "";
this.FconfSettingsSave = "";
this.VersionSave = "";
this.AllGangsSave = "";
this.CorporationResearchTreesSave = "";
}
BitburnerSaveObject.prototype.saveGame = function(db) {
@ -260,6 +263,7 @@ function loadImportedGame(saveObj, saveString) {
var tempMessages = null;
var tempStockMarket = null;
var tempAllGangs = null;
let tempCorporationResearchTrees = null;
//Check to see if the imported save file can be parsed. If any
//errors are caught it will fail
@ -332,7 +336,8 @@ function loadImportedGame(saveObj, saveString) {
try {
loadAllGangs(tempSaveObj.AllGangsSave);
} catch(e) {
console.log("ERROR: Failed to parse AllGangsSave: " + e);
console.error(`Failed to parse AllGangsSave: {e}`);
throw e;
}
}
} catch(e) {