Implemented Corporation Research Tree UI using Treant library

This commit is contained in:
danielyxie 2018-12-15 15:31:21 -08:00
parent db252bf25b
commit 1095438075
22 changed files with 4899 additions and 2050 deletions

@ -1,6 +1,13 @@
@import "mixins";
@import "theme";
/**
* Styling for Corporations
* The names/labels refer to "Company Management", which was the old name
* for the mechanic before it got changed to avoid confusion with normal
* companies
*/
#cmpy-mgmt-container p,
#cmpy-mgmt-container a,
#cmpy-mgmt-container div {

38
css/treant.css Normal file

@ -0,0 +1,38 @@
/* required LIB STYLES */
/* .Treant se automatski dodaje na svaki chart conatiner */
.Treant { position: relative; overflow: hidden; padding: 0 !important; }
.Treant > .node,
.Treant > .pseudo { position: absolute; display: block; visibility: hidden; }
.Treant.Treant-loaded .node,
.Treant.Treant-loaded .pseudo { visibility: visible; }
.Treant > .pseudo { width: 0; height: 0; border: none; padding: 0; }
.Treant .collapse-switch { width: 3px; height: 3px; display: block; border: 1px solid black; position: absolute; top: 1px; right: 1px; cursor: pointer; }
.Treant .collapsed .collapse-switch { background-color: #868DEE; }
.Treant > .node img { border: none; float: left; }
.Treant > .node {
cursor: pointer;
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #E8E8E3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0,0,0,.5);
font-size: 12px;
}
.Treant > .researched {
background-color: #444;
}
.Treant > .locked > div {
color: red;
pointer-events: none;
}
.Treant > .node > div {
font-size: 12px;
}
.Treant > .unlocked:hover {
background-color: #666;
}

2933
dist/engine.bundle.js vendored

File diff suppressed because it is too large Load Diff

69
dist/engine.css vendored

@ -1870,6 +1870,12 @@ button {
/* COLORS */
/* Attributes */
/**
* Styling for Corporations
* The names/labels refer to "Company Management", which was the old name
* for the mechanic before it got changed to avoid confusion with normal
* companies
*/
#cmpy-mgmt-container p,
#cmpy-mgmt-container a,
#cmpy-mgmt-container div {
@ -2094,5 +2100,68 @@ button {
margin: 1px;
padding: 1px; }
/* required LIB STYLES */
/* .Treant se automatski dodaje na svaki chart conatiner */
.Treant {
position: relative;
overflow: hidden;
padding: 0 !important; }
.Treant > .node,
.Treant > .pseudo {
position: absolute;
display: block;
visibility: hidden; }
.Treant.Treant-loaded .node,
.Treant.Treant-loaded .pseudo {
visibility: visible; }
.Treant > .pseudo {
width: 0;
height: 0;
border: none;
padding: 0; }
.Treant .collapse-switch {
width: 3px;
height: 3px;
display: block;
border: 1px solid black;
position: absolute;
top: 1px;
right: 1px;
cursor: pointer; }
.Treant .collapsed .collapse-switch {
background-color: #868DEE; }
.Treant > .node img {
border: none;
float: left; }
.Treant > .node {
cursor: pointer;
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #E8E8E3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
font-size: 12px; }
.Treant > .researched {
background-color: #444; }
.Treant > .locked > div {
color: red;
pointer-events: none; }
.Treant > .node > div {
font-size: 12px; }
.Treant > .unlocked:hover {
background-color: #666; }
/*# sourceMappingURL=engine.css.map*/

1129
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -1005,4 +1005,9 @@
</div>
</div>
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="dist/engine.bundle.js"></script></body>
<!-- Misc Scripts -->
<script src="/src/ThirdParty/raphael.min.js"></script>
<script src="/src/ThirdParty/Treant.js"></script>
</html>

5
package-lock.json generated

@ -12006,11 +12006,6 @@
"punycode": "1.4.1"
}
},
"treantjs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/treantjs/-/treantjs-1.0.0.tgz",
"integrity": "sha1-28PwU+aRz3AOZx/xfG5oySSoE6o="
},
"trim": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",

@ -32,7 +32,6 @@
"numeral": "2.0.6",
"sprintf-js": "^1.1.1",
"tapable": "^1.0.0",
"treantjs": "^1.0.0",
"uglifyjs-webpack-plugin": "^1.2.5",
"uuid": "^3.2.1",
"w3c-blob": "0.0.1"

@ -1,12 +1,17 @@
import { AllCorporationStates,
CorporationState } from "./CorporationState";
import { CorporationUnlockUpgrades } from "./CorporationUnlockUpgrades";
import { CorporationUpgrades } from "./CorporationUpgrades";
import { EmployeePositions } from "./EmployeePositions";
import { Industries,
IndustryStartingCosts,
IndustryDescriptions } from "./IndustryData";
IndustryDescriptions,
IndustryResearchTrees } from "./IndustryData";
import { IndustryUpgrades } from "./IndustryUpgrades";
import { Material } from "./Material";
import { MaterialSizes } from "./MaterialSizes";
import { Product } from "./Product";
import { ResearchMap } from "./ResearchMap";
import { BitNodeMultipliers } from "../BitNodeMultipliers";
import { Factions } from "../Faction/Factions";
@ -22,12 +27,14 @@ import { clearSelector } from "../../utils/uiHelp
import { Reviver,
Generic_toJSON,
Generic_fromJSON } from "../../utils/JSONReviver";
import { appendLineBreaks } from "../../utils/uiHelpers/appendLineBreaks";
import { createElement } from "../../utils/uiHelpers/createElement";
import { createPopup } from "../../utils/uiHelpers/createPopup";
import { formatNumber, generateRandomString } from "../../utils/StringHelperFunctions";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { isString } from "../../utils/helpers/isString";
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
import { removeElement } from "../../utils/uiHelpers/removeElement";
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
import { yesNoBoxCreate,
yesNoTxtInpBoxCreate,
@ -61,21 +68,19 @@ export const BribeToRepRatio = 1e9; //Bribe Value divided by this
export const ProductProductionCostRatio = 5; //Ratio of material cost of a product to its production cost
//Industry upgrades
//The structure is:
// [index in array, base price, price mult, benefit mult (if applicable), name, desc]
var IndustryUpgrades = {
"0": [0, 500e3, 1, 1.05,
"Coffee", "Provide your employees with coffee, increasing their energy by 5%."],
"1": [1, 1e9, 1.06, 1.03,
"AdVert.Inc", "Hire AdVert.Inc to advertise your company. Each level of " +
"this upgrade grants your company a static increase of 3 and 1 to its awareness and " +
"popularity, respectively. It will then increase your company's awareness by 1%, and its popularity " +
"by a random percentage between 1% and 3%. These effects are increased by other upgrades " +
"that increase the power of your advertising."]
}
// Delete Research Popup Box when clicking outside of it
$(document).mousedown(function(event) {
const boxId = "corporation-research-popup-box";
const contentId = "corporation-research-popup-box-content";
if (researchTreeBoxOpened) {
if ( $(event.target).closest("#" + contentId).get(0) == null ) {
// Delete the box
removeElement(researchTreeBox);
researchTreeBox = null;
researchTreeBoxOpened = false;
}
}
});
var empManualAssignmentModeActive = false;
function Industry(params={}) {
@ -1130,6 +1135,82 @@ Industry.prototype.getMarketFactor = function(mat) {
return mat.dmd * (100 - mat.cmp)/100;
}
// Returns a boolean indicating whether this Industry has the specified Research
Industry.prototype.hasResearch = function(name) {
const researchTree = IndustryResearchTrees[this.type];
const node = researchTree.findNode(name);
if (node == null) { return false; }
return node.researched;
}
// Create the Research Tree UI for this Industry
Industry.prototype.createResearchBox = function() {
const boxId = "corporation-research-popup-box";
if (researchTreeBoxOpened) {
// It's already opened, so delete it to refresh content
removeElementById(boxId);
researchTreeBox = null;
}
// New popup box
const researchTree = IndustryResearchTrees[this.type];
// Get the tree's markup (i.e. config) for Treant
const markup = researchTree.createTreantMarkup();
markup.chart.container = "#" + boxId + "-content";
markup.chart.nodeAlign = "BOTTOM";
markup.chart.rootOrientation = "WEST";
markup.chart.siblingSeparation = 40;
markup.chart.connectors = {
type: "step",
style: {
"arrow-end": "block-wide-long",
"stroke": "white",
"stroke-width": 2,
},
}
// 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
const treantTree = new Treant(markup);
// Add Event Listeners for all Nodes
const allResearch = researchTree.getAllNodes();
for (let i = 0; i < allResearch.length; ++i) {
// Get the Research object
const research = ResearchMap[allResearch[i]];
// Get the DOM Element to add a click listener to it
const sanitizedName = allResearch[i].replace(/\s/g, '');
const div = document.getElementById(sanitizedName + "-click-listener");
if (div == null) {
console.warn(`Could not find Research Tree div for ${sanitizedName}`);
continue;
}
div.addEventListener("click", () => {
if (this.sciResearch.qty >= research.cost) {
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;
return createResearchBox();
} else {
dialogBoxCreate(`You do not have enough Scientific Research for ${research.name}`);
}
});
}
researchTreeBoxOpened = true;
}
Industry.prototype.toJSON = function() {
return Generic_toJSON("Industry", this);
}
@ -2449,99 +2530,6 @@ Warehouse.fromJSON = function(value) {
Reviver.constructors.Warehouse = Warehouse;
//Corporation Unlock Upgrades
//Upgrades for entire corporation, unlocks features, either you have it or you dont
//The structure is [index in Corporation feature upgrades array, price ]
var CorporationUnlockUpgrades = {
//Lets you export goods
"0": [0, 20e9, "Export",
"Develop infrastructure to export your materials to your other facilities. " +
"This allows you to move materials around between different divisions and cities."],
//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. " +
"This allows you to purchase exactly however many materials you need for production."],
//Displays each material/product's demand
"2": [2, 5e9, "Market Research - Demand",
"Mine and analyze market data to determine the demand of all resources. " +
"The demand attribute, which affects sales, will be displayed for every material and product."],
//Display's each material/product's competition
"3": [3, 5e9, "Market Data - Competition",
"Mine and analyze market data to determine how much competition there is on the market " +
"for all resources. The competition attribute, which affects sales, will be displayed for " +
"for every material and product."],
"4": [4, 10e9, "VeChain",
"Use AI and blockchain technology to identify where you can improve your supply chain systems. " +
"This upgrade will allow you to view a wide array of useful statistics about your " +
"Corporation."]
}
//Corporation Upgrades
//Upgrades for entire corporation, levelable upgrades
//The structure is [index in Corporation upgrades array, base price, price mult, benefit mult (additive),
// name, desc]
var CorporationUpgrades = {
//Smart factories, increases production
"0": [0, 2e9, 1.07, 0.03,
"Smart Factories", "Advanced AI automatically optimizes the operation and productivity " +
"of factories. Each level of this upgrade increases your global production by 3% (additive)."],
//Smart warehouses, increases storage size
"1": [1, 2e9, 1.07, .1,
"Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " +
"Each level of this upgrade increases your global warehouse storage size by 10% (additive)."],
//Advertise through dreams, passive popularity/ awareness gain
"2": [2, 8e9, 1.09, .001,
"DreamSense", "Use DreamSense LCC Technologies to advertise your corporation " +
"to consumers through their dreams. Each level of this upgrade provides a passive " +
"increase in awareness of all of your companies (divisions) by 0.004 / market cycle," +
"and in popularity by 0.001 / market cycle. A market cycle is approximately " +
"20 seconds."],
//Makes advertising more effective
"3": [3, 4e9, 1.12, 0.005,
"Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " +
"firm. Each level of this upgrades increases the effectiveness of your " +
"advertising by 0.5% (additive)."],
//Augmentation for employees, increases cre
"4": [4, 1e9, 1.06, 0.1,
"Nuoptimal Nootropic Injector Implants", "Purchase the Nuoptimal Nootropic " +
"Injector augmentation for your employees. Each level of this upgrade " +
"globally increases the creativity of your employees by 10% (additive)."],
//Augmentation for employees, increases cha
"5": [5, 1e9, 1.06, 0.1,
"Speech Processor Implants", "Purchase the Speech Processor augmentation for your employees. " +
"Each level of this upgrade globally increases the charisma of your employees by 10% (additive)."],
//Augmentation for employees, increases int
"6": [6, 1e9, 1.06, 0.1,
"Neural Accelerators", "Purchase the Neural Accelerator augmentation for your employees. " +
"Each level of this upgrade globally increases the intelligence of your employees " +
"by 10% (additive)."],
//Augmentation for employees, increases eff
"7": [7, 1e9, 1.06, 0.1,
"FocusWires", "Purchase the FocusWire augmentation for your employees. Each level " +
"of this upgrade globally increases the efficiency of your employees by 10% (additive)."],
//Improves sales of materials/products
"8": [8, 1e9, 1.08, 0.01,
"ABC SalesBots", "Always Be Closing. Purchase these robotic salesmen to increase the amount of " +
"materials and products you sell. Each level of this upgrade globally increases your sales " +
"by 1% (additive)."],
//Improves scientific research rate
"9": [9, 5e9, 1.07, 0.05,
"Project Insight", "Purchase 'Project Insight', a R&D service provided by the secretive " +
"Fulcrum Technologies. Each level of this upgrade globally increases the amount of " +
"Scientific Research you produce by 5% (additive)."],
}
function Corporation(params={}) {
this.name = params.name ? params.name : "The Corporation";
@ -2857,6 +2845,12 @@ var companyManagementDiv, companyManagementHeaderTabs, companyManagementPanel,
industryWarehousePanel, industrySmartSupplyCheckbox, industryWarehouseStorageText,
industryWarehouseUpgradeSizeButton, industryWarehouseStateText,
industryWarehouseMaterials, industryWarehouseProducts,
// Research Tree
researchTreeBoxOpened = false,
researchTreeBox,
// Tabs
headerTabs, cityTabs;
Corporation.prototype.createUI = function() {
companyManagementDiv = createElement("div", {
@ -3619,8 +3613,16 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
}
//Left and right panels
var leftPanel = createElement("div", {class:"cmpy-mgmt-industry-left-panel"});
var rightPanel = createElement("div", {class:"cmpy-mgmt-industry-right-panel"});
var leftPanel = createElement("div", {
class: "cmpy-mgmt-industry-left-panel",
overflow: "visible",
padding: "2px",
});
var rightPanel = createElement("div", {
class: "cmpy-mgmt-industry-right-panel",
overflow: "visible",
padding: "2px",
});
companyManagementPanel.appendChild(leftPanel);
companyManagementPanel.appendChild(rightPanel);
@ -4158,7 +4160,7 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
var info = createElement("h2", {
display:"inline-block", width:"40%", fontSize:"15px",
innerText: positions[i] + "(" + counts[i] + ")",
tooltipleft: descriptions[i]
tooltip: descriptions[i]
});
var plusBtn = createElement("a", {
class: unassignedCount > 0 ? "a-link-button" : "a-link-button-inactive",
@ -4268,13 +4270,20 @@ Corporation.prototype.updateDivisionContent = function(division) {
"production multiplier of your entire Division.");
}
}));
industryOverviewText.appendChild(createElement("br"));
appendLineBreaks(industryOverviewText, 2);
industryOverviewText.appendChild(createElement("p", {
display:"inline-block",
innerText:"Scientific Research: " + formatNumber(division.sciResearch.qty, 3),
tooltip:"Scientific Research increases the quality of the materials and " +
"products that you produce."
}));
industryOverviewText.appendChild(createElement("div", {
class: "help-tip",
innerText: "Research",
clickListener: () => {
division.createResearchBox();
}
}));
//Office and Employee List
var office = division.offices[currentCityUi];
@ -4400,6 +4409,9 @@ Corporation.prototype.clearUI = function() {
industryWarehouseMaterials = null;
industryWarehouseProducts = null;
researchTreeBoxOpened = false;
researchTreeBox = null;
companyManagementHeaderTabs = null;
headerTabs = null;
cityTabs = null;

@ -0,0 +1,31 @@
import { IMap } from "../types";
// Corporation Unlock Upgrades
// Upgrades for entire corporation, unlocks features, either you have it or you dont
// The data structure is an array with the following format:
// [index in Corporation feature upgrades array, price, name, description]
export const CorporationUnlockUpgrades: IMap<any[]> = {
//Lets you export goods
"0": [0, 20e9, "Export",
"Develop infrastructure to export your materials to your other facilities. " +
"This allows you to move materials around between different divisions and cities."],
//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. " +
"This allows you to purchase exactly however many materials you need for production."],
//Displays each material/product's demand
"2": [2, 5e9, "Market Research - Demand",
"Mine and analyze market data to determine the demand of all resources. " +
"The demand attribute, which affects sales, will be displayed for every material and product."],
//Display's each material/product's competition
"3": [3, 5e9, "Market Data - Competition",
"Mine and analyze market data to determine how much competition there is on the market " +
"for all resources. The competition attribute, which affects sales, will be displayed for " +
"for every material and product."],
"4": [4, 10e9, "VeChain",
"Use AI and blockchain technology to identify where you can improve your supply chain systems. " +
"This upgrade will allow you to view a wide array of useful statistics about your " +
"Corporation."]
}

@ -0,0 +1,65 @@
import { IMap } from "../types";
// Corporation Upgrades
// Upgrades for entire corporation, levelable upgrades
// The data structure is an array with the following format
// [index in Corporation upgrades array, base price, price mult, benefit mult (additive), name, desc]
export const CorporationUpgrades: IMap<any[]> = {
//Smart factories, increases production
"0": [0, 2e9, 1.07, 0.03,
"Smart Factories", "Advanced AI automatically optimizes the operation and productivity " +
"of factories. Each level of this upgrade increases your global production by 3% (additive)."],
//Smart warehouses, increases storage size
"1": [1, 2e9, 1.07, .1,
"Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " +
"Each level of this upgrade increases your global warehouse storage size by 10% (additive)."],
//Advertise through dreams, passive popularity/ awareness gain
"2": [2, 8e9, 1.09, .001,
"DreamSense", "Use DreamSense LCC Technologies to advertise your corporation " +
"to consumers through their dreams. Each level of this upgrade provides a passive " +
"increase in awareness of all of your companies (divisions) by 0.004 / market cycle," +
"and in popularity by 0.001 / market cycle. A market cycle is approximately " +
"20 seconds."],
//Makes advertising more effective
"3": [3, 4e9, 1.12, 0.005,
"Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " +
"firm. Each level of this upgrades increases the effectiveness of your " +
"advertising by 0.5% (additive)."],
//Augmentation for employees, increases cre
"4": [4, 1e9, 1.06, 0.1,
"Nuoptimal Nootropic Injector Implants", "Purchase the Nuoptimal Nootropic " +
"Injector augmentation for your employees. Each level of this upgrade " +
"globally increases the creativity of your employees by 10% (additive)."],
//Augmentation for employees, increases cha
"5": [5, 1e9, 1.06, 0.1,
"Speech Processor Implants", "Purchase the Speech Processor augmentation for your employees. " +
"Each level of this upgrade globally increases the charisma of your employees by 10% (additive)."],
//Augmentation for employees, increases int
"6": [6, 1e9, 1.06, 0.1,
"Neural Accelerators", "Purchase the Neural Accelerator augmentation for your employees. " +
"Each level of this upgrade globally increases the intelligence of your employees " +
"by 10% (additive)."],
//Augmentation for employees, increases eff
"7": [7, 1e9, 1.06, 0.1,
"FocusWires", "Purchase the FocusWire augmentation for your employees. Each level " +
"of this upgrade globally increases the efficiency of your employees by 10% (additive)."],
//Improves sales of materials/products
"8": [8, 1e9, 1.08, 0.01,
"ABC SalesBots", "Always Be Closing. Purchase these robotic salesmen to increase the amount of " +
"materials and products you sell. Each level of this upgrade globally increases your sales " +
"by 1% (additive)."],
//Improves scientific research rate
"9": [9, 5e9, 1.07, 0.05,
"Project Insight", "Purchase 'Project Insight', a R&D service provided by the secretive " +
"Fulcrum Technologies. Each level of this upgrade globally increases the amount of " +
"Scientific Research you produce by 5% (additive)."],
}

@ -1,5 +1,6 @@
import { ResearchTree } from "./ResearchTree";
import { BaseResearchTree } from "./data/BaseResearchTree";
import { BaseResearchTree,
getBaseResearchTreeCopy } from "./data/BaseResearchTree";
import { numeralWrapper } from "../ui/numeralFormat";
@ -105,18 +106,18 @@ 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> = {
Energy: BaseResearchTree,
Utilities: BaseResearchTree,
Agriculture: BaseResearchTree,
Fishing: BaseResearchTree,
Mining: BaseResearchTree,
Food: BaseResearchTree,
Tobacco: BaseResearchTree,
Chemical: BaseResearchTree,
Pharmaceutical: BaseResearchTree,
Computer: BaseResearchTree,
Robotics: BaseResearchTree,
Software: BaseResearchTree,
Healthcare: BaseResearchTree,
RealEstate: BaseResearchTree,
Energy: getBaseResearchTreeCopy(),
Utilities: getBaseResearchTreeCopy(),
Agriculture: getBaseResearchTreeCopy(),
Fishing: getBaseResearchTreeCopy(),
Mining: getBaseResearchTreeCopy(),
Food: getBaseResearchTreeCopy(),
Tobacco: getBaseResearchTreeCopy(),
Chemical: getBaseResearchTreeCopy(),
Pharmaceutical: getBaseResearchTreeCopy(),
Computer: getBaseResearchTreeCopy(),
Robotics: getBaseResearchTreeCopy(),
Software: getBaseResearchTreeCopy(),
Healthcare: getBaseResearchTreeCopy(),
RealEstate: getBaseResearchTreeCopy(),
}

@ -0,0 +1,15 @@
import { IMap } from "../types";
// Industry upgrades
// The data structure is an array with the following format:
// [index in array, base price, price mult, benefit mult (if applicable), name, desc]
export const IndustryUpgrades: IMap<any[]> = {
"0": [0, 500e3, 1, 1.05,
"Coffee", "Provide your employees with coffee, increasing their energy by 5%."],
"1": [1, 1e9, 1.06, 1.03,
"AdVert.Inc", "Hire AdVert.Inc to advertise your company. Each level of " +
"this upgrade grants your company a static increase of 3 and 1 to its awareness and " +
"popularity, respectively. It will then increase your company's awareness by 1%, and its popularity " +
"by a random percentage between 1% and 3%. These effects are increased by other upgrades " +
"that increase the power of your advertising."]
}

@ -8,7 +8,8 @@ import { ResearchMap } from "./ResearchMap";
interface IConstructorParams {
children?: Node[];
data: string;
cost: number;
text: string;
parent?: Node | null;
}
@ -18,20 +19,28 @@ export class Node {
// child Nodes
children: Node[] = [];
// Name of the Research held in this Node
data: string = "";
// How much Scientific Research is needed for this
// Necessary to show it on the UI
cost: number = 0;
// Whether or not this Research has been unlocked
researched: boolean = false;
// Parent node in the tree
// The parent node defines the prerequisite Research (there can only be one)
// Set as null for no prerequisites
parent: Node | null = null;
// Name of the Research held in this Node
text: string = "";
constructor(p: IConstructorParams) {
if (ResearchMap[p.data] == null) {
throw new Error(`Invalid Research name used when constructing ResearchTree Node: ${p.data}`);
if (ResearchMap[p.text] == null) {
throw new Error(`Invalid Research name used when constructing ResearchTree Node: ${p.text}`);
}
this.data = p.data;
this.text = p.text;
this.cost = p.cost;
if (p.children && p.children.length > 0) {
this.children = p.children;
@ -47,6 +56,48 @@ export class Node {
n.parent = this;
}
// Return an object that describes a TreantJS-compatible markup/config for this Node
// See: http://fperucic.github.io/treant-js/
createTreantMarkup(): object {
const childrenArray = [];
for (let i = 0; i < this.children.length; ++i) {
childrenArray.push(this.children[i].createTreantMarkup());
}
// Determine what css class this Node should have in the diagram
let htmlClass: string = "";
if (this.researched) {
htmlClass = "researched";
} else if (this.parent && this.parent.researched === false) {
htmlClass = "locked";
} else {
htmlClass = "unlocked";
}
const sanitizedName: string = this.text.replace(/\s/g, '');
return {
children: childrenArray,
HTMLclass: htmlClass,
innerHTML: `<div id="${sanitizedName}-click-listener">${this.text}<br>${this.cost} Scientific Research</div>`,
text: { name: this.text },
}
}
// Recursive function for finding a Node with the specified text
findNode(text: string): Node | null {
// Is this the Node?
if (this.text === text) { return this; }
// Recursively search chilren
let res = null;
for (let i = 0; i < this.children.length; ++i) {
res = this.children[i].findNode(text);
if (res != null) { return res; }
}
return null;
}
setParent(n: Node) {
this.parent = n;
}
@ -59,6 +110,70 @@ export class ResearchTree {
constructor() {}
// Return an object that contains a Tree markup for TreantJS (using the JSON approach)
// See: http://fperucic.github.io/treant-js/
createTreantMarkup(): object {
if (this.root == null) { return {}; }
const treeMarkup = this.root.createTreantMarkup();
return {
chart: {
container: "",
},
nodeStructure: treeMarkup,
};
}
// Gets an array with the 'text' values of ALL Nodes in the Research Tree
getAllNodes(): string[] {
const res: string[] = [];
const queue: Node[] = [];
if (this.root == null) { return res; }
queue.push(this.root);
while (queue.length !== 0) {
const node: Node | undefined = queue.shift();
if (node == null) { continue; }
res.push(node.text);
for (let i = 0; i < node.children.length; ++i) {
queue.push(node.children[i]);
}
}
return res;
}
// Search for a Node with the given name ('text' property on the Node)
// Returns 'null' if it cannot be found
findNode(name: string): Node | null {
if (this.root == null) { return null; }
return this.root.findNode(name);
}
// Marks a Node as researched
research(name: string): void {
if (this.root == null) { return; }
const queue: Node[] = [];
queue.push(this.root);
while (queue.length !== 0) {
const node: Node | undefined = queue.shift();
if (node == null) { continue; }
if (node.text === name) {
node.researched = true;
}
for (let i = 0; i < node.children.length; ++i) {
queue.push(node.children[i]);
}
}
}
// Set the tree's Root Node
setRoot(root: Node): void {
this.root = root;
}

@ -1,25 +1,37 @@
// Defines the ResearchTree that is common to all Corporation Industries
// i.e. all Industries have these types of Research available to unlock
import { Research } from "../Research";
import { ResearchMap } from "../ResearchMap";
import { ResearchTree,
Node } from "../ResearchTree";
export const BaseResearchTree: ResearchTree = new ResearchTree();
const rootNode = new Node({data: "Hi-Tech R&D Laboratory"});
const autoBrew = new Node({data: "AutoBrew"});
const autoParty = new Node({data: "AutoPartyManager"});
const autoDrugs = new Node({data: "Automatic Drug Administration"});
const cph4 = new Node({data: "CPH4 Injections"});
const drones = new Node({data: "Drones"});
const dronesAssembly = new Node({data: "Drones - Assembly"});
const dronesTransport = new Node({data: "Drones - Transport"});
const goJuice = new Node({data: "Go-Juice"});
const joywire = new Node({data: "JoyWire"});
const marketta1 = new Node({data: "Market-TA.I"});
const marketta2 = new Node({data: "Market-TA.II"});
const overclock = new Node({data: "Overclock"});
const scAssemblers = new Node({data: "Self-Correcting Assemblers"});
const stimu = new Node({data: "Sti.mu"});
function makeNode(name: string): Node {
const research: Research | null = ResearchMap[name];
if (research == null) {
throw new Error(`Invalid research name: ${name}`);
}
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);

1
src/ThirdParty/README.md vendored Normal file

@ -0,0 +1 @@
Third Party Code/Modules that aren't installed using NPM

2171
src/ThirdParty/Treant.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
src/ThirdParty/raphael.min.js vendored Normal file

File diff suppressed because one or more lines are too long

@ -91,6 +91,7 @@ import "../css/missions.scss";
import "../css/companymanagement.scss";
import "../css/bladeburner.scss";
import "../css/gang.scss";
import "../css/treant.css";
/* Shortcuts to navigate through the game
* Alt-t - Terminal

@ -1007,4 +1007,9 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
</div>
</div>
</body>
<!-- Misc Scripts -->
<script src="/src/ThirdParty/raphael.min.js"></script>
<script src="/src/ThirdParty/Treant.js"></script>
</html>

@ -53,6 +53,7 @@ interface ICreateElementStyleOptions {
margin?: string;
marginLeft?: string;
marginTop?: string;
overflow?: string;
padding?: string;
position?: string;
visibility?: string;
@ -202,6 +203,9 @@ function setElementStyle(el: HTMLElement, params: ICreateElementStyleOptions) {
if (params.position !== undefined) {
el.style.position = params.position;
}
if (params.overflow !== undefined) {
el.style.overflow = params.overflow;
}
}
function setElementTooltip(el: HTMLElement, params: ICreateElementTooltipOptions) {

@ -1,28 +1,38 @@
import { createElement } from "./createElement";
import { getElementById } from "./getElementById";
interface ICreatePopupOptions {
backgroundColor?: string;
}
/**
* Creates the necessary DOM elements to present an in-game popup to the player.
* @param id The (hopefully) unique identifier for the popup container.
* @param elems The collection of HTML Elements to show within the popup.
*/
export function createPopup(id: string, elems: HTMLElement[]) {
export function createPopup(id: string, elems: HTMLElement[], options: ICreatePopupOptions={}) {
const container: HTMLDivElement = createElement("div", {
class: "popup-box-container",
display: "flex",
id,
}) as HTMLDivElement;
class: "popup-box-container",
display: "flex",
id: id,
}) as HTMLDivElement;
const content: HTMLElement = createElement("div", {
class: "popup-box-content",
id: `${id}-content`,
});
class: "popup-box-content",
id: `${id}-content`,
});
for (const elem of elems) {
content.appendChild(elem);
}
// Configurable Options
if (options.backgroundColor) {
content.style.backgroundColor = options.backgroundColor;
}
container.appendChild(content);
getElementById("entire-game-container")
.appendChild(container);
getElementById("entire-game-container").appendChild(container);
return container;
}