diff --git a/.gitignore b/.gitignore index 4147856a2..4e1caf1bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Changelog.txt Netburner.txt -README.md \ No newline at end of file +README.md +/node_modules \ No newline at end of file diff --git a/css/interactivetutorial.css b/css/interactivetutorial.css index 12990bb96..95e51b380 100644 --- a/css/interactivetutorial.css +++ b/css/interactivetutorial.css @@ -40,6 +40,7 @@ -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; + background-color:black; } #interactive-tutorial-exit { @@ -65,4 +66,3 @@ text-decoration: none; cursor: pointer; } - diff --git a/css/menupages.css b/css/menupages.css index 3d8d98612..ac67756af 100644 --- a/css/menupages.css +++ b/css/menupages.css @@ -16,6 +16,42 @@ } /* Script Editor */ +#script-editor-container { + background-color:transparent; +} +#javascript-editor { + margin: 10px; + + height: 80%; + width: 100%; + margin-left: 6px; + + padding-left: 6px; + padding-top: 6px; + padding-bottom: 6px; + + border: 2px solid var(--my-highlight-color); + z-index: 1; + font-family: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman'; +} + +#javascript-editor textarea { + color: var(--my-font-color); +} + +.ace_line, +.ace_line * { + color: var(--my-font-color); + background-color:transparent; + margin:0px; + padding:0px; +} + +.ace_text-input { + font-size:16px; + background-color:transparent; +} + /* This temp element is used for auto adjusting filename field */ .tmp-element { visibility: hidden; @@ -56,6 +92,7 @@ #script-editor-wrapper { height:100%; width: 70%; + background:transparent; } #script-editor-filename-wrapper { @@ -103,28 +140,6 @@ color: #ffffff; } -#script-editor-text { - color: var(--my-font-color); - height: 80%; - width: 100%; - margin-left: 6px; - - padding-left: 6px; - padding-top: 6px; - padding-bottom: 6px; - - border: 2px solid var(--my-highlight-color); - -webkit-box-shadow: - inset 0 0 8px rgba(0,0,0,0.1), - 0 0 16px rgba(0,0,0,0.1); - -moz-box-shadow: - inset 0 0 8px rgba(0,0,0,0.1), - 0 0 16px rgba(0,0,0,0.1); - box-shadow: - inset 0 0 8px rgba(0,0,0,0.1), - 0 0 16px rgba(0,0,0,0.1); -} - /* Active scripts */ .active-scripts-list { list-style-type: none; @@ -261,6 +276,7 @@ box-shadow: 1px 1px 3px #000; margin: 4px; padding: 4px; + background-color:black; } .active-scripts-button:hover, @@ -569,6 +585,7 @@ div.faction-clear { color: var(--my-font-color); padding: 4px; margin: 4px; + background-color:black; } .stock-market-buy-sell-button { diff --git a/css/popupboxes.css b/css/popupboxes.css index 9d9ad0b17..d84c84fd1 100644 --- a/css/popupboxes.css +++ b/css/popupboxes.css @@ -7,6 +7,7 @@ top: 0; width: 100%; height: 100%; + overflow:auto; background-color: rbga(var(--my-background-color), 0.4); } @@ -16,7 +17,6 @@ padding: 12px; border: 5px solid var(--my-highlight-color); width: 70%; - overflow: auto; /* Enable scroll if needed */ color: var(--my-font-color); } @@ -29,6 +29,7 @@ padding: 2px; margin: 6px; border: 1px solid white; + background-color:black; } .popup-box-button:hover, @@ -43,6 +44,12 @@ cursor: default; } +#yes-no-text-input-box-input { + color: var(--my-font-color); + border: 1px solid white; + background-color:black; +} + .dialog-box-container, #log-box-container { display: block; @@ -94,20 +101,6 @@ cursor: pointer; } -/* Purchase server box */ -#purchase-server-box-container { - transition: opacity 400ms ease-in; -} - -#purchase-server-box-input { - color: white; -} - -/* Purchase Augmentation Box */ -#purchase-augmentation-box-container { - transition: opacity 400ms ease-in; -} - /* Faction invitation box */ #faction-invitation-box-container { transition: opacity 400ms ease-in; diff --git a/css/styles.css b/css/styles.css index 74661d623..564b9522c 100644 --- a/css/styles.css +++ b/css/styles.css @@ -1,20 +1,20 @@ /** This removes all padding and margins as well as setting a default font size and family for the page **/ - :root{ --my-font-color: #66ff33; --my-background-color: #000000; --my-highlight-color: #ffffff; } - * { margin: 0; padding: 0; font-size: 16px; font-family: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman'; - /*background-color: #252527;*/ +} + +body { background-color: var(--my-background-color); } @@ -41,6 +41,10 @@ span { padding: 4px; } +#entire-game-container { + background-color:transparent; +} + /* Disable border highlight on elements */ input:focus, textarea:focus, @@ -346,6 +350,7 @@ a:link, a:visited { -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; height: 22px; + background-color:black; } #character-overview-save-button:hover, diff --git a/dist/bundle.js b/dist/bundle.js new file mode 100644 index 000000000..e6cdfabad --- /dev/null +++ b/dist/bundle.js @@ -0,0 +1,64355 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 4); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Player; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return loadPlayer; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Augmentations_js__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__BitNode_js__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Company_js__ = __webpack_require__(17); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Constants_js__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__CreateProgram_js__ = __webpack_require__(14); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Crimes_js__ = __webpack_require__(40); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__engine_js__ = __webpack_require__(4); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Faction_js__ = __webpack_require__(10); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Gang_js__ = __webpack_require__(29); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__Location_js__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__Server_js__ = __webpack_require__(6); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__ = __webpack_require__(11); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__SourceFile_js__ = __webpack_require__(30); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js__ = __webpack_require__(23); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_13__utils_decimal_js__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__ = __webpack_require__(2); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__utils_IPAddress_js__ = __webpack_require__(21); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__utils_JSONReviver_js__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__ = __webpack_require__(5); + + + + + + + + + + + + + + + + + + + + + +function PlayerObject() { + //Skills and stats + this.hacking_skill = 1; + + //Fighting + this.hp = 10; + this.max_hp = 10; + this.strength = 1; //Damage dealt + this.defense = 1; //Damage received + this.dexterity = 1; //Accuracy + this.agility = 1; //Dodge % + + //Labor stats + this.charisma = 1; + //Intelligence, perhaps? + + //Hacking multipliers + this.hacking_chance_mult = 1; //Increase through ascensions/augmentations + this.hacking_speed_mult = 1; //Decrease through ascensions/augmentations + this.hacking_money_mult = 1; //Increase through ascensions/augmentations. Can't go above 1 + this.hacking_grow_mult = 1; + + //Experience and multipliers + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.hacking_mult = 1; + this.strength_mult = 1; + this.defense_mult = 1; + this.dexterity_mult = 1; + this.agility_mult = 1; + this.charisma_mult = 1; + + this.hacking_exp_mult = 1; + this.strength_exp_mult = 1; + this.defense_exp_mult = 1; + this.dexterity_exp_mult = 1; + this.agility_exp_mult = 1; + this.charisma_exp_mult = 1; + + this.company_rep_mult = 1; + this.faction_rep_mult = 1; + + //Money + this.money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(1000); + this.total_money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(0); //Total money ever earned in this "simulation" + this.lifetime_money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(0); //Total money ever earned + + //IP Address of Starting (home) computer + this.homeComputer = ""; + + //Location information + this.city = __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12; + this.location = ""; + + //Company Information + this.companyName = ""; //Name of Company, equivalent to an object from Locations + this.companyPosition = ""; //CompanyPosition object + + //Servers + this.currentServer = ""; //IP address of Server currently being accessed through terminal + this.discoveredServers = []; //IP addresses of secret servers not in the network that you have discovered + this.purchasedServers = []; + this.hacknetNodes = []; + this.totalHacknetNodeProduction = 0; + + //Factions + this.factions = []; //Names of all factions player has joined + this.factionInvitations = []; //Outstanding faction invitations + + //Augmentations + this.queuedAugmentations = []; + this.augmentations = []; + + this.sourceFiles = []; + + //Crime statistics + this.numPeopleKilled = 0; + this.karma = 0; + + this.crime_money_mult = 1; + this.crime_success_mult = 1; + + //Flag to let the engine know the player is starting an action + // Current actions: hack, analyze + this.startAction = false; + this.actionTime = 0; + + //Flags/variables for working (Company, Faction, Creating Program, Taking Class) + this.isWorking = false; + this.workType = ""; + + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + this.workMoneyLossRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.createProgramName = ""; + + this.className = ""; + + this.crimeType = ""; + + this.timeWorked = 0; //in ms + this.timeNeededToCompleteWork = 0; + + this.work_money_mult = 1; + + //Hacknet Node multipliers + this.hacknet_node_money_mult = 1; + this.hacknet_node_purchase_cost_mult = 1; + this.hacknet_node_ram_cost_mult = 1; + this.hacknet_node_core_cost_mult = 1; + this.hacknet_node_level_cost_mult = 1; + + //Stock Market + this.hasWseAccount = false; + this.hasTixApiAccess = false; + + //Gang + this.gang = 0; + + //bitnode + this.bitNodeN = 1; + + //Flags for determining whether certain "thresholds" have been achieved + this.firstFacInvRecvd = false; + this.firstAugPurchased = false; + this.firstJobRecvd = false; + this.firstTimeTraveled = false; + this.firstProgramAvailable = false; + + //Used to store the last update time. + this.lastUpdate = 0; + this.totalPlaytime = 0; + this.playtimeSinceLastAug = 0; +}; + +PlayerObject.prototype.init = function() { + /* Initialize Player's home computer */ + var t_homeComp = new __WEBPACK_IMPORTED_MODULE_10__Server_js__["d" /* Server */](Object(__WEBPACK_IMPORTED_MODULE_16__utils_IPAddress_js__["a" /* createRandomIp */])(), "home", "Home PC", true, true, true, 8); + this.homeComputer = t_homeComp.ip; + this.currentServer = t_homeComp.ip; + Object(__WEBPACK_IMPORTED_MODULE_10__Server_js__["a" /* AddToAllServers */])(t_homeComp); + + this.getHomeComputer().programs.push(__WEBPACK_IMPORTED_MODULE_4__CreateProgram_js__["a" /* Programs */].NukeProgram); +} + +PlayerObject.prototype.increaseMultiplier = function(name, val) { + let mult = this[name]; + if (mult === null || mult === undefined) { + console.log("ERROR: Could not find this multiplier " + name); + return; + } + mult *= val; +} + +PlayerObject.prototype.prestigeAugmentation = function() { + var homeComp = this.getHomeComputer(); + this.currentServer = homeComp.ip; + this.homeComputer = homeComp.ip; + + this.numPeopleKilled = 0; + this.karma = 0; + + //Reset stats + this.hacking_skill = 1; + + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + this.charisma = 1; + + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(1000); + + this.city = __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12; + this.location = ""; + + this.companyName = ""; + this.companyPosition = ""; + + this.discoveredServers = []; + this.purchasedServers = []; + + this.factions = []; + this.factionInvitations = []; + + this.queuedAugmentations = []; + + this.startAction = false; + this.actionTime = 0; + + this.isWorking = false; + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + this.crimeType = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.lastUpdate = new Date().getTime(); + + this.playtimeSinceLastAug = 0; + + this.hacknetNodes.length = 0; + this.totalHacknetNodeProduction = 0; +} + +PlayerObject.prototype.prestigeSourceFile = function() { + var homeComp = this.getHomeComputer(); + this.currentServer = homeComp.ip; + this.homeComputer = homeComp.ip; + + this.numPeopleKilled = 0; + this.karma = 0; + + //Reset stats + this.hacking_skill = 1; + + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + this.charisma = 1; + + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(1000); + + this.city = __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12; + this.location = ""; + + this.companyName = ""; + this.companyPosition = ""; + + this.discoveredServers = []; + this.purchasedServers = []; + + this.factions = []; + this.factionInvitations = []; + + this.queuedAugmentations = []; + this.augmentations = []; + + this.startAction = false; + this.actionTime = 0; + + this.isWorking = false; + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + this.crimeType = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.lastUpdate = new Date().getTime(); + + this.hacknetNodes.length = 0; + this.totalHacknetNodeProduction = 0; + + //Gang + this.gang = null; + + //Reset Stock market + this.hasWseAccount = false; + this.hasTixApiAccess = false; + + this.playtimeSinceLastAug = 0; +} + +PlayerObject.prototype.getCurrentServer = function() { + return __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][this.currentServer]; +} + +PlayerObject.prototype.getHomeComputer = function() { + return __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][this.homeComputer]; +} + +//Calculates skill level based on experience. The same formula will be used for every skill +// At the maximum possible exp (MAX_INT = 9007199254740991), the hacking skill will be 1796 TODO REcalculate this +// Gets to level 1000 hacking skill at (TODO Determine this) +PlayerObject.prototype.calculateSkill = function(exp) { + return Math.max(Math.floor(32 * Math.log(exp + 534.5) - 200), 1); +} + +PlayerObject.prototype.updateSkillLevels = function() { + this.hacking_skill = Math.floor(this.calculateSkill(this.hacking_exp) * this.hacking_mult); + this.strength = Math.floor(this.calculateSkill(this.strength_exp) * this.strength_mult); + this.defense = Math.floor(this.calculateSkill(this.defense_exp) * this.defense_mult); + this.dexterity = Math.floor(this.calculateSkill(this.dexterity_exp) * this.dexterity_mult); + this.agility = Math.floor(this.calculateSkill(this.agility_exp) * this.agility_mult); + this.charisma = Math.floor(this.calculateSkill(this.charisma_exp) * this.charisma_mult); + + var ratio = this.hp / this.max_hp; + this.max_hp = Math.floor(10 + this.defense / 10); + Player.hp = Math.round(this.max_hp * ratio); +} + +PlayerObject.prototype.resetMultipliers = function() { + this.hacking_chance_mult = 1; + this.hacking_speed_mult = 1; + this.hacking_money_mult = 1; + this.hacking_grow_mult = 1; + + this.hacking_mult = 1; + this.strength_mult = 1; + this.defense_mult = 1; + this.dexterity_mult = 1; + this.agility_mult = 1; + this.charisma_mult = 1; + + this.hacking_exp_mult = 1; + this.strength_exp_mult = 1; + this.defense_exp_mult = 1; + this.dexterity_exp_mult = 1; + this.agility_exp_mult = 1; + this.charisma_exp_mult = 1; + + this.company_rep_mult = 1; + this.faction_rep_mult = 1; + + this.crime_money_mult = 1; + this.crime_success_mult = 1; + + this.hacknet_node_money_mult = 1; + this.hacknet_node_purchase_cost_mult = 1; + this.hacknet_node_ram_cost_mult = 1; + this.hacknet_node_core_cost_mult = 1; + this.hacknet_node_level_cost_mult = 1; + + this.work_money_mult = 1; +} + +//Calculates the chance of hacking a server +//The formula is: +// (2 * hacking_chance_multiplier * hacking_skill - requiredLevel) 100 - difficulty +// ----------------------------------------------------------- * ----------------- +// (2 * hacking_chance_multiplier * hacking_skill) 100 +PlayerObject.prototype.calculateHackingChance = function() { + var difficultyMult = (100 - this.getCurrentServer().hackDifficulty) / 100; + var skillMult = (1.75 * this.hacking_skill); + var skillChance = (skillMult - this.getCurrentServer().requiredHackingSkill) / skillMult; + var chance = skillChance * difficultyMult * this.hacking_chance_mult; + if (chance > 1) {return 1;} + if (chance < 0) {return 0;} + return chance; +} + +//Calculate the time it takes to hack a server in seconds. Returns the time +//The formula is: +// (2.5 * requiredLevel * difficulty + 200) +// ----------------------------------- * hacking_speed_multiplier +// hacking_skill + 100 +PlayerObject.prototype.calculateHackingTime = function() { + var difficultyMult = this.getCurrentServer().requiredHackingSkill * this.getCurrentServer().hackDifficulty; + var skillFactor = (2.5 * difficultyMult + 200) / (this.hacking_skill + 100); + return 5 * skillFactor / this.hacking_speed_mult; +} + +//Calculates the PERCENTAGE of a server's money that the player will hack from the server if successful +//The formula is: +// (hacking_skill - (requiredLevel-1)) 100 - difficulty +// --------------------------------------* ----------------------- * hacking_money_multiplier +// hacking_skill 100 +PlayerObject.prototype.calculatePercentMoneyHacked = function() { + var difficultyMult = (100 - this.getCurrentServer().hackDifficulty) / 100; + var skillMult = (this.hacking_skill - (this.getCurrentServer().requiredHackingSkill - 1)) / this.hacking_skill; + var percentMoneyHacked = difficultyMult * skillMult * this.hacking_money_mult / 240; + console.log("Percent money hacked calculated to be: " + percentMoneyHacked); + if (percentMoneyHacked < 0) {return 0;} + if (percentMoneyHacked > 1) {return 1;} + return percentMoneyHacked * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ManualHackMoney; +} + +//Returns how much EXP the player gains on a successful hack +//The formula is: +// difficulty * requiredLevel * hacking_multiplier +PlayerObject.prototype.calculateExpGain = function() { + var s = this.getCurrentServer(); + if (s.baseDifficulty == null) { + s.baseDifficulty = s.hackDifficulty; + } + return (s.baseDifficulty * this.hacking_exp_mult * 0.3 + 3) * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].HackExpGain; +} + +//Hack/Analyze a server. Return the amount of time the hack will take. This lets the Terminal object know how long to disable itself for +//This assumes that the server being hacked is not purchased by the player, that the player's hacking skill is greater than the +//required hacking skill and that the player has admin rights. +PlayerObject.prototype.hack = function() { + this.actionTime = this.calculateHackingTime(); + console.log("Hacking time: " + this.actionTime); + this.startAction = true; //Set the startAction flag so the engine starts the hacking process +} + +PlayerObject.prototype.analyze = function() { + this.actionTime = 1; + this.startAction = true; +} + +PlayerObject.prototype.hasProgram = function(programName) { + var home = Player.getHomeComputer(); + for (var i = 0; i < home.programs.length; ++i) { + if (programName.toLowerCase() == home.programs[i].toLowerCase()) {return true;} + } + return false; +} + +PlayerObject.prototype.setMoney = function(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.setMoney()"); return; + } + this.money = money; +} + +PlayerObject.prototype.gainMoney = function(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.gainMoney()"); return; + } + this.money = this.money.plus(money); + this.total_money = this.total_money.plus(money); + this.lifetime_money = this.lifetime_money.plus(money); +} + +PlayerObject.prototype.loseMoney = function(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.loseMoney()"); return; + } + this.money = this.money.minus(money); +} + +PlayerObject.prototype.gainHackingExp = function(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainHackingExp()"); return; + } + this.hacking_exp += exp; +} + +PlayerObject.prototype.gainStrengthExp = function(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainStrengthExp()"); return; + } + this.strength_exp += exp; +} + +PlayerObject.prototype.gainDefenseExp = function(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into player.gainDefenseExp()"); return; + } + this.defense_exp += exp; +} + +PlayerObject.prototype.gainDexterityExp = function(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainDexterityExp()"); return; + } + this.dexterity_exp += exp; +} + +PlayerObject.prototype.gainAgilityExp = function(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainAgilityExp()"); return; + } + this.agility_exp += exp; +} + +PlayerObject.prototype.gainCharismaExp = function(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainCharismaExp()"); return; + } + this.charisma_exp += exp; +} + +/******* Working functions *******/ +PlayerObject.prototype.resetWorkStatus = function() { + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + + document.getElementById("work-in-progress-text").innerHTML = ""; +} + +PlayerObject.prototype.gainWorkExp = function() { + this.gainHackingExp(this.workHackExpGained); + this.gainStrengthExp(this.workStrExpGained); + this.gainDefenseExp(this.workDefExpGained); + this.gainDexterityExp(this.workDexExpGained); + this.gainAgilityExp(this.workAgiExpGained); + this.gainCharismaExp(this.workChaExpGained); +} + +/* Working for Company */ +PlayerObject.prototype.finishWork = function(cancelled, sing=false) { + //Since the work was cancelled early, player only gains half of what they've earned so far + if (cancelled) { + this.workRepGained /= 2; + } + + this.gainWorkExp(); + + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + company.playerReputation += (this.workRepGained); + + this.gainMoney(this.workMoneyGained); + + this.updateSkillLevels(); + + var txt = "You earned a total of:
" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + "
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " reputation for the company
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma exp
"; + + if (cancelled) { + txt = "You worked a short shift of " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "Since you cancelled your work early, you only gained half of the reputation you earned.

" + txt; + } else { + txt = "You worked a full shift of 8 hours!

" + + "You earned a total of:
" + txt; + } + if (!sing) {Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + this.isWorking = false; + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadTerminalContent(); + + if (sing) { + return "You worked a short shift of " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + " and " + + "earned $" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + ", " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " reputation, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility exp, and " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma exp."; + } +} + +PlayerObject.prototype.startWork = function() { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCompany; + + this.workHackExpGainRate = this.getWorkHackExpGain(); + this.workStrExpGainRate = this.getWorkStrExpGain(); + this.workDefExpGainRate = this.getWorkDefExpGain(); + this.workDexExpGainRate = this.getWorkDexExpGain(); + this.workAgiExpGainRate = this.getWorkAgiExpGain(); + this.workChaExpGainRate = this.getWorkChaExpGain(); + this.workRepGainRate = this.getWorkRepGain(); + this.workMoneyGainRate = this.getWorkMoneyGain(); + + this.timeNeededToCompleteWork = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MillisecondsPer8Hours; + + //Remove all old event listeners from Cancel button + var newCancelButton = Object(__WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__["b" /* clearEventListeners */])("work-in-progress-cancel-button"); + newCancelButton.innerHTML = "Cancel Work"; + newCancelButton.addEventListener("click", function() { + Player.finishWork(true); + return false; + }); + + //Display Work In Progress Screen + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadWorkInProgressContent(); +} + +PlayerObject.prototype.work = function(numCycles) { + this.workRepGainRate = this.getWorkRepGain(); + + this.workHackExpGained += this.workHackExpGainRate * numCycles; + this.workStrExpGained += this.workStrExpGainRate * numCycles; + this.workDefExpGained += this.workDefExpGainRate * numCycles; + this.workDexExpGained += this.workDexExpGainRate * numCycles; + this.workAgiExpGained += this.workAgiExpGainRate * numCycles; + this.workChaExpGained += this.workChaExpGainRate * numCycles; + this.workRepGained += this.workRepGainRate * numCycles; + this.workMoneyGained += this.workMoneyGainRate * numCycles; + + var cyclesPerSec = 1000 / __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed; + + this.timeWorked += __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed * numCycles; + + //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money + if (this.timeWorked >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MillisecondsPer8Hours) { + var maxCycles = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].GameCyclesPer8Hours; + this.workHackExpGained = this.workHackExpGainRate * maxCycles; + this.workStrExpGained = this.workStrExpGainRate * maxCycles; + this.workDefExpGained = this.workDefExpGainRate * maxCycles; + this.workDexExpGained = this.workDexExpGainRate * maxCycles; + this.workAgiExpGained = this.workAgiExpGainRate * maxCycles; + this.workChaExpGained = this.workChaExpGainRate * maxCycles; + this.workRepGained = this.workRepGainRate * maxCycles; + this.workMoneyGained = this.workMoneyGainRate * maxCycles; + this.finishWork(false); + return; + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + + " at " + Player.companyName + "

" + + "You have been working for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "You have earned:

" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + " ($" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec)

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGainRate * cyclesPerSec, 4) + " / sec) reputation for this company

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp

" + + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " + + "but you will only gain half of the reputation you've earned so far." + +} + +PlayerObject.prototype.startWorkPartTime = function() { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCompanyPartTime; + + this.workHackExpGainRate = this.getWorkHackExpGain(); + this.workStrExpGainRate = this.getWorkStrExpGain(); + this.workDefExpGainRate = this.getWorkDefExpGain(); + this.workDexExpGainRate = this.getWorkDexExpGain(); + this.workAgiExpGainRate = this.getWorkAgiExpGain(); + this.workChaExpGainRate = this.getWorkChaExpGain(); + this.workRepGainRate = this.getWorkRepGain(); + this.workMoneyGainRate = this.getWorkMoneyGain(); + + this.timeNeededToCompleteWork = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MillisecondsPer8Hours; + + var newCancelButton = Object(__WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__["b" /* clearEventListeners */])("work-in-progress-cancel-button"); + newCancelButton.innerHTML = "Stop Working"; + newCancelButton.addEventListener("click", function() { + Player.finishWorkPartTime(); + return false; + }); + + //Display Work In Progress Screen + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadWorkInProgressContent(); +} + +PlayerObject.prototype.workPartTime = function(numCycles) { + this.workRepGainRate = this.getWorkRepGain(); + + this.workHackExpGained += this.workHackExpGainRate * numCycles; + this.workStrExpGained += this.workStrExpGainRate * numCycles; + this.workDefExpGained += this.workDefExpGainRate * numCycles; + this.workDexExpGained += this.workDexExpGainRate * numCycles; + this.workAgiExpGained += this.workAgiExpGainRate * numCycles; + this.workChaExpGained += this.workChaExpGainRate * numCycles; + this.workRepGained += this.workRepGainRate * numCycles; + this.workMoneyGained += this.workMoneyGainRate * numCycles; + + var cyclesPerSec = 1000 / __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed; + + this.timeWorked += __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed * numCycles; + + //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money + if (this.timeWorked >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MillisecondsPer8Hours) { + var maxCycles = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].GameCyclesPer8Hours; + this.workHackExpGained = this.workHackExpGainRate * maxCycles; + this.workStrExpGained = this.workStrExpGainRate * maxCycles; + this.workDefExpGained = this.workDefExpGainRate * maxCycles; + this.workDexExpGained = this.workDexExpGainRate * maxCycles; + this.workAgiExpGained = this.workAgiExpGainRate * maxCycles; + this.workChaExpGained = this.workChaExpGainRate * maxCycles; + this.workRepGained = this.workRepGainRate * maxCycles; + this.workMoneyGained = this.workMoneyGainRate * maxCycles; + this.finishWorkPartTime(); + return; + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + + " at " + Player.companyName + "

" + + "You have been working for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "You have earned:

" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + " ($" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec)

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGainRate * cyclesPerSec, 4) + " / sec) reputation for this company

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp

" + + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
" + + "and there will be no penalty because this is a part-time job."; + +} + +PlayerObject.prototype.finishWorkPartTime = function(sing=false) { + this.gainWorkExp(); + + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + company.playerReputation += (this.workRepGained); + + this.gainMoney(this.workMoneyGained); + + this.updateSkillLevels(); + + var txt = "You earned a total of:
" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + "
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " reputation for the company
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma exp
"; + txt = "You worked for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + txt; + if (!sing) {Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + this.isWorking = false; + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadTerminalContent(); + if (sing) { + return "You worked for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + " and " + + "earned a total of " + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + ", " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " reputation, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility exp, and " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma exp"; + } +} + +/* Working for Faction */ +PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) { + this.gainWorkExp(); + + var faction = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */][this.currentWorkFactionName]; + faction.playerReputation += (this.workRepGained); + + this.gainMoney(this.workMoneyGained); + + this.updateSkillLevels(); + + var txt = "You worked for your faction " + faction.name + " for a total of " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "You earned a total of:
" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + "
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " reputation for the faction
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma exp
"; + if (!sing) {Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + this.isWorking = false; + + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadTerminalContent(); + if (sing) { + return "You worked for your faction " + faction.name + " for a total of " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + ". " + + "You earned " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " rep, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " str exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " def exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dex exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agi exp, and " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " cha exp."; + } +} + +PlayerObject.prototype.startFactionWork = function(faction) { + //Update reputation gain rate to account for faction favor + var favorMult = 1 + (faction.favor / 100); + if (isNaN(favorMult)) {favorMult = 1;} + this.workRepGainRate *= favorMult; + this.workRepGainRate *= __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkRepGain; + + this.isWorking = true; + this.workType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeFaction; + this.currentWorkFactionName = faction.name; + + this.timeNeededToCompleteWork = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MillisecondsPer20Hours; + + var cancelButton = Object(__WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__["b" /* clearEventListeners */])("work-in-progress-cancel-button"); + cancelButton.innerHTML = "Stop Faction Work"; + cancelButton.addEventListener("click", function() { + Player.finishFactionWork(true); + return false; + }); + + //Display Work In Progress Screen + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadWorkInProgressContent(); +} + +PlayerObject.prototype.startFactionHackWork = function(faction) { + this.resetWorkStatus(); + + this.workHackExpGainRate = .15 * this.hacking_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workRepGainRate = this.hacking_skill / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel * this.faction_rep_mult; + + this.factionWorkType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].FactionWorkHacking; + this.currentWorkFactionDescription = "carrying out hacking contracts"; + + this.startFactionWork(faction); +} + +PlayerObject.prototype.startFactionFieldWork = function(faction) { + this.resetWorkStatus(); + + this.workHackExpGainRate = .1 * this.hacking_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workStrExpGainRate = .1 * this.strength_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workDefExpGainRate = .1 * this.defense_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workDexExpGainRate = .1 * this.dexterity_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workAgiExpGainRate = .1 * this.agility_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workChaExpGainRate = .1 * this.charisma_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workRepGainRate = this.getFactionFieldWorkRepGain(); + + this.factionWorkType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].FactionWorkField; + this.currentWorkFactionDescription = "carrying out field missions" + + this.startFactionWork(faction); +} + +PlayerObject.prototype.startFactionSecurityWork = function(faction) { + this.resetWorkStatus(); + + this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workStrExpGainRate = 0.15 * this.strength_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workDefExpGainRate = 0.15 * this.defense_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkExpGain; + this.workRepGainRate = this.getFactionSecurityWorkRepGain(); + + this.factionWorkType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].FactionWorkSecurity; + this.currentWorkFactionDescription = "performing security detail" + + this.startFactionWork(faction); +} + +PlayerObject.prototype.workForFaction = function(numCycles) { + var faction = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */][this.currentWorkFactionName]; + + //Constantly update the rep gain rate + switch (this.factionWorkType) { + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].FactionWorkHacking: + this.workRepGainRate = this.hacking_skill / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel * this.faction_rep_mult; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].FactionWorkField: + this.workRepGainRate = this.getFactionFieldWorkRepGain(); + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].FactionWorkSecurity: + this.workRepGainRate = this.getFactionSecurityWorkRepGain(); + break; + default: + break; + } + + //Update reputation gain rate to account for faction favor + var favorMult = 1 + (faction.favor / 100); + if (isNaN(favorMult)) {favorMult = 1;} + this.workRepGainRate *= favorMult; + this.workRepGainRate *= __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].FactionWorkRepGain; + + this.workHackExpGained += this.workHackExpGainRate * numCycles; + this.workStrExpGained += this.workStrExpGainRate * numCycles; + this.workDefExpGained += this.workDefExpGainRate * numCycles; + this.workDexExpGained += this.workDexExpGainRate * numCycles; + this.workAgiExpGained += this.workAgiExpGainRate * numCycles; + this.workChaExpGained += this.workChaExpGainRate * numCycles; + this.workRepGained += this.workRepGainRate * numCycles; + this.workMoneyGained += this.workMoneyGainRate * numCycles; + + var cyclesPerSec = 1000 / __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed; + + this.timeWorked += __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed * numCycles; + + //If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours + if (this.timeWorked >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MillisecondsPer20Hours) { + var maxCycles = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].GameCyclesPer20Hours; + this.workHackExpGained = this.workHackExpGainRate * maxCycles; + this.workStrExpGained = this.workStrExpGainRate * maxCycles; + this.workDefExpGained = this.workDefExpGainRate * maxCycles; + this.workDexExpGained = this.workDexExpGainRate * maxCycles; + this.workAgiExpGained = this.workAgiExpGainRate * maxCycles; + this.workChaExpGained = this.workChaExpGainRate * maxCycles; + this.workRepGained = this.workRepGainRate * maxCycles; + this.workMoneyGained = this.workMoneyGainRate * maxCycles; + this.finishFactionWork(false); + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently " + this.currentWorkFactionDescription + " for your faction " + faction.name + "." + + " You have been doing this for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "You have earned:

" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec)

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workRepGainRate * cyclesPerSec, 4) + " / sec) reputation for this faction

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp

" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp

" + + + "You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
" + + "There is no penalty for cancelling earlier."; +} + + +//Money gained per game cycle +PlayerObject.prototype.getWorkMoneyGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.baseSalary * company.salaryMultiplier * + this.work_money_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkMoney; +} + +//Hack exp gained per game cycle +PlayerObject.prototype.getWorkHackExpGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.hackingExpGain * company.expMultiplier * + this.hacking_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkExpGain; +} + +//Str exp gained per game cycle +PlayerObject.prototype.getWorkStrExpGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.strengthExpGain * company.expMultiplier * + this.strength_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkExpGain; +} + +//Def exp gained per game cycle +PlayerObject.prototype.getWorkDefExpGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.defenseExpGain * company.expMultiplier * + this.defense_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkExpGain; +} + +//Dex exp gained per game cycle +PlayerObject.prototype.getWorkDexExpGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.dexterityExpGain * company.expMultiplier * + this.dexterity_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkExpGain; +} + +//Agi exp gained per game cycle +PlayerObject.prototype.getWorkAgiExpGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.agilityExpGain * company.expMultiplier * + this.agility_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkExpGain; +} + +//Charisma exp gained per game cycle +PlayerObject.prototype.getWorkChaExpGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + return this.companyPosition.charismaExpGain * company.expMultiplier * + this.charisma_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CompanyWorkExpGain; +} + +//Reputation gained per game cycle +PlayerObject.prototype.getWorkRepGain = function() { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + var jobPerformance = this.companyPosition.calculateJobPerformance(this.hacking_skill, this.strength, + this.defense, this.dexterity, + this.agility, this.charisma); + //Update reputation gain rate to account for company favor + var favorMult = 1 + (company.favor / 100); + if (isNaN(favorMult)) {favorMult = 1;} + return jobPerformance * this.company_rep_mult * favorMult; +} + +PlayerObject.prototype.getFactionSecurityWorkRepGain = function() { + var t = 0.9 * (this.hacking_skill / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.strength / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.defense / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.dexterity / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.agility / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel) / 5; + return t * this.faction_rep_mult; +} + +PlayerObject.prototype.getFactionFieldWorkRepGain = function() { + var t = 0.9 * (this.hacking_skill / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.strength / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.defense / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.dexterity / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.agility / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel + + this.charisma / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel) / 6; + return t * this.faction_rep_mult; +} + +/* Creating a Program */ +PlayerObject.prototype.startCreateProgramWork = function(programName, time, reqLevel) { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCreateProgram; + + //Time needed to complete work affected by hacking skill (linearly based on + //ratio of (your skill - required level) to MAX skill) + var timeMultiplier = (__WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel - (this.hacking_skill - reqLevel)) / __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].MaxSkillLevel; + if (timeMultiplier > 1) {timeMultiplier = 1;} + if (timeMultiplier < 0.01) {timeMultiplier = 0.01;} + + this.timeNeededToCompleteWork = timeMultiplier * time; + //Check for incomplete program + for (var i = 0; i < Player.getHomeComputer().programs.length; ++i) { + var programFile = Player.getHomeComputer().programs[i]; + if (programFile.startsWith(programName) && programFile.endsWith("%-INC")) { + var res = programFile.split("-"); + if (res.length != 3) {break;} + var percComplete = Number(res[1].slice(0, -1)); + if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {break;} + this.timeWorked = percComplete / 100 * this.timeNeededToCompleteWork; + Player.getHomeComputer().programs.splice(i, 1); + } + } + + this.createProgramName = programName; + + var cancelButton = Object(__WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__["b" /* clearEventListeners */])("work-in-progress-cancel-button"); + cancelButton.innerHTML = "Cancel work on creating program"; + cancelButton.addEventListener("click", function() { + Player.finishCreateProgramWork(true); + return false; + }); + + //Display Work In Progress Screen + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadWorkInProgressContent(); +} + +PlayerObject.prototype.createProgramWork = function(numCycles) { + this.timeWorked += __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed * numCycles; + var programName = this.createProgramName; + + if (this.timeWorked >= this.timeNeededToCompleteWork) { + this.finishCreateProgramWork(false); + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working on coding " + programName + ".

" + + "You have been working for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "The program is " + (this.timeWorked / this.timeNeededToCompleteWork * 100).toFixed(2) + "% complete.
" + + "If you cancel, your work will be saved and you can come back to complete the program later."; +} + +PlayerObject.prototype.finishCreateProgramWork = function(cancelled, sing=false) { + var programName = this.createProgramName; + if (cancelled === false) { + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You've finished creating " + programName + "!
" + + "The new program can be found on your home computer."); + + Player.getHomeComputer().programs.push(programName); + } else { + var perc = Math.floor(this.timeWorked / this.timeNeededToCompleteWork * 100).toString(); + var incompleteName = programName + "-" + perc + "%-INC"; + Player.getHomeComputer().programs.push(incompleteName); + } + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + Player.isWorking = false; + + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadTerminalContent(); +} + +/* Studying/Taking Classes */ +PlayerObject.prototype.startClass = function(costMult, expMult, className) { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeStudyClass; + + this.className = className; + + var gameCPS = 1000 / __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed; + + //Base exp gains per second + var baseStudyComputerScienceExp = 0.5; + var baseDataStructuresExp = 1; + var baseNetworksExp = 2; + var baseAlgorithmsExp = 4; + var baseManagementExp = 2; + var baseLeadershipExp = 4; + var baseGymExp = 1; + + //Find cost and exp gain per game cycle + var cost = 0; + var hackExp = 0, strExp = 0, defExp = 0, dexExp = 0, agiExp = 0, chaExp = 0; + switch (className) { + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassStudyComputerScience: + hackExp = baseStudyComputerScienceExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassDataStructures: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassDataStructuresBaseCost * costMult / gameCPS; + hackExp = baseDataStructuresExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassNetworks: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassNetworksBaseCost * costMult / gameCPS; + hackExp = baseNetworksExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassAlgorithms: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassAlgorithmsBaseCost * costMult / gameCPS; + hackExp = baseAlgorithmsExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassManagement: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassManagementBaseCost * costMult / gameCPS; + chaExp = baseManagementExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassLeadership: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassLeadershipBaseCost * costMult / gameCPS; + chaExp = baseLeadershipExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymStrength: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymBaseCost * costMult / gameCPS; + strExp = baseGymExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymDefense: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymBaseCost * costMult / gameCPS; + defExp = baseGymExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymDexterity: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymBaseCost * costMult / gameCPS; + dexExp = baseGymExp * expMult / gameCPS; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymAgility: + cost = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymBaseCost * costMult / gameCPS; + agiExp = baseGymExp * expMult / gameCPS; + break; + default: + throw new Error("ERR: Invalid/unregocnized class name"); + return; + } + + this.workMoneyLossRate = cost; + this.workHackExpGainRate = hackExp * this.hacking_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ClassGymExpGain; + this.workStrExpGainRate = strExp * this.strength_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ClassGymExpGain;; + this.workDefExpGainRate = defExp * this.defense_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ClassGymExpGain;; + this.workDexExpGainRate = dexExp * this.dexterity_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ClassGymExpGain;; + this.workAgiExpGainRate = agiExp * this.agility_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ClassGymExpGain;; + this.workChaExpGainRate = chaExp * this.charisma_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].ClassGymExpGain;; + + var cancelButton = Object(__WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__["b" /* clearEventListeners */])("work-in-progress-cancel-button"); + if (className == __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymStrength || + className == __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymDefense || + className == __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymDexterity || + className == __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].ClassGymAgility) { + cancelButton.innerHTML = "Stop training at gym"; + } else { + cancelButton.innerHTML = "Stop taking course"; + } + cancelButton.addEventListener("click", function() { + Player.finishClass(); + return false; + }); + + //Display Work In Progress Screen + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadWorkInProgressContent(); +} + +PlayerObject.prototype.takeClass = function(numCycles) { + this.timeWorked += __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed * numCycles; + var className = this.className; + + this.workHackExpGained += this.workHackExpGainRate * numCycles; + this.workStrExpGained += this.workStrExpGainRate * numCycles; + this.workDefExpGained += this.workDefExpGainRate * numCycles; + this.workDexExpGained += this.workDexExpGainRate * numCycles; + this.workAgiExpGained += this.workAgiExpGainRate * numCycles; + this.workChaExpGained += this.workChaExpGainRate * numCycles; + this.workRepGained += this.workRepGainRate * numCycles; + this.workMoneyGained += this.workMoneyGainRate * numCycles; + this.workMoneyGained -= this.workMoneyLossRate * numCycles; + + var cyclesPerSec = 1000 / __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed; + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You have been " + className + " for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + "

" + + "This has cost you:
" + + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + " ($" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyLossRate * cyclesPerSec, 2) + " / sec)

" + + "You have gained:
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGainRate * cyclesPerSec, 4) + " / sec) hacking exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGainRate * cyclesPerSec, 4) + " / sec) defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGainRate * cyclesPerSec, 4) + " / sec) strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGainRate * cyclesPerSec, 4) + " / sec) dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGainRate * cyclesPerSec, 4) + " / sec) agility exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " (" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGainRate * cyclesPerSec, 4) + " / sec) charisma exp
" + + "You may cancel at any time"; +} + +//The 'sing' argument defines whether or not this function was called +//through a Singularity Netscript function +PlayerObject.prototype.finishClass = function(sing=false) { + this.gainWorkExp(); + + if (this.workMoneyGained > 0) { + throw new Error("ERR: Somehow gained money while taking class"); + } + this.loseMoney(this.workMoneyGained * -1); + + this.updateSkillLevels(); + var txt = "After " + this.className + " for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + ",
" + + "you spent a total of $" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained * -1, 2) + ".

" + + "You earned a total of:
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility exp
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma exp
"; + if (!sing) {Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + this.isWorking = false; + + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); + + if (sing) {return "After " + this.className + " for " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeWorked) + ", " + + "you spent a total of $" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained * -1, 2) + ". " + + "You earned a total of: " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 3) + " hacking exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 3) + " strength exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 3) + " defense exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 3) + " dexterity exp, " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 3) + " agility exp, and " + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 3) + " charisma exp";} +} + +//The EXP and $ gains are hardcoded. Time is in ms +PlayerObject.prototype.startCrime = function(hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time) { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCrime; + + this.workHackExpGained = hackExp * this.hacking_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeExpGain; + this.workStrExpGained = strExp * this.strength_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeExpGain; + this.workDefExpGained = defExp * this.defense_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeExpGain; + this.workDexExpGained = dexExp * this.dexterity_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeExpGain; + this.workAgiExpGained = agiExp * this.agility_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeExpGain; + this.workChaExpGained = chaExp * this.charisma_exp_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeExpGain; + this.workMoneyGained = money * this.crime_money_mult * __WEBPACK_IMPORTED_MODULE_1__BitNode_js__["a" /* BitNodeMultipliers */].CrimeMoney; + + this.timeNeededToCompleteWork = time; + + //Remove all old event listeners from Cancel button + var newCancelButton = Object(__WEBPACK_IMPORTED_MODULE_15__utils_HelperFunctions_js__["b" /* clearEventListeners */])("work-in-progress-cancel-button") + newCancelButton.innerHTML = "Cancel crime" + newCancelButton.addEventListener("click", function() { + Player.finishCrime(true); + return false; + }); + + //Display Work In Progress Screen + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadWorkInProgressContent(); +} + +PlayerObject.prototype.commitCrime = function (numCycles) { + this.timeWorked += __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"]._idleSpeed * numCycles; + + if (this.timeWorked >= this.timeNeededToCompleteWork) {Player.finishCrime(false); return;} + + var percent = Math.round(Player.timeWorked / Player.timeNeededToCompleteWork * 100); + var numBars = Math.round(percent / 5); + if (numBars < 0) {numBars = 0;} + if (numBars > 20) {numBars = 20;} + var progressBar = "[" + Array(numBars+1).join("|") + Array(20 - numBars + 1).join(" ") + "]"; + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are attempting to " + Player.crimeType + ".
" + + "Time remaining: " + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(this.timeNeededToCompleteWork - this.timeWorked) + "
" + + progressBar.replace( / /g, " " ); +} + +PlayerObject.prototype.finishCrime = function(cancelled) { + //Determine crime success/failure + if (!cancelled) { + var statusText = ""; //TODO, unique message for each crime when you succeed + if (Object(__WEBPACK_IMPORTED_MODULE_5__Crimes_js__["w" /* determineCrimeSuccess */])(this.crimeType, this.workMoneyGained)) { + //Handle Karma and crime statistics + switch(this.crimeType) { + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeShoplift: + this.karma -= 0.1; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeRobStore: + this.karma -= 0.5; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeMug: + this.karma -= 0.25; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeLarceny: + this.karma -= 1.5; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeDrugs: + this.karma -= 0.5; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeTraffickArms: + this.karma -= 1; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeHomicide: + ++this.numPeopleKilled; + this.karma -= 3; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeGrandTheftAuto: + this.karma -= 5; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeKidnap: + this.karma -= 6; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeAssassination: + ++this.numPeopleKilled; + this.karma -= 10; + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CrimeHeist: + this.karma -= 15; + break; + default: + console.log(this.crimeType); + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("ERR: Unrecognized crime type. This is probably a bug please contact the developer"); + return; + } + + //On a crime success, gain 2x exp + this.workHackExpGained *= 2; + this.workStrExpGained *= 2; + this.workDefExpGained *= 2; + this.workDexExpGained *= 2; + this.workAgiExpGained *= 2; + this.workChaExpGained *= 2; + + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Crime successful!

" + + "You gained:
"+ + "$" + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workMoneyGained, 2) + "
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma experience"); + } else { + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Crime failed!

" + + "You gained:
"+ + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workHackExpGained, 4) + " hacking experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workStrExpGained, 4) + " strength experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDefExpGained, 4) + " defense experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workDexExpGained, 4) + " dexterity experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workAgiExpGained, 4) + " agility experience
" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.workChaExpGained, 4) + " charisma experience"); + } + + this.gainWorkExp(); + } + + + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + this.isWorking = false; + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); +} + +//Cancels the player's current "work" assignment and gives the proper rewards +//Used only for Singularity functions, so no popups are created +PlayerObject.prototype.singularityStopWork = function() { + if (!this.isWorking) {return "";} + var res; //Earnings text for work + switch (this.workType) { + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeStudyClass: + res = this.finishClass(true); + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCompany: + res = this.finishWork(true, true); + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCompanyPartTime: + res = this.finishWorkPartTime(true); + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeFaction: + res = this.finishFactionWork(true, true); + break; + case __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].WorkTypeCreateProgram: + res = this.finishCreateProgramWork(true, true); + break; + default: + console.log("ERROR: Unrecognized work type"); + return ""; + } + return res; +} + + +//Returns true if hospitalized, false otherwise +PlayerObject.prototype.takeDamage = function(amt) { + this.hp -= amt; + if (this.hp <= 0) { + this.hospitalize(); + return true; + } else { + return false; + } +} + +PlayerObject.prototype.hospitalize = function() { + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You were in critical condition! You were taken to the hospital where " + + "luckily they were able to save your life. You were charged $" + + Object(__WEBPACK_IMPORTED_MODULE_18__utils_StringHelperFunctions_js__["c" /* formatNumber */])(this.max_hp * __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].HospitalCostPerHp, 2)); + Player.loseMoney(this.max_hp * __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].HospitalCostPerHp); + this.hp = this.max_hp; +} + +/********* Company job application **********/ +//Determines the job that the Player should get (if any) at the current company +//The 'sing' argument designates whether or not this is being called from +//the applyToCompany() Netscript Singularity function +PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) { + var currCompany = ""; + if (this.companyName != "") { + currCompany = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + } + var currPositionName = ""; + if (this.companyPosition != "") { + currPositionName = this.companyPosition.positionName; + } + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (sing && !(company instanceof __WEBPACK_IMPORTED_MODULE_2__Company_js__["b" /* Company */])) { + return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed"; + } + + var pos = entryPosType; + + if (!this.isQualified(company, pos)) { + var reqText = Object(__WEBPACK_IMPORTED_MODULE_2__Company_js__["f" /* getJobRequirementText */])(company, pos); + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position
" + reqText); + return; + } + + while (true) { + if (__WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].Debug) {console.log("Determining qualification for next Company Position");} + var newPos = Object(__WEBPACK_IMPORTED_MODULE_2__Company_js__["g" /* getNextCompanyPosition */])(pos); + if (newPos == null) {break;} + + //Check if this company has this position + if (company.hasPosition(newPos)) { + if (!this.isQualified(company, newPos)) { + //If player not qualified for next job, break loop so player will be given current job + break; + } + pos = newPos; + } else { + break; + } + } + + //Check if the determined job is the same as the player's current job + if (currCompany != "") { + if (currCompany.companyName == company.companyName && + pos.positionName == currPositionName) { + var nextPos = Object(__WEBPACK_IMPORTED_MODULE_2__Company_js__["g" /* getNextCompanyPosition */])(pos); + if (nextPos == null) { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You are already at the highest position for your field! No promotion available"); + } else if (company.hasPosition(nextPos)) { + if (sing) {return false;} + var reqText = Object(__WEBPACK_IMPORTED_MODULE_2__Company_js__["f" /* getJobRequirementText */])(company, nextPos); + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unfortunately, you do not qualify for a promotion
" + reqText); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You are already at the highest position for your field! No promotion available"); + } + return; //Same job, do nothing + } + } + + + //Lose reputation from a Company if you are leaving it for another job + var leaveCompany = false; + var oldCompanyName = ""; + if (currCompany != "") { + if (currCompany.companyName != company.companyName) { + leaveCompany = true; + oldCompanyName = currCompany.companyName; + company.playerReputation -= 1000; + if (company.playerReputation < 0) {company.playerReputation = 0;} + } + } + + this.companyName = company.companyName; + this.companyPosition = pos; + + Player.firstJobRecvd = true; + + if (leaveCompany) { + if (sing) {return true;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Congratulations! You were offered a new job at " + this.companyName + " as a " + + pos.positionName + "!
" + + "You lost 1000 reputation at your old company " + oldCompanyName + " because you left."); + } else { + if (sing) {return true;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.positionName + "!"); + } + + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); +} + +//Returns your next position at a company given the field (software, business, etc.) +PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType) { + var currCompany = null; + if (this.companyName != "") { + currCompany = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + } + + //Not employed at this company, so return the entry position + if (currCompany == null || (currCompany.companyName != company.companyName)) { + return entryPosType; + } + + //If the entry pos type and the player's current position have the same type, + //return the player's "nextCompanyPosition". Otherwise return the entryposType + //Employed at this company, so just return the next position if it exists. + if ((this.companyPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) || + (this.companyPosition.isITJob() && entryPosType.isITJob()) || + (this.companyPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) || + (this.companyPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) || + (this.companyPosition.isSecurityJob() && entryPosType.isSecurityJob()) || + (this.companyPosition.isAgentJob() && entryPosTypeisAgentJob()) || + (this.companyPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) || + (this.companyPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) || + (this.companyPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) { + return Object(__WEBPACK_IMPORTED_MODULE_2__Company_js__["g" /* getNextCompanyPosition */])(this.companyPosition); + } + + + return entryPosType; +} + +PlayerObject.prototype.applyForSoftwareJob = function(sing=false) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].SoftwareIntern, sing); +} + +PlayerObject.prototype.applyForSoftwareConsultantJob = function(sing=false) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].SoftwareConsultant, sing); +} + +PlayerObject.prototype.applyForItJob = function(sing=false) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].ITIntern, sing); +} + +PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].SecurityEngineer)) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].SecurityEngineer, sing); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].NetworkEngineer)) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].NetworkEngineer, sing); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForBusinessJob = function(sing=false) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].BusinessIntern, sing); +} + +PlayerObject.prototype.applyForBusinessConsultantJob = function(sing=false) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].BusinessConsultant, sing); +} + +PlayerObject.prototype.applyForSecurityJob = function(sing=false) { + //TODO If case for POlice departments + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].SecurityGuard, sing); +} + +PlayerObject.prototype.applyForAgentJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].FieldAgent)) { + return this.applyForJob(__WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].FieldAgent, sing); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForEmployeeJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].Employee)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].Employee; + if (sing) {return true;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Congratulations, you are now employed at " + this.companyName); + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].PartTimeEmployee)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].PartTimeEmployee; + if (sing) {return true;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Congratulations, you are now employed part-time at " + this.companyName); + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForWaiterJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].Waiter)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].Waiter; + if (sing) {return true;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Congratulations, you are now employed as a waiter at " + this.companyName); + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) { + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.location]; //Company being applied to + if (this.isQualified(company, __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].PartTimeWaiter)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].PartTimeWaiter; + if (sing) {return true;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Congratulations, you are now employed as a part-time waiter at " + this.companyName); + __WEBPACK_IMPORTED_MODULE_6__engine_js__["Engine"].loadLocationContent(); + } else { + if (sing) {return false;} + Object(__WEBPACK_IMPORTED_MODULE_14__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Unforunately, you do not qualify for this position"); + } +} + +//Checks if the Player is qualified for a certain position +PlayerObject.prototype.isQualified = function(company, position) { + var offset = company.jobStatReqOffset; + var reqHacking = position.requiredHacking > 0 ? position.requiredHacking+offset : 0; + var reqStrength = position.requiredStrength > 0 ? position.requiredStrength+offset : 0; + var reqDefense = position.requiredDefense > 0 ? position.requiredDefense+offset : 0; + var reqDexterity = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; + var reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; + var reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma+offset : 0; + + if (this.hacking_skill >= reqHacking && + this.strength >= reqStrength && + this.defense >= reqDefense && + this.dexterity >= reqDexterity && + this.agility >= reqAgility && + this.charisma >= reqCharisma && + company.playerReputation >= position.requiredReputation) { + return true; + } + return false; +} + +/********** Reapplying Augmentations and Source File ***********/ +PlayerObject.prototype.reapplyAllAugmentations = function(resetMultipliers=true) { + console.log("Re-applying augmentations"); + if (resetMultipliers) { + this.resetMultipliers(); + } + + for (let i = 0; i < this.augmentations.length; ++i) { + //Compatibility with new version + if (typeof this.augmentations[i] === 'string' || this.augmentations[i] instanceof String) { + var newOwnedAug = new PlayerOwnedAugmentation(this.augmentations[i]); + if (this.augmentations[i] == __WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["b" /* AugmentationNames */].NeuroFluxGovernor) { + newOwnedAug.level = __WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["c" /* Augmentations */][__WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["b" /* AugmentationNames */].NeuroFluxGovernor].level; + } + this.augmentations[i] = newOwnedAug; + } + + var augName = this.augmentations[i].name; + var aug = __WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["c" /* Augmentations */][augName]; + aug.owned = true; + if (aug == null) { + console.log("WARNING: Invalid augmentation name"); + continue; + } + if (aug.name == __WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["b" /* AugmentationNames */].NeuroFluxGovernor) { + for (let j = 0; j < aug.level; ++j) { + Object(__WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["e" /* applyAugmentation */])(this.augmentations[i], true); + } + continue; + } + Object(__WEBPACK_IMPORTED_MODULE_0__Augmentations_js__["e" /* applyAugmentation */])(this.augmentations[i], true); + } +} + +PlayerObject.prototype.reapplyAllSourceFiles = function() { + console.log("Re-applying source files"); + //Will always be called after reapplyAllAugmentations() so multipliers do not have to be reset + //this.resetMultipliers(); + + for (let i = 0; i < this.sourceFiles.length; ++i) { + var srcFileKey = "SourceFile" + this.sourceFiles[i].n; + var sourceFileObject = __WEBPACK_IMPORTED_MODULE_12__SourceFile_js__["b" /* SourceFiles */][srcFileKey]; + if (sourceFileObject == null) { + console.log("ERROR: Invalid source file number: " + this.sourceFiles[i].n); + continue; + } + Object(__WEBPACK_IMPORTED_MODULE_12__SourceFile_js__["c" /* applySourceFile */])(this.sourceFiles[i]); + } +} + +/*************** Check for Faction Invitations *************/ +//This function sets the requirements to join a Faction. It checks whether the Player meets +//those requirements and will return an array of all factions that the Player should +//receive an invitation to +PlayerObject.prototype.checkForFactionInvitations = function() { + let invitedFactions = []; //Array which will hold all Factions th eplayer should be invited to + + var numAugmentations = this.augmentations.length; + + var company = __WEBPACK_IMPORTED_MODULE_2__Company_js__["a" /* Companies */][this.companyName]; + var companyRep = 0; + if (company != null) { + companyRep = company.playerReputation; + } + + //Illuminati + var illuminatiFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Illuminati"]; + if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(150000000000) && + this.hacking_skill >= 1500 && + this.strength >= 1200 && this.defense >= 1200 && + this.dexterity >= 1200 && this.agility >= 1200) { + invitedFactions.push(illuminatiFac); + } + + //Daedalus + var daedalusFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Daedalus"]; + if (!daedalusFac.isBanned && !daedalusFac.isMember && !daedalusFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(100000000000) && + (this.hacking_skill >= 2500 || + (this.strength >= 1500 && this.defense >= 1500 && + this.dexterity >= 1500 && this.agility >= 1500))) { + invitedFactions.push(daedalusFac); + } + + //The Covenant + var covenantFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["The Covenant"]; + if (!covenantFac.isBanned && !covenantFac.isMember && !covenantFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(75000000000) && + this.hacking_skill >= 850 && + this.strength >= 850 && + this.defense >= 850 && + this.dexterity >= 850 && + this.agility >= 850) { + invitedFactions.push(covenantFac); + } + + //ECorp + var ecorpFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["ECorp"]; + if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].AevumECorp && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(ecorpFac); + } + + //MegaCorp + var megacorpFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["MegaCorp"]; + if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12MegaCorp && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(megacorpFac); + } + + //Bachman & Associates + var bachmanandassociatesFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Bachman & Associates"]; + if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember && + !bachmanandassociatesFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].AevumBachmanAndAssociates && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(bachmanandassociatesFac); + } + + //Blade Industries + var bladeindustriesFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Blade Industries"]; + if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12BladeIndustries && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(bladeindustriesFac); + } + + //NWO + var nwoFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["NWO"]; + if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].VolhavenNWO && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(nwoFac); + } + + //Clarke Incorporated + var clarkeincorporatedFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Clarke Incorporated"]; + if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].AevumClarkeIncorporated && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(clarkeincorporatedFac); + } + + //OmniTek Incorporated + var omnitekincorporatedFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["OmniTek Incorporated"]; + if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].VolhavenOmniTekIncorporated && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(omnitekincorporatedFac); + } + + //Four Sigma + var foursigmaFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Four Sigma"]; + if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12FourSigma && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(foursigmaFac); + } + + //KuaiGong International + var kuaigonginternationalFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["KuaiGong International"]; + if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember && + !kuaigonginternationalFac.alreadyInvited && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].ChongqingKuaiGongInternational && companyRep >= __WEBPACK_IMPORTED_MODULE_3__Constants_js__["a" /* CONSTANTS */].CorpFactionRepRequirement) { + invitedFactions.push(kuaigonginternationalFac); + } + + //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company + var fulcrumsecrettechonologiesFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Fulcrum Secret Technologies"]; + var fulcrumSecretServer = __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["a" /* SpecialServerIps */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["b" /* SpecialServerNames */].FulcrumSecretTechnologies]]; + if (fulcrumSecretServer == null) { + console.log("ERROR: Could not find Fulcrum Secret Technologies Server"); + } else { + if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && + !fulcrumsecrettechonologiesFac.alreadyInvited && + fulcrumSecretServer.manuallyHacked && + this.companyName == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].AevumFulcrumTechnologies && companyRep >= 250000) { + invitedFactions.push(fulcrumsecrettechonologiesFac); + } + } + + //BitRunners + var bitrunnersFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["BitRunners"]; + var homeComp = this.getHomeComputer(); + var bitrunnersServer = __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["a" /* SpecialServerIps */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["b" /* SpecialServerNames */].BitRunnersServer]]; + if (bitrunnersServer == null) { + console.log("ERROR: Could not find BitRunners Server"); + } else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked && + !bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) { + invitedFactions.push(bitrunnersFac); + } + + //The Black Hand + var theblackhandFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["The Black Hand"]; + var blackhandServer = __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["a" /* SpecialServerIps */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["b" /* SpecialServerNames */].TheBlackHandServer]]; + if (blackhandServer == null) { + console.log("ERROR: Could not find The Black Hand Server"); + } else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked && + !theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) { + invitedFactions.push(theblackhandFac); + } + + //NiteSec + var nitesecFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["NiteSec"]; + var nitesecServer = __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["a" /* SpecialServerIps */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["b" /* SpecialServerNames */].NiteSecServer]]; + if (nitesecServer == null) { + console.log("ERROR: Could not find NiteSec Server"); + } else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked && + !nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) { + invitedFactions.push(nitesecFac); + } + + //Chongqing + var chongqingFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Chongqing"]; + if (!chongqingFac.isBanned && !chongqingFac.isMember && !chongqingFac.alreadyInvited && + this.money.gte(20000000) && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Chongqing) { + invitedFactions.push(chongqingFac); + } + + //Sector-12 + var sector12Fac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Sector-12"]; + if (!sector12Fac.isBanned && !sector12Fac.isMember && !sector12Fac.alreadyInvited && + this.money.gte(15000000) && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12) { + invitedFactions.push(sector12Fac); + } + + //New Tokyo + var newtokyoFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["New Tokyo"]; + if (!newtokyoFac.isBanned && !newtokyoFac.isMember && !newtokyoFac.alreadyInvited && + this.money.gte(20000000) && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].NewTokyo) { + invitedFactions.push(newtokyoFac); + } + + //Aevum + var aevumFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Aevum"]; + if (!aevumFac.isBanned && !aevumFac.isMember && !aevumFac.alreadyInvited && + this.money.gte(40000000) && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Aevum) { + invitedFactions.push(aevumFac); + } + + //Ishima + var ishimaFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Ishima"]; + if (!ishimaFac.isBanned && !ishimaFac.isMember && !ishimaFac.alreadyInvited && + this.money.gte(30000000) && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Ishima) { + invitedFactions.push(ishimaFac); + } + + //Volhaven + var volhavenFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Volhaven"]; + if (!volhavenFac.isBanned && !volhavenFac.isMember && !volhavenFac.alreadyInvited && + this.money.gte(50000000) && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Volhaven) { + invitedFactions.push(volhavenFac); + } + + //Speakers for the Dead + var speakersforthedeadFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Speakers for the Dead"]; + if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited && + this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 && + this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 && + this.karma <= -45 && this.companyName != __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12CIA && + this.companyName != __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12NSA) { + invitedFactions.push(speakersforthedeadFac); + } + + //The Dark Army + var thedarkarmyFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["The Dark Army"]; + if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited && + this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 && + this.dexterity >= 300 && this.agility >= 300 && this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Chongqing && + this.numPeopleKilled >= 5 && this.karma <= -45 && this.companyName != __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12CIA && + this.companyName != __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12NSA) { + invitedFactions.push(thedarkarmyFac); + } + + //The Syndicate + var thesyndicateFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["The Syndicate"]; + if (!thesyndicateFac.isBanned && !thesyndicateFac.isMember && !thesyndicateFac.alreadyInvited && + this.hacking_skill >= 200 && this.strength >= 200 && this.defense >= 200 && + this.dexterity >= 200 && this.agility >= 200 && + (this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Aevum || this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12) && + this.money.gte(10000000) && this.karma <= -90 && + this.companyName != __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12CIA && this.companyName != __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Sector12NSA) { + invitedFactions.push(thesyndicateFac); + } + + //Silhouette + var silhouetteFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Silhouette"]; + if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited && + (this.companyPosition.positionName == __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].CTO.positionName || + this.companyPosition.positionName == __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].CFO.positionName || + this.companyPosition.positionName == __WEBPACK_IMPORTED_MODULE_2__Company_js__["d" /* CompanyPositions */].CEO.positionName) && + this.money.gte(15000000) && this.karma <= -22) { + invitedFactions.push(silhouetteFac); + } + + //Tetrads + var tetradsFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Tetrads"]; + if (!tetradsFac.isBanned && !tetradsFac.isMember && !tetradsFac.alreadyInvited && + (this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Chongqing || this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].NewTokyo || + this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Ishima) && this.strength >= 75 && this.defense >= 75 && + this.dexterity >= 75 && this.agility >= 75 && this.karma <= -18) { + invitedFactions.push(tetradsFac); + } + + //SlumSnakes + var slumsnakesFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Slum Snakes"]; + if (!slumsnakesFac.isBanned && !slumsnakesFac.isMember && !slumsnakesFac.alreadyInvited && + this.strength >= 30 && this.defense >= 30 && this.dexterity >= 30 && + this.agility >= 30 && this.karma <= -9 && this.money.gte(1000000)) { + invitedFactions.push(slumsnakesFac); + } + + //Netburners + var netburnersFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Netburners"]; + var totalHacknetRam = 0; + var totalHacknetCores = 0; + var totalHacknetLevels = 0; + for (var i = 0; i < Player.hacknetNodes.length; ++i) { + totalHacknetLevels += Player.hacknetNodes[i].level; + totalHacknetRam += Player.hacknetNodes[i].ram; + totalHacknetCores += Player.hacknetNodes[i].cores; + } + if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited && + this.hacking_skill >= 80 && totalHacknetRam >= 8 && + totalHacknetCores >= 4 && totalHacknetLevels >= 100) { + invitedFactions.push(netburnersFac); + } + + //Tian Di Hui + var tiandihuiFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["Tian Di Hui"]; + if (!tiandihuiFac.isBanned && !tiandihuiFac.isMember && !tiandihuiFac.alreadyInvited && + this.money.gte(1000000) && this.hacking_skill >= 50 && + (this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Chongqing || this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].NewTokyo || + this.city == __WEBPACK_IMPORTED_MODULE_9__Location_js__["a" /* Locations */].Ishima)) { + invitedFactions.push(tiandihuiFac); + } + + //CyberSec + var cybersecFac = __WEBPACK_IMPORTED_MODULE_7__Faction_js__["b" /* Factions */]["CyberSec"]; + var cybersecServer = __WEBPACK_IMPORTED_MODULE_10__Server_js__["b" /* AllServers */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["a" /* SpecialServerIps */][__WEBPACK_IMPORTED_MODULE_11__SpecialServerIps_js__["b" /* SpecialServerNames */].CyberSecServer]]; + if (cybersecServer == null) { + console.log("ERROR: Could not find CyberSec Server"); + } else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked && + !cybersecFac.alreadyInvited && this.hacking_skill >= 50) { + invitedFactions.push(cybersecFac); + } + + return invitedFactions; +} + + +/*************** Gang ****************/ +//Returns true if Player is in a gang and false otherwise +PlayerObject.prototype.inGang = function() { + if (this.gang == null || this.gang == undefined) {return false;} + return (this.gang instanceof __WEBPACK_IMPORTED_MODULE_8__Gang_js__["b" /* Gang */]); +} + +PlayerObject.prototype.startGang = function(factionName, hacking) { + this.gang = new __WEBPACK_IMPORTED_MODULE_8__Gang_js__["b" /* Gang */](factionName, hacking); +} + +/************* BitNodes **************/ +PlayerObject.prototype.setBitNodeNumber = function(n) { + this.bitNodeN = n; +} + +/* Functions for saving and loading the Player data */ +function loadPlayer(saveString) { + Player = JSON.parse(saveString, __WEBPACK_IMPORTED_MODULE_17__utils_JSONReviver_js__["c" /* Reviver */]); + + //Parse Decimal.js objects + Player.money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(Player.money); + Player.total_money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(Player.total_money); + Player.lifetime_money = new __WEBPACK_IMPORTED_MODULE_13__utils_decimal_js___default.a(Player.lifetime_money); +} + +PlayerObject.prototype.toJSON = function() { + return Object(__WEBPACK_IMPORTED_MODULE_17__utils_JSONReviver_js__["b" /* Generic_toJSON */])("PlayerObject", this); +} + +PlayerObject.fromJSON = function(value) { + return Object(__WEBPACK_IMPORTED_MODULE_17__utils_JSONReviver_js__["a" /* Generic_fromJSON */])(PlayerObject, value.data); +} + +__WEBPACK_IMPORTED_MODULE_17__utils_JSONReviver_js__["c" /* Reviver */].constructors.PlayerObject = PlayerObject; + +let Player = new PlayerObject(); + + + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* unused harmony export sizeOfObject */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return addOffset; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return clearEventListeners; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return getRandomInt; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return compareArrays; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "f", function() { return printArray; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "e", function() { return powerOfTwo; }); +//General helper functions + +//Returns the size (number of keys) of an object +function sizeOfObject(obj) { + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) size++; + } + return size; +} + +//Adds a random offset to a number within a certain percentage +//e.g. addOffset(100, 5) will return anything from 95 to 105. +//The percentage argument must be between 0 and 100; +function addOffset(n, percentage) { + if (percentage < 0 || percentage > 100) {return;} + + var offset = n * (percentage / 100); + + return n + ((Math.random() * (2 * offset)) - offset); +} + +//Given an element by its Id(usually an 'a' element), removes all event listeners +//from that element by cloning and replacing. Then returns the new cloned element +function clearEventListeners(elemId) { + var elem = document.getElementById(elemId); + if (elem == null) {console.log("ERR: Could not find element for: " + elemId); return null;} + var newElem = elem.cloneNode(true); + elem.parentNode.replaceChild(newElem, elem); + return newElem; +} + +function getRandomInt(min, max) { + if (min > max) {return getRandomInt(max, min);} + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +//Returns true if all elements are equal, and false otherwise +//Assumes both arguments are arrays and that there are no nested arrays +function compareArrays(a1, a2) { + if (a1.length != a2.length) { + return false; + } + + for (var i = 0; i < a1.length; ++i) { + if (a1[i] != a2[i]) {return false;} + } + return true; +} + +function printArray(a) { + return "[" + a.join(", ") + "]"; +} + +//Returns bool indicating whether or not its a power of 2 +function powerOfTwo(n) { + if (isNaN(n)) {return false;} + return n && (n & (n-1)) === 0; +} + + + + +/***/ }), +/* 2 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return dialogBoxCreate; }); +/* Pop up Dialog Box */ +let dialogBoxes = []; + +//Close dialog box when clicking outside +$(document).click(function(event) { + if (dialogBoxOpened && dialogBoxes.length >= 1) { + if (!$(event.target).closest(dialogBoxes[0]).length){ + dialogBoxes[0].remove(); + dialogBoxes.splice(0, 1); + if (dialogBoxes.length == 0) { + dialogBoxOpened = false; + } else { + dialogBoxes[0].style.visibility = "visible"; + } + } + } +}); + + +//Dialog box close buttons +$(document).on('click', '.dialog-box-close-button', function( event ) { + if (dialogBoxOpened && dialogBoxes.length >= 1) { + dialogBoxes[0].remove(); + dialogBoxes.splice(0, 1); + if (dialogBoxes.length == 0) { + dialogBoxOpened = false; + } else { + dialogBoxes[0].style.visibility = "visible"; + } + } +}); + +var dialogBoxOpened = false; + +function dialogBoxCreate(txt) { + var container = document.createElement("div"); + container.setAttribute("class", "dialog-box-container"); + + var content = document.createElement("div"); + content.setAttribute("class", "dialog-box-content"); + + var closeButton = document.createElement("span"); + closeButton.setAttribute("class", "dialog-box-close-button"); + closeButton.innerHTML = "×" + + var textE = document.createElement("p"); + textE.innerHTML = txt; + + content.appendChild(closeButton); + content.appendChild(textE); + container.appendChild(content); + + document.body.appendChild(container); + if (dialogBoxes.length >= 1) { + container.style.visibility = "hidden"; + } + dialogBoxes.push(container); + + setTimeout(function() { + dialogBoxOpened = true; + }, 400); +} + + + +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(8))) + +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return CONSTANTS; }); +let CONSTANTS = { + Version: "0.28.1", + + //Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience + //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then + //the player will have this level assuming no multipliers. Multipliers can cause skills to go above this. + MaxSkillLevel: 975, + + //How much reputation is needed to join a megacorporation's faction + CorpFactionRepRequirement: 250000, + + /* Base costs */ + BaseCostFor1GBOfRamHome: 30000, + BaseCostFor1GBOfRamServer: 50000, //1 GB of RAM + BaseCostFor1GBOfRamHacknetNode: 30000, + + BaseCostForHacknetNode: 1000, + BaseCostForHacknetNodeCore: 500000, + + /* Hacknet Node constants */ + HacknetNodeMoneyGainPerLevel: 1.6, + HacknetNodePurchaseNextMult: 1.85, //Multiplier when purchasing an additional hacknet node + HacknetNodeUpgradeLevelMult: 1.04, //Multiplier for cost when upgrading level + HacknetNodeUpgradeRamMult: 1.28, //Multiplier for cost when upgrading RAM + HacknetNodeUpgradeCoreMult: 1.48, //Multiplier for cost when buying another core + + HacknetNodeMaxLevel: 200, + HacknetNodeMaxRam: 64, + HacknetNodeMaxCores: 16, + + /* Faction and Company favor */ + FactionReputationToFavorBase: 500, + FactionReputationToFavorMult: 1.02, + CompanyReputationToFavorBase: 500, + CompanyReputationToFavorMult: 1.02, + + + /* Augmentation */ + //NeuroFlux Governor cost multiplier as you level up + NeuroFluxGovernorLevelMult: 1.14, + + //RAM Costs for different commands + ScriptWhileRamCost: 0.2, + ScriptForRamCost: 0.2, + ScriptIfRamCost: 0.1, + ScriptHackRamCost: 0.1, + ScriptGrowRamCost: 0.15, + ScriptWeakenRamCost: 0.15, + ScriptScanRamCost: 0.2, + ScriptNukeRamCost: 0.05, + ScriptBrutesshRamCost: 0.05, + ScriptFtpcrackRamCost: 0.05, + ScriptRelaysmtpRamCost: 0.05, + ScriptHttpwormRamCost: 0.05, + ScriptSqlinjectRamCost: 0.05, + ScriptRunRamCost: 0.8, + ScriptExecRamCost: 1.1, + ScriptScpRamCost: 0.5, + ScriptKillRamCost: 0.5, //Kill and killall + ScriptHasRootAccessRamCost: 0.05, + ScriptGetHostnameRamCost: 0.05, + ScriptGetHackingLevelRamCost: 0.05, + ScriptGetServerCost: 0.1, + ScriptFileExistsRamCost: 0.1, + ScriptIsRunningRamCost: 0.1, + ScriptOperatorRamCost: 0.01, + ScriptPurchaseHacknetRamCost: 1.5, + ScriptHacknetNodesRamCost: 1.0, //Base cost for accessing hacknet nodes array + ScriptHNUpgLevelRamCost: 0.4, + ScriptHNUpgRamRamCost: 0.6, + ScriptHNUpgCoreRamCost: 0.8, + ScriptGetStockRamCost: 2.0, + ScriptBuySellStockRamCost: 2.5, + ScriptPurchaseServerRamCost: 2.0, + ScriptRoundRamCost: 0.05, + ScriptReadWriteRamCost: 1.0, + ScriptArbScriptRamCost: 1.0, //Functions that apply to all scripts regardless of args + ScriptGetScriptRamCost: 0.1, + ScriptGetHackTimeRamCost: 0.05, + + ScriptSingularityFn1RamCost: 1, + ScriptSingularityFn2RamCost: 2, + ScriptSingularityFn3RamCost: 3, + + MultithreadingRAMCost: 1, + + //Server constants + ServerBaseGrowthRate: 1.03, //Unadjusted Growth rate + ServerMaxGrowthRate: 1.0035, //Maximum possible growth rate (max rate accounting for server security) + ServerFortifyAmount: 0.002, //Amount by which server's security increases when its hacked/grown + ServerWeakenAmount: 0.05, //Amount by which server's security decreases when weakened + + PurchasedServerLimit: 25, + + //Augmentation Constants + AugmentationCostMultiplier: 5, //Used for balancing costs without having to readjust every Augmentation cost + AugmentationRepMultiplier: 2.5, //Used for balancing rep cost without having to readjust every value + MultipleAugMultiplier: 1.9, + + //How much a TOR router costs + TorRouterCost: 200000, + + //Infiltration constants + InfiltrationBribeBaseAmount: 100000, //Amount per clearance level + InfiltrationMoneyValue: 2000, //Convert "secret" value to money + + //Stock market constants + WSEAccountCost: 200000000, + TIXAPICost: 5000000000, + StockMarketCommission: 100000, + + //Hospital/Health + HospitalCostPerHp: 100000, + + //Gang constants + GangRespectToReputationRatio: 2, //Respect is divided by this to get rep gain + MaximumGangMembers: 20, + GangRecruitCostMultiplier: 2, + GangTerritoryUpdateTimer: 150, + + MillisecondsPer20Hours: 72000000, + GameCyclesPer20Hours: 72000000 / 200, + + MillisecondsPer10Hours: 36000000, + GameCyclesPer10Hours: 36000000 / 200, + + MillisecondsPer8Hours: 28800000, + GameCyclesPer8Hours: 28800000 / 200, + + MillisecondsPer4Hours: 14400000, + GameCyclesPer4Hours: 14400000 / 200, + + MillisecondsPer2Hours: 7200000, + GameCyclesPer2Hours: 7200000 / 200, + + MillisecondsPerHour: 3600000, + GameCyclesPerHour: 3600000 / 200, + + MillisecondsPerHalfHour: 1800000, + GameCyclesPerHalfHour: 1800000 / 200, + + MillisecondsPerQuarterHour: 900000, + GameCyclesPerQuarterHour: 900000 / 200, + + MillisecondsPerFiveMinutes: 300000, + GameCyclesPerFiveMinutes: 300000 / 200, + + FactionWorkHacking: "Faction Hacking Work", + FactionWorkField: "Faction Field Work", + FactionWorkSecurity: "Faction Security Work", + + WorkTypeCompany: "Working for Company", + WorkTypeCompanyPartTime: "Working for Company part-time", + WorkTypeFaction: "Working for Faction", + WorkTypeCreateProgram: "Working on Create a Program", + WorkTypeStudyClass: "Studying or Taking a class at university", + WorkTypeCrime: "Committing a crime", + + ClassStudyComputerScience: "studying Computer Science", + ClassDataStructures: "taking a Data Structures course", + ClassNetworks: "taking a Networks course", + ClassAlgorithms: "taking an Algorithms course", + ClassManagement: "taking a Management course", + ClassLeadership: "taking a Leadership course", + ClassGymStrength: "training your strength at a gym", + ClassGymDefense: "training your defense at a gym", + ClassGymDexterity: "training your dexterity at a gym", + ClassGymAgility: "training your agility at a gym", + + ClassDataStructuresBaseCost: 40, + ClassNetworksBaseCost: 80, + ClassAlgorithmsBaseCost: 320, + ClassManagementBaseCost: 160, + ClassLeadershipBaseCost: 320, + ClassGymBaseCost: 120, + + CrimeShoplift: "shoplift", + CrimeRobStore: "rob a store", + CrimeMug: "mug someone", + CrimeLarceny: "commit larceny", + CrimeDrugs: "deal drugs", + CrimeTraffickArms: "traffick illegal arms", + CrimeHomicide: "commit homicide", + CrimeGrandTheftAuto: "commit grand theft auto", + CrimeKidnap: "kidnap someone for ransom", + CrimeAssassination: "assassinate a high-profile target", + CrimeHeist: "pull off the ultimate heist", + + /* Tutorial related things */ + TutorialNetworkingText: "Servers are a central part of the game. You start with a single personal server (your home computer) " + + "and you can purchase additional servers as you progress through the game. Connecting to other servers " + + "and hacking them can be a major source of income and experience. Servers can also be used to run " + + "scripts which can automatically hack servers for you.

" + + "In order to navigate between machines, use the 'scan' or 'scan-analyze' Terminal command to see all servers " + + "that are reachable from your current server. Then, you can use the 'connect [hostname/ip]' " + + "command to connect to one of the available machines.

" + + "The 'hostname' and 'ifconfig' commands can be used to display the hostname/IP of the " + + "server you are currently connected to.", + + TutorialHackingText: "In the year 2077, currency has become digital and decentralized. People and corporations " + + "store their money on servers. By hacking these servers, you can steal their money and gain " + + "experience.

" + + "

Gaining root access


" + + "The key to hacking a server is to gain root access to that server. This can be done using " + + "the NUKE virus (NUKE.exe). You start the game with a copy of the NUKE virus on your home " + + "computer. The NUKE virus attacks the target server's open ports using buffer overflow " + + "exploits. When successful, you are granted root administrative access to the machine.

" + + "Typically, in order for the NUKE virus to succeed, the target server needs to have at least " + + "one of its ports opened. Some servers have no security and will not need any ports opened. Some " + + "will have very high security and will need many ports opened. In order to open ports on another " + + "server, you will need to run programs that attack the server to open specific ports. These programs " + + "can be coded once your hacking skill gets high enough, or they can be purchased if you can find " + + "a seller.

" + + "In order to determine how many ports need to be opened to successfully NUKE a server, connect to " + + "that server and run the 'analyze' command. This will also show you which ports have already been " + + "opened.

" + + "Once you have enough ports opened and have ran the NUKE virus to gain root access, the server " + + "can then be hacked by simply calling the 'hack' command through terminal, or by using a script.

" + + "

Hacking mechanics


" + + "When you execute the hack command, either manually through the terminal or automatically through " + + "a script, you attempt to hack the server. This action takes time. The more advanced a server's " + + "security is, the more time it will take. Your hacking skill level also affects the hacking time, " + + "with a higher hacking skill leading to shorter hacking times. Also, running the hack command " + + "manually through terminal is faster than hacking from a script.

" + + "Your attempt to hack a server will not always succeed. The chance you have to successfully hack a " + + "server is also determined by the server's security and your hacking skill level. Even if your " + + "hacking attempt is unsuccessful, you will still gain experience points.

" + + "When you successfully hack a server. You steal a certain percentage of that server's total money. This " + + "percentage is determined by the server's security and your hacking skill level. The amount of money " + + "on a server is not limitless. So, if you constantly hack a server and deplete its money, then you will " + + "encounter diminishing returns in your hacking (since you are only hacking a certain percentage). You can " + + "increase the amount of money on a server using a script and the grow() function in Netscript.

" + + "

Server Security


" + + "Each server has a security level, which is denoted by a number between 1 and 100. A higher number means " + + "the server has stronger security. As mentioned above, a server's security level is an important factor " + + "to consider when hacking. You can check a server's security level using the 'analyze' command, although this " + + "only gives an estimate (with 5% uncertainty). You can also check a server's security in a script, using the " + + "getServerSecurityLevel(server) function in Netscript. See the Netscript documentation for more details. " + + "This function will give you an exact value for a server's security.

" + + "Whenever a server is hacked manually or through a script, its security level increases by a small amount. Calling " + + "the grow() command in a script will also increase security level of the target server. These actions will " + + "make it harder for you to hack the server, and decrease the amount of money you can steal. You can lower a " + + "server's security level in a script using the weaken(server) function in Netscript. See the Netscript " + + "documentation for more details.

" + + "A server has a minimum security level that is equal to one third of its starting security, rounded to the " + + "nearest integer. To be more precise:

" + + "server.minSecurityLevel = Math.max(1, Math.round(server.startingSecurityLevel / 3))

" + + "This means that a server's security will not fall below this value if you are trying to weaken it.", + + TutorialScriptsText: "Scripts can be used to automate the hacking process. Scripts must be written in the Netscript language. " + + "Documentation about the Netscript language can be found in the 'Netscript Programming Language' " + + "section of this 'Tutorial' page.

" + + "It is highly recommended that you have a basic background in programming to start writing scripts. " + + "You by no means need to be an expert. All you need is some familiarity with basic programming " + + "constructs like for/while loops, if statements, " + + "functions, variables, etc. The Netscript programming language most resembles the Javascript language. " + + "Therefore, a good beginner's programming tutorial to read might be " + + "this one. Note that while the Netscript language is similar to Javascript, it is not the exact same, so the " + + "syntax will vary a little bit.

" + + "Running a script requires RAM. The more complex a script is, the more RAM " + + "it requires to run. Scripts can be run on any server you have root access to.

" + + "Here are some Terminal commands that are useful when working with scripts:

" + + "check [script] [args...]
Prints the logs of the script specified by the name and arguments to Terminal. Arguments should be separated " + + "by a space. Note that scripts are uniquely " + + "identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the argument 'foodnstuff' then in order to 'check' it you must " + + "also add the 'foodnstuff' argument to the check command as so:
check foo.script foodnstuff

" + + "free
Shows the current server's RAM usage and availability

" + + "kill [script] [args...]
Stops a script that is running with the specified script name and arguments. " + + "Arguments should be separated by a space. Note that " + + "scripts are uniquely identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the " + + "argument 1 and 2, then just typing 'kill foo.script' will not work. You have to use 'kill foo.script 1 2'.

" + + "mem [script] [-t] [n]
Check how much RAM a script requires to run with n threads

" + + "nano [script]
Create/Edit a script. The name of the script must end with the '.script' extension

" + + "ps
Displays all scripts that are actively running on the current server

" + + "rm [script]
Delete a script

" + + "run [script] [-t] [n] [args...]
Run a script with n threads and the specified arguments. Each argument should be separated by a space. " + + "Both the arguments and thread specification are optional. If neither are specified, then the script will be run single-threaded with no arguments.
" + + "Examples:
run foo.script
The command above will run 'foo.script' single-threaded with no arguments." + + "
run foo.script -t 10
The command above will run 'foo.script' with 10 threads and no arguments." + + "
run foo.script foodnstuff sigma-cosmetics 10
The command above will run 'foo.script' single-threaded with three arguments: [foodnstuff, sigma-cosmetics, 10]" + + "
run foo.script -t 50 foodnstuff
The command above will run 'foo.script' with 50 threads and a single argument: [foodnstuff]

" + + "tail [script] [args...]
Displays the logs of the script specified by the name and arguments. Note that scripts are uniquely " + + "identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the argument 'foodnstuff' then in order to 'tail' it you must " + + "also add the 'foodnstuff' argument to the tail command as so:
tail foo.script foodnstuff

" + + "top
Displays all active scripts and their RAM usage

" + + "

Multithreading scripts


" + + "Scripts can be multithreaded. A multithreaded script runs the script's code once in each thread. The result is that " + + "every call to the hack(), grow(), and weaken() Netscript functions will have its effect multiplied by the number of threads. " + + "For example, if a normal single-threaded script is able to hack $10,000, then running the same script with 5 threads would " + + "yield $50,000.

" + + "When multithreading a script, the total RAM cost can be calculated by simply multiplying the base RAM cost of the script " + + "with the number of threads, where the base cost refers to the amount of RAM required to run the script single-threaded. " + + "In the terminal, you can run the " + + "'mem [scriptname] -t n' command to see how much RAM a script requires with n threads.

" + + "Every method for running a script has an option for making it multihreaded. To run a script with " + + "n threads from a Terminal:
" + + "run [scriptname] -t n

" + + "Using Netscript commands:
" + + "run('scriptname.script', n);
" + + "exec('scriptname.script, 'targetServer', n);

" + + "

Notes about how scripts work offline


" + + " The scripts that you write and execute are interpreted in Javascript. For this " + + "reason, it is not possible for these scripts to run while offline (when the game is closed). " + + "It is important to note that for this reason, conditionals such as if/else statements and certain " + + "commands such as purchaseHacknetNode() or nuke() will not work while the game is offline.

" + + "However, Scripts WILL continue to generate money and hacking exp for you while the game is offline. This " + + "offline production is based off of the scripts' production while the game is online.

" + + "grow() and weaken() are two Netscript commands that will also be applied when the game is offline, although at a slower rate " + + "compared to if the game was open. This is done by having each script keep track of the " + + "rate at which the grow() and weaken() commands are called when the game is online. These calculated rates are used to determine how many times " + + "these function calls would be made while the game is offline.

" + + "Also, note that because of the way the Netscript interpreter is implemented, " + + "whenever you reload or re-open the game all of the scripts that you are running will " + + "start running from the BEGINNING of the code. The game does not keep track of where exactly " + + "the execution of a script is when it saves/loads.


", + TutorialNetscriptText: "Netscript is a programming language implemented for this game. The language has " + + "your basic programming constructs and several built-in commands that are used to hack.

" + + "

Official Wiki and Documentation


" + + "Check out Bitburner's wiki for the official Netscript documentation" + + ". The wiki documentation will contain more details and " + + "code examples than this documentation page. Also, it can be opened up in another tab/window for convenience!

" + + "

Variables and data types


" + + "The following data types are supported by Netscript:
" + + "numeric - Integers and floats (eg. 6, 10.4999)
" + + "string - Encapsulated by single or double quotes (eg. 'this is a string')
" + + "boolean - true or false

" + + "Strings are fully functional Javascript strings, " + + "which means that all of the member functions of Javascript strings such as toLowerCase() and includes() are also " + + "available in Netscript!

" + + "To create a variable, use the assign (=) operator. The language is not strongly typed. Examples:
" + + "i = 5;
" + + "s = 'this game is awesome!';

" + + "In the first example above, we are creating the variable i and assigning it a value of 5. In the second, " + + "we are creating the variable s and assigning it the value of a string. Note that all expressions must be " + + "ended with a semicolon.

" + + "

Operators


" + + "The following operators are supported by Netscript:
" + + " +
" + + " -
" + + " *
" + + " /
" + + " %
" + + " &&
" + + " ||
" + + " <
" + + " >
" + + " <=
" + + " >=
" + + " ==
" + + " !=
" + + " ++ (Note: This ONLY pre-increments. Post-increment does not work)
" + + " -- (Note: This ONLY pre-decrements. Post-decrement does not work)
" + + " - (Negation operator)
" + + " !

" + + "

Arrays


" + + "Netscript arrays have the same properties and functions as javascript arrays. For information see javascripts array documentation.

"+ + "

Script Arguments


" + + "Arguments passed into a script can be accessed using a special array called 'args'. The arguments can be accessed like a normal array using the [] " + + "operator. (args[0], args[1], args[2]...)

" + + "For example, let's say we want to make a generic script 'generic-run.script' and we plan to pass two arguments into that script. The first argument will be the name of " + + "another script, and the second argument will be a number. This generic script will run the script specified in the first argument " + + "with the amount of threads specified in the second element. The code would look like:

" + + "run(args[0], args[1]);

" + + "It is also possible to get the number of arguments that was passed into a script using:

" + + "args.length

" + + "Note that none of the other functions that typically work with arrays, such as remove(), insert(), clear(), etc., will work on the " + + "args array.

" + + "

Functions


" + + "You can NOT define you own functions in Netscript (yet), but there are several built in functions that " + + "you may use:

" + + "hack(hostname/ip)
Core function that is used to try and hack servers to steal money and gain hacking experience. The argument passed in must be a string with " + + "either the IP or hostname of the server you want to hack. The runtime for this command depends on your hacking level and the target server's security level. " + + " A script can hack a server from anywhere. It does not need to be running on the same server to hack that server. " + + "For example, you can create a script that hacks the 'foodnstuff' server and run that script on any server in the game. A successful hack() on " + + "a server will raise that server's security level by 0.002. Returns true if the hack is successful and " + + "false otherwise.
" + + "Examples: hack('foodnstuff'); or hack('148.192.0.12');

" + + "sleep(n, log=true)
Suspends the script for n milliseconds. The second argument is an optional boolean that indicates " + + "whether or not the function should log the sleep action. If this argument is true, then calling this function will write " + + "'Sleeping for N milliseconds' to the script's logs. If it's false, then this function will not log anything. " + + "If this argument is not specified then it will be true by default.
Example: sleep(5000);

" + + "grow(hostname/ip)
Use your hacking skills to increase the amount of money available on a server. The argument passed in " + + "must be a string with either the IP or hostname of the target server. The runtime for this command depends on your hacking level and the target server's security level. " + + "When grow() completes, the money available on a target server will be increased by a certain, fixed percentage. This percentage " + + "is determined by the server's growth rate and varies between servers. Generally, higher-level servers have higher growth rates.

" + + "Like hack(), grow() can be called on any server, regardless of where the script is running. " + + "The grow() command requires root access to the target server, but there is no required hacking level to run the command. " + + "It also raises the security level of the target server by 0.004. " + + "Returns the number by which the money on the server was multiplied for the growth. " + + "Works offline at a slower rate.
Example: grow('foodnstuff');

" + + "weaken(hostname/ip)
Use your hacking skills to attack a server's security, lowering the server's security level. The argument passed " + + "in must be a string with either the IP or hostname of the target server. The runtime for this command depends on your " + + "hacking level and the target server's security level. This function lowers the security level of the target server by " + + "0.05.

Like hack() and grow(), weaken() can be called on " + + "any server, regardless of where the script is running. This command requires root access to the target server, but " + + "there is no required hacking level to run the command. Returns " + + "0.1. Works offline at a slower rate
Example: weaken('foodnstuff');

" + + "print(x)
Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command ).

" + + "tprint(x)
Prints a value or a variable to the Terminal

" + + "clearLog()
Clears the script's logs.

" + + "scan(hostname/ip)
Returns an array containing the hostnames of all servers that are one node away from the specified server. " + + "The argument must be a string containing the IP or hostname of the target server. The hostnames in the returned array are strings.

" + + "nuke(hostname/ip)
Run NUKE.exe on the target server. NUKE.exe must exist on your home computer. Does NOT work while offline
Example: nuke('foodnstuff');

" + + "brutessh(hostname/ip)
Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer. Does NOT work while offline
Example: brutessh('foodnstuff');

" + + "ftpcrack(hostname/ip)
Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer. Does NOT work while offline
Example: ftpcrack('foodnstuff');

" + + "relaysmtp(hostname/ip)
Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer. Does NOT work while offline
Example: relaysmtp('foodnstuff');

" + + "httpworm(hostname/ip)
Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer. Does NOT work while offline
Example: httpworm('foodnstuff');

" + + "sqlinject(hostname/ip)
Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer. Does NOT work while offline
Example: sqlinject('foodnstuff');

" + + "run(script, [numThreads], [args...])
Run a script as a separate process. The first argument that is passed in is the name of the script as a string. This function can only " + + "be used to run scripts located on the current server (the server running the script that calls this function). The second argument " + + "is optional, and it specifies how many threads to run the script with. This argument must be a number greater than 0. If it is omitted, then the script will be run single-threaded. Any additional arguments will specify " + + "arguments to pass into the new script that is being run. If arguments are specified for the new script, then the second argument numThreads argument must be filled in with a value.

" + + "Returns true if the script is successfully started, and false otherwise. Requires a significant amount " + + "of RAM to run this command. Does NOT work while offline

" + + "The simplest way to use the run command is to call it with just the script name. The following example will run 'foo.script' single-threaded with no arguments:

" + + "run('foo.script');

" + + "The following example will run 'foo.script' but with 5 threads instead of single-threaded:

" + + "run('foo.script', 5);

" + + "The following example will run 'foo.script' single-threaded, and will pass the string 'foodnstuff' into the script as an argument:

" + + "run('foo.script', 1, 'foodnstuff');

" + + "exec(script, hostname/ip, [numThreads], [args...])
Run a script as a separate process on another server. The first argument is the name of the script as a string. The " + + "second argument is a string with the hostname or IP of the 'target server' on which to run the script. The specified script must exist on the target server. " + + "The third argument is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " + + "This argument must be a number that is greater than 0. Any additional arguments will specify arguments to pass into the new script that is being run. If " + + "arguments are specified for the new script, then the third argument numThreads must be filled in with a value.

Returns " + + "true if the script is successfully started, and false otherwise. Does NOT work while offline

" + + "The simplest way to use the exec command is to call it with just the script name and the target server. The following example will try to run 'generic-hack.script' " + + "on the 'foodnstuff' server:

" + + "exec('generic-hack.script', 'foodnstuff');

" + + "The following example will try to run the script 'generic-hack.script' on the 'joesguns' server with 10 threads:

" + + "exec('generic-hack.script', 'joesguns', 10);

" + + "The following example will try to run the script 'foo.script' on the 'foodnstuff' server with 5 threads. It will also pass the number 1 and the string 'test' in as arguments " + + "to the script.

" + + "exec('foo.script', 'foodnstuff', 5, 1, 'test');

" + + "kill(script, hostname/ip, [args...])
Kills the script on the target server specified by the script's name and arguments. Remember that " + + "scripts are uniquely identified by both their name and arguments. For example, if 'foo.script' is run with the argument 1, then this is not the " + + "same as 'foo.script' run with the argument 2, even though they have the same code.

" + + "The first argument must be a string with the name of the script. The name is case-sensitive. " + + "The second argument must be a string with the hostname or IP of the target server. Any additional arguments to the function will specify the arguments passed " + + "into the script that should be killed.

The function will try to kill the specified script on the target server. " + + "If the script is found on the specified server and is running, then it will be killed and this function " + + "will return true. Otherwise, this function will return false.

" + + "Examples:
" + + "If you are trying to kill a script named 'foo.script' on the 'foodnstuff' server that was ran with no arguments, use this:

" + + "kill('foo.script', 'foodnstuff');

" + + "If you are trying to kill a script named 'foo.script' on the current server that was ran with no arguments, use this:

" + + "kill('foo.script', getHostname());

" + + "If you are trying to kill a script named 'foo.script' on the current server that was ran with the arguments 1 and 'foodnstuff', use this:

" + + "kill('foo.script', getHostname(), 1, 'foodnstuff');

" + + "killall(hostname/ip)
Kills all running scripts on the specified server. This function takes a single argument which " + + "must be a string containing the hostname or IP of the target server. This function will always return true.

" + + "scp(script, hostname/ip)
Copies a script to another server. The first argument is a string with the filename of the script " + + "to be copied. The second argument is a string with the hostname or IP of the destination server. Returns true if the script is successfully " + + "copied over and false otherwise.
Example: scp('hack-template.script', 'foodnstuff');

" + + "hasRootAccess(hostname/ip)
Returns a boolean (true or false) indicating whether or not the Player has root access to a server. " + + "The argument passed in must be a string with either the hostname or IP of the target server. Does NOT work while offline.
" + + "Example:
if (hasRootAccess('foodnstuff') == false) {
    nuke('foodnstuff');
}

" + + "getHostname()
Returns a string with the hostname of the server that the script is running on

" + + "getHackingLevel()
Returns the Player's current hacking level. Does NOT work while offline

" + + "getServerMoneyAvailable(hostname/ip)
Returns the amount of money available on a server. The argument passed in must be a string with either the " + + "hostname or IP of the target server. Does NOT work while offline
Example: getServerMoneyAvailable('foodnstuff');

" + + "getServerMaxMoney(hostname/ip)
Returns the maximum amount of money that can be available on a server. The argument passed in must be a string with " + + "the hostname or IP of the target server. Does NOT work while offline
Example: getServerMaxMoney('foodnstuff');

" + + "getServerGrowth(hostname/ip)
Returns the server's intrinsic 'growth parameter'. This growth parameter is a number " + + "between 1 and 100 that represents how quickly the server's money grows. This parameter affects the percentage by which this server's " + + "money is increased when using the grow() function. A higher growth parameter will result in a higher percentage from grow().

" + + "The argument passed in must be a string with the hostname or IP of the target server.

" + + "getServerSecurityLevel(hostname/ip)
Returns the security level of a server. The argument passed in must be a string with either the " + + "hostname or IP of the target server. A server's security is denoted by a number between 1 and 100. Does NOT work while offline.

" + + "getServerBaseSecurityLevel(hostname/ip)
Returns the base security level of a server. This is the security level that the server starts out with. " + + "This is different than getServerSecurityLevel() because getServerSecurityLevel() returns the current security level of a server, which can constantly change " + + "due to hack(), grow(), and weaken() calls on that server. The base security level will stay the same until you reset by installing an Augmentation.

" + + "The argument passed in must be a string with either the hostname or IP of the target server. A server's base security is denoted by a number between 1 and 100. " + + "Does NOT work while offline.

" + + "getServerRequiredHackingLevel(hostname/ip)
Returns the required hacking level of a server. The argument passed in must be a string with either the " + + "hostname or IP or the target server. Does NOT work while offline

" + + "getServerNumPortsRequired(hostname/ip)
Returns the number of open ports required to successfully run NUKE.exe on a server. The argument " + + "passed in must be a string with either the hostname or IP of the target server. Does NOT work while offline

" + + "getServerRam(hostname/ip)
Returns an array with two elements that gives information about the target server's RAM. The first " + + "element in the array is the amount of RAM that the server has (in GB). The second element in the array is the amount of RAM that " + + "is currently being used on the server.

" + + "fileExists(filename, [hostname/ip])
Returns a boolean (true or false) indicating whether the specified file exists on a server. " + + "The first argument must be a string with the name of the file. A file can either be a script or a program. A script name is case-sensitive, but a " + + "program is not. For example, fileExists('brutessh.exe') will work fine, even though the actual program is named BruteSSH.exe.

" + + "The second argument is a string with the hostname or IP of the server on which to search for the program. This second argument is optional. " + + "If it is omitted, then the function will search through the current server (the server running the script that calls this function) for the file.
" + + "Example: fileExists('foo.script', 'foodnstuff');
" + + "Example: fileExists('ftpcrack.exe');

" + + "The first example above will return true if the script named 'foo.script' exists on the 'foodnstuff' server, and false otherwise. The second example above will " + + "return true if the current server (the server on which this function runs) contains the FTPCrack.exe program, and false otherwise.

" + + "isRunning(filename, hostname/ip, [args...])
Returns a boolean (true or false) indicating whether the specified script is running on a server. " + + "Remember that a script is uniquely identified by both its name and its arguments.

" + + "The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is a string with the " + + "hostname or IP of the target server. Any additional arguments passed to the function will specify the arguments passed into the target script. " + + "The function will check whether the script is running on that target server.
" + + "Example: isRunning('foo.script', 'foodnstuff');
" + + "Example: isRunning('foo.script', getHostname());
" + + "Example: isRunning('foo.script', 'joesguns', 1, 5, 'test');

" + + "The first example above will return true if there is a script named 'foo.script' with no arguments running on the 'foodnstuff' server, and false otherwise. The second " + + "example above will return true if there is a script named 'foo.script' with no arguments running on the current server, and false otherwise. " + + "The third example above will return true if there is a script named 'foo.script' with the arguments 1, 5, and 'test' running on the 'joesguns' server, and " + + "false otherwise.

" + + "getNextHacknetNodeCost()
Returns the cost of purchasing a new Hacknet Node

" + + "purchaseHacknetNode()
Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number " + + "at the end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford to purchase " + + "a new Hacknet Node then the function will return false. Does NOT work offline

" + + "purchaseServer(hostname, ram)
Purchases a server with the specified hostname and amount of RAM. The first argument can be any data type, " + + "but it will be converted to a string using Javascript's String function. Anything that resolves to an empty string will cause the function to fail. " + + "The second argument specified the amount of RAM (in GB) for the server. This argument must resolve to a numeric and it must be a power of 2 " + + "(2, 4, 8, etc...).

" + + "Purchasing a server using this Netscript function is twice as expensive as manually purchasing a server from a location in the World.

" + + "This function returns the hostname of the newly purchased server as a string. If the function fails to purchase a server, then it will return " + + "an empty string. The function will fail if the arguments passed in are invalid or if the player does not have enough money to purchase the specified server.

" + + "round(n)
Rounds the number n to the nearest integer. If the argument passed in is not a number, then the function will return 0.

" + + "write(port, data)
Writes data to a port. The first argument must be a number between 1 and 10 that specifies the port. The second " + + "argument defines the data to write to the port. If the second argument is not specified then it will write an empty string to the port.

" + + "read(port)
Reads data from a port. The first argument must be a number between 1 and 10 that specifies the port. A port is a serialized queue. " + + "This function will remove the first element from the queue and return it. If the queue is empty, then the string 'NULL PORT DATA' will be returned.

" + + "scriptRunning(scriptname, hostname/ip)
Returns a boolean indicating whether any instance of the specified script is running " + + "on a server, regardless of its arguments. This is different than the isRunning() function because it does not " + + "try to identify a specific instance of a running script by its arguments.

" + + "The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is " + + "a string with the hostname or IP of the target server. Both arguments are required.

" + + "scriptKill(scriptname, hostname/ip)
Kills all scripts with the specified filename that are running on the server specified by the " + + "hostname/ip, regardless of arguments. Returns true if one or more scripts were successfully killed, and false if there were none.

" + + "The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is " + + "a string with the hostname or IP of the target server. Both arguments are required.

" + + "getScriptRam(scriptname, hostname/ip)
Returns the amount of RAM required to run the specified script on the " + + "target server. The first argument must be a string with the name of the script. The script name is case sensitive. " + + "The second argument is a string with the hostname or IP of the server where that script is. Both arguments are required.

" + + "getHackTime(hostname/ip)
Returns the amount of time in seconds it takes to execute the hack() Netscript function " + + "on the server specified by the hostname/ip. The argument must be a string with the hostname/ip of the target server.

" + + "getGrowTime(hostname/ip)
Returns the amount of time in seconds it takes to execute the grow() Netscript function " + + "on the server specified by the hostname/ip. The argument must be a string with the hostname/ip of the target server.

" + + "getWeakenTime(hostname/ip)
Returns the amount of time in seconds it takes to execute the weaken() Netscript function " + + "on the server specified by the hostname/ip. The argument must be a string with the hostname/ip of the target server.

" + + "

Hacknet Nodes API


" + + "Netscript provides the following API for accessing and upgrading your Hacknet Nodes through scripts. This API does NOT work offline.

" + + "hacknetnodes
A special variable. This is an array that maps to the Player's Hacknet Nodes. The Hacknet Nodes are accessed through " + + "indexes. These indexes correspond to the number at the end of the name of the Hacknet Node. For example, the first Hacknet Node you purchase " + + "will have the same 'hacknet-node-0' and can be accessed with hacknetnodes[0]. The fourth Hacknet Node you purchase will have the name " + + "'hacknet-node-3' and can be accessed with hacknetnodes[3].

" + + "hacknetnodes.length
Returns the number of Hacknet Nodes that the player owns

" + + "hacknetnodes[i].level
Returns the level of the corresponding Hacknet Node

" + + "hacknetnodes[i].ram
Returns the amount of RAM on the corresponding Hacknet Node

" + + "hacknetnodes[i].cores
Returns the number of cores on the corresponding Hacknet Node

" + + "hacknetnodes[i].upgradeLevel(n)
Tries to upgrade the level of the corresponding Hacknet Node n times. The argument n must be a " + + "positive integer. Returns true if the Hacknet Node's level is successfully upgraded n times or up to the max level (200), and false otherwise.

" + + "hacknetnodes[i].upgradeRam()
Tries to upgrade the amount of RAM on the corresponding Hacknet Node. Returns true if the " + + "RAM is successfully upgraded, and false otherwise.

" + + "hacknetnodes[i].upgradeCore()
Attempts to purchase an additional core for the corresponding Hacknet Node. Returns true if the " + + "additional core is successfully purchase, and false otherwise.

" + + "Example: The following is an example of one way a script can be used to automate the purchasing and upgrading of Hacknet Nodes. " + + "This script purchases new Hacknet Nodes until the player has four. Then, it iteratively upgrades each of those four Hacknet Nodes " + + "to a level of at least 75, RAM to at least 8GB, and number of cores to at least 2.

" + + "while(hacknetnodes.length < 4) {
" + + "    purchaseHacknetNode();
" + + "}
" + + "for (i = 0; i < 4; i = i++) {
" + + "    while (hacknetnodes[i].level <= 75) {
" + + "        hacknetnodes[i].upgradeLevel(5);
" + + "        sleep(10000);
" + + "    }
" + + "}
" + + "for (i = 0; i < 4; i = i++) {
" + + "    while (hacknetnodes[i].ram < 8) {
" + + "        hacknetnodes[i].upgradeRam();
" + + "        sleep(10000);
" + + "    }
" + + "}
" + + "for (i = 0; i < 4; i = i++) {
" + + "    while (hacknetnodes[i].cores < 2) {
" + + "        hacknetnodes[i].upgradeCore();
" + + "        sleep(10000);
" + + "    }
" + + "}

" + + "

Trade Information eXchange (TIX) API


" + + "getStockPrice(sym)
Returns the price of a stock. The argument passed in must be the stock's symbol (NOT THE COMPANY NAME!). The symbol " + + "is a sequence of two to four capital letters. The symbol argument must be a string.

" + + "Example: getStockPrice('FSIG');

" + + "getStockPosition(sym)
Returns an array of two elements that represents the player's position in a stock. The first element " + + "in the array is the number of shares the player owns of the specified stock. The second element in the array is the average price of the player's " + + "shares. Both elements are numbers. The argument passed in must be the stock's symbol, which is a sequence of two to four capital letters.

" + + "Example:

pos = getStockPosition('ECP');
shares = pos[0];
avgPx = pos[1];

"+ + "buyStock(sym, shares)
Attempts to purchase shares of a stock. The first argument must be a string with the stock's symbol. The second argument " + + "must be the number of shares to purchase.

" + + "If the player does not have enough money to purchase specified number of shares, then no shares will be purchased (it will not purchase the most you can afford). " + + "Remember that every transaction on the stock exchange costs a certain commission fee.

" + + "The function will return true if it successfully purchases the specified number of shares of stock, and false otherwise.

" + + "sellStock(sym, shares)
Attempts to sell shares of a stock. The first argument must be a string with the stock's symbol. The second argument " + + "must be the number of shares to sell.

" + + "If the specified number of shares in the function exceeds the amount that the player actually owns, then this function will sell all owned shares. " + + "Remember that every transaction on the stock exchange costs a certain commission fee.

" + + "The net profit made from selling stocks with this function is reflected in the script's statistics. This net profit is calculated as:

" + + "shares * (sell price - average price of purchased shares)

" + + "This function will return true if the shares of stock are successfully sold and false otherwise.

" + + "

While loops


" + + "A while loop is a control flow statement that repeatedly executes code as long as a condition is met.

" + + "while ([cond]) {
    [code]
}


" + + "As long as [cond] remains true, the code block [code] will continuously execute. Example:

" + + "i = 0;
while (i < 10) {
    hack('foodnstuff');
    i = i + 1;
}


" + + "This code above repeats the 'hack('foodnstuff')' command 10 times before it stops and exits.

" + + "while(true) {
     hack('foodnstuff');
}


" + + "This while loop above is an infinite loop (continuously runs until the script is manually stopped) that repeatedly runs the 'hack('foodnstuff')' command. " + + "Note that a semicolon is needed at closing bracket of the while loop, UNLESS it is at the end of the code

" + + "

For loops


" + + "A for loop is another control flow statement that allows code to be repeated by iterations. The structure is:

" + + "for ([init]; [cond]; [post]) {
    code
}


" + + "The [init] expression evaluates before the for loop begins. The for loop will continue to execute " + + "as long as [cond] is met. The [post] expression will evaluate at the end of every iteration " + + "of the for loop. The following example shows code that will run the 'hack('foodnstuff');' command 10 times " + + " using a for loop:

" + + "for (i = 0; i < 10; i = i++) {
    hack('foodnstuff');
}


" + + "

If statements


" + + "If/Else if/Else statements are conditional statements used to perform different actions based on different conditions:

" + + "if (condition1) {
    code1
} else if (condition2) {
    code2
} else {
" + + "    code3
}


" + + "In the code above, first condition1 will be checked. If this condition is true, then code1 will execute and the " + + "rest of the if/else if/else statement will be skipped. If condition1 is NOT true, then the code will then go on to check " + + "condition2. If condition2 is true, then code2 will be executed, and the rest of the if/else if/else statement " + + "will be skipped. If none of the conditions are true, then the code within the else block (code3) will be executed. " + + "Note that a conditional statement can have any number of 'else if' statements.

" + + "Example:

" + + "if(getServerMoneyAvailable('foodnstuff') > 200000) {
    hack('foodnstuff');
" + + "} else {
    grow('foodnstuff');
}

" + + "The code above will use the getServerMoneyAvailable() function to check how much money there is on the 'foodnstuff' server. " + + "If there is more than $200,000, then it will try to hack that server. If there is $200,000 or less on the server, " + + "then the code will call grow('foodnstuff') instead and add more money to the server.

", + TutorialSingularityFunctionsText: "

Singularity Functions


" + + "The Singularity Functions are a special set of Netscript functions that are unlocked in BitNode-4. " + + "These functions allow you to control many additional aspects of the game through scripts, such as " + + "working for factions/companies, purchasing/installing Augmentations, and creating programs.

" + + "If you are in BitNode-4, then you will automatically have access to all of these functions. " + + "You can use the Singularity Functions in other BitNodes if and only if you have the Source-File " + + "for BitNode-4 (aka Source-File 4). Each level of Source-File 4 will open up additional Singularity " + + "Functions that you can use in other BitNodes. If your Source-File 4 is upgraded all the way to level 3, " + + "then you will be able to access all of the Singularity Functions.

" + + "Note that Singularity Functions require a lot of RAM outside of BitNode-4 (their RAM costs are multiplied by " + + "10 if you are not in BitNode-4).

" + + "universityCourse(universityName, courseName)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start taking a course at a university. If you are already " + + "in the middle of some 'working' action (such as working at a company, for a faction, or on a program), " + + "then running this function will automatically cancel that action and give you your earnings.

" + + "The first argument must be a string with the name of the university. The names are NOT case-sensitive. " + + "Note that you must be in the correct city for whatever university you specify. The three universities are:

" + + "Summit University
Rothman University
ZB Institute of Technology

" + + "The second argument must be a string with the name of the course you are taking. These names are NOT case-sensitive. " + + "The available courses are:

" + + "Study Computer Science
Data Structures
Networks
Algorithms
Management
Leadership

" + + "The cost and experience gains for all of these universities and classes are the same as if you were to manually " + + "visit and take these classes.

" + + "This function will return true if you successfully start taking the course, and false otherwise.

" + + "gymWorkout(gymName, stat)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working out at a gym to train a particular stat. If you are " + + "already in the middle of some 'working' action (such as working at a company, for a faction, or on a program), then " + + "running this function will automatically cancel that action and give you your earnings.

" + + "The first argument must be a string with the name of the gym. The names are NOT case-sensitive. Note that you must " + + "be in the correct city for whatever gym you specify. The available gyms are:

" + + "Crush Fitness Gym
Snap Fitness Gym
Iron Gym
Powerhouse Gym
Millenium Fitness Gym

" + + "The second argument must be a string with the stat you want to work out. These are NOT case-sensitive. " + + "The valid stats are:

strength OR str
defense OR def
dexterity OR dex
agility OR agi

" + + "The cost and experience gains for all of these gyms are the same as if you were to manually visit these gyms and train " + + "This function will return true if you successfully start working out at the gym, and false otherwise.

" + + "travelToCity(cityname)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function allows the player to travel to any city. The cost for using this function is the same as the cost for traveling through the Travel Agency.

" + + "The argument passed into this must be a string with the name of the city to travel to. Note that this argument IS CASE SENSITIVE. The valid cities are:

" + + "Aevum
Chongqing
Sector-12
New Tokyo
Ishima
Volhaven

" + + "This function will return true if you successfully travel to the specified city and false otherwise.

" + + "purchaseTor()
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function allows you to automatically purchase a TOR router. The cost for purchasing a TOR router using this " + + "function is the same as if you were to manually purchase one.

" + + "This function will return true if it successfully purchase a TOR router and false otherwise.

" + + "purchaseProgram(programName)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function allows you to automatically purchase programs. You MUST have a TOR router in order to use this function.

" + + "The argument passed in must be a string with the name of the program (including the '.exe' extension). This argument is " + + "NOT case-sensitive.

Example: " + + "purchaseProgram('brutessh.exe');

" + + "The cost of purchasing programs using this function is the same as if you were purchasing them through the Dark Web (using " + + "the buy Terminal command).

" + + "This function will return true if the specified program is purchased, and false otherwise.

" + + "upgradeHomeRam()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will upgrade amount of RAM on the player's home computer. The cost is the same as if you were to do it manually.

" + + "This function will return true if the player's home computer RAM is successfully upgraded, and false otherwise.

" + + "getUpgradeHomeRamCost()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "Returns the cost of upgrading the player's home computer RAM.

" + + "workForCompany()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working at the company at which you are employed. If you are already " + + "in the middle of some 'working' action (such as working for a faction, training at a gym, or creating a program), then " + + "running this function will automatically cancel that action and give you your earnings.

" + + "This function will return true if the player starts working, and false otherwise.

" + + "applyToCompany(companyName, field)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically try to apply to the specified company for a position in the specified field. This " + + "function can also be used to apply for promotions by specifying the company and field you are already employed at.

" + + "The first argument must be a string with the name of the company. This argument IS CASE-SENSITIVE. The second argument must " + + "be a string representing the 'field' to which you want to apply. This second argument is NOT case-sensitive. Valid values for " + + "the second argument are:

" + + "software
software consultant
it
security engineer
network engineer
business
business consultant
" + + "security
agent
employee
part-time employee
waiter
part-time waiter

" + + "This function will return true if you successfully get a job/promotion, and false otherwise. Note " + + "that if you are trying to use this function to apply for a promotion and you don't get one, it will return false.

" + + "getCompanyRep(companyName)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will return the amount of reputation you have at the specified company. If the company passed in as " + + "an argument is invalid, -1 will be returned.

" + + "The argument passed in must be a string with the name of the company. This argument IS CASE-SENSITIVE.

" + + "checkFactionInvitations()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "Returns an array with the name of all Factions you currently have oustanding invitations from.

" + + "joinFaction(name)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically accept an invitation from a faction and join it.

" + + "The argument must be a string with the name of the faction. This name IS CASE-SENSITIVE.

" + + "workForFaction(factionName, workType)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working for the specified Faction. Obviously, you " + + "must be a member of the Faction or else this function will fail. If you are already in the middle of " + + "some 'working' action (such as working for a company, training at a gym, or creating a program), then running " + + "this function will automatically cancel that action and give you your earnings.

" + + "The first argument must be a string with the name of the faction. This argument IS CASE-SENSITIVE. The second argument " + + "must be a string with the type of work you want to perform for the faction. The valid values for this argument are:

" + + "
hacking/hacking contracts/hackingcontracts
field/fieldwork/field work
security/securitywork/security work

" + + "This function will return true if you successfully start working for the specified faction, and false otherwise.

" + + "getFactionRep(factionName)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function returns the amount of reputation you have for the specified Faction. The argument must be a " + + "string with the name of the Faction. The argument IS CASE-SENSITIVE.

" + + "createProgram(programName)
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working on creating the specified program. If you are already in " + + "the middle of some 'working' action (such as working for a company, training at a gym, or taking a course), then " + + "running this function will automatically cancel that action and give you your earnings.

" + + "The argument passed in must be a string designating the name of the program. This argument is NOT case-sensitive.

" + + "Example:

createProgram('relaysmtp.exe');

" + + "Note that creating a program using this function has the same hacking level requirements as it normally would. These level requirements are:

" + + "BruteSSH.exe: 50
FTPCrack.exe: 100
relaySMTP.exe: 250
HTTPWorm.exe: 500
SQLInject.exe: 750
" + + "DeepscanV1.exe: 75
DeepscanV2.exe: 400
ServerProfiler.exe: 75
AutoLink.exe: 25

" + + "This function returns true if you successfully start working on the specified program, and false otherwise.

" + + "getAugmentationCost(augName)
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function returns an array with two elements that gives the cost for the specified Augmentation" + + ". The first element in the returned array is the reputation requirement of the Augmentation, and the second element " + + "is the money cost.

" + + "The argument passed in must be a string with the name of the Augmentation. This argument IS CASE-SENSITIVE. " + + "If an invalid Augmentation name is passed in, this function will return the array [-1, -1].

" + + "purchaseAugmentation(factionName, augName)
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function will try to purchase the specified Augmentation through the given Faction.

" + + "The two arguments must be strings specifying the name of the Faction and Augmentation, respectively. These arguments are both CASE-SENSITIVE.

" + + "This function will return true if the Augmentation is successfully purchased, and false otherwise.

" + + "installAugmentations()
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function will automatically install your Augmentations, resetting the game as usual.

" + + "It will return true if successful, and false otherwise.", + + TutorialTravelingText:"There are six major cities in the world that you are able to travel to:

" + + " Aevum
" + + " Chongqing
" + + " Sector-12
" + + " New Tokyo
" + + " Ishima
" + + " Volhaven

" + + "To travel between cities, visit your current city's travel agency through the 'World' page. " + + "From the travel agency you can travel to any other city. Doing so costs money.

" + + "Each city has its own set of companies and unique locations. Also, certain content is only available to you " + + "if you are in certain cities, so get exploring!", + TutorialCompaniesText: "Hacking is not the only way to gain money and experience! Located around the world are many " + + "different companies which you can work for. By working for a company you can earn money, " + + "train your various labor skills, and unlock powerful passive perks.

" + + "To apply for a job, visit the company you want to work for through the 'World' menu. The company " + + "page will have options that let you apply to positions in the company. There might be several different " + + "positions you can apply for, ranging from software engineer to business analyst to security officer.

" + + "When you apply for a job, you will get the offer if your stats are high enough. Your first position at " + + "a company will be an entry-level position such as 'intern'. Once you get the job, an button will appear on " + + "the company page that allows you to work for the company. Click this button to start working.

" + + "Working occurs in 8 hour shifts. Once you start working, you will begin earning money, experience, " + + "and reputation. The rate at which you money and experience depends on the company and your position. " + + "The amount of reputation you gain for your company is based on your job performance, which is affected by " + + "your stats. Different positions value different stats. When you are working, you are unable to perform any " + + "other actions such as using your terminal or visiting other locations (However, note that any scripts you have " + + "running on servers will continue to run as you work!). It is possible to cancel your work shift before the " + + "8 hours is up. However, if you have a full-time job, then cancelling a shift early will result in you gaining " + + "only half of the reputation " + + "that you had earned up to that point. There are also part-time/consultant jobs available where you will not " + + " be penalized if you cancel a work shift early. However, these positions pay less than full-time positions.

" + + "As you continue to work at a company, you will gain more and more reputation at that company. When your stats " + + "and reputation are high enough, you can get a promotion. You can apply for a promotion on the company page, just like " + + "you applied for the job originally. Higher positions at a company provide better salaries and stat gains.

" + + "

Infiltrating Companies


" + + "Many companies have facilities that you can attempt to infiltrate. By infiltrating, you can steal classified company secrets " + + "and then sell these for money or for faction reputation. To try and infiltrate a company, visit a company through the " + + "'World' menu. There will be an option that says 'Infiltrate Company'.

" + + "When infiltrating a company, you must progress through clearance levels in the facility. Every clearance level " + + "has some form of security that you must get past. There are several forms of security, ranging from high-tech security systems to " + + "armed guards. For each form of security, there are a variety of options that you can choose to try and bypass the security. Examples " + + "include hacking the security, engaging in combat, assassination, or sneaking past the security. The chance to succeed for each option " + + "is determined in part by your stats. So, for example, trying to hack the security system relies on your hacking skill, whereas trying to " + + "sneak past the security relies on your agility level.

" + + "The facility has a 'security level' that affects your chance of success when trying to get past a clearance level. " + + "Every time you advance to the next clearance level, the facility's security level will increase by a fixed amount. Furthermore " + + "the options you choose and whether you succeed or fail will affect the security level as well. For example, " + + "if you try to kill a security guard and fail, the security level will increase by a lot. If you choose to sneak past " + + "security and succeed, the security level will not increase at all.

" + + "Every 5 clearance levels, you will steal classified company secrets that can be sold for money or faction reputation. However, " + + "in order to sell these secrets you must successfully escape the facility using the 'Escape' option. Furthermore, companies have " + + "a max clearance level. If you reach the max clearance level you will automatically escape the facility with all of your " + + "stolen secrets.

", + TutorialFactionsText: "Throughout the game you may receive invitations from factions. There are many different factions, and each faction " + + "has different criteria for determining its potential members. Joining a faction and furthering its cause is crucial " + + "to progressing in the game and unlocking endgame content.

" + + "It is possible to join multiple factions if you receive invitations from them. However, note that joining a faction " + + "may prevent you from joining other rival factions.

" + + "The 'Factions' link on the menu brings up a list of all factions that you have joined. " + + "You can select a Faction on this list to go to that Faction page. This page displays general " + + "information about the Faction and also lets you perform work for the faction. " + + "Working for a Faction is similar to working for a company except that you don't get paid a salary. " + + "You will only earn reputation in your Faction and train your stats. Also, cancelling work early " + + "when working for a Faction does NOT result in reduced experience/reputation earnings.

" + + "Earning reputation for a Faction unlocks powerful Augmentations. Purchasing and installing these Augmentations will " + + "upgrade your abilities. The Augmentations that are available to unlock vary from faction to faction.", + TutorialAugmentationsText: "Advances in science and medicine have lead to powerful new technologies that allow people to augment themselves " + + "beyond normal human capabilities. There are many different types of Augmentations, ranging from cybernetic to " + + "genetic to biological. Acquiring these Augmentations enhances the user's physical and mental faculties.

" + + "Because of how powerful these Augmentations are, the technology behind them is kept private and secret by the " + + "corporations and organizations that create them. Therefore, the only way for the player to obtain Augmentations is " + + "through Factions. After joining a Faction and earning enough reputation in it, you will be able to purchase " + + "its Augmentations. Different Factions offer different Augmentations. Augmentations must be purchased in order to be installed, " + + "and they are fairly expensive.

" + + "When you purchase an Augmentation, the price of purchasing another Augmentation increases by 90%. This multiplier stacks for " + + "each Augmentation you purchase. You will not gain the benefits of your purchased Augmentations until you install them. You can " + + "choose to install Augmentations through the 'Augmentations' menu tab. Once you install your purchased Augmentations, " + + "their costs are reset back to the original price.

" + + "Unfortunately, installing Augmentations has side effects. You will lose most of the progress you've made, including your " + + "skills, stats, and money. You will have to start over, but you will have all of the Augmentations you have installed to " + + "help you progress.

" + + "To summarize, here is a list of everything you will LOSE when you install an Augmentation:

" + + "Stats/Skills
" + + "Money
" + + "Scripts on all servers EXCEPT your home computer
" + + "Purchased servers
" + + "Hacknet Nodes
" + + "Company/faction reputation
" + + "Jobs and Faction memberships
" + + "Programs
" + + "Stocks
" + + "TOR router

" + + "Here is everything you will KEEP when you install an Augmentation:

" + + "Every Augmentation you have installed
" + + "Scripts on your home computer
" + + "RAM Upgrades on your home computer
" + + "World Stock Exchange account and TIX API Access
", + + LatestUpdate: + "v0.28.1
" + + "-The script editor now uses the open-source Ace editor, which provides a much better experience when coding!
" + + "-Added tprint() Netscript function

" + + "v0.28.0
" + + "-Added BitNode-4: The Singularity
" + + "-Added BitNode-11: The Big Crash
" + + "-Migrated the codebase to use webpack (doesn't affect any in game content, except maybe some slight " + + "performance improvements and there may be bugs that result from dependency errors)" +} + + + + +/***/ }), +/* 4 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Engine", function() { return Engine; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__ = __webpack_require__(2); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__utils_GameOptions_js__ = __webpack_require__(37); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js__ = __webpack_require__(38); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__ = __webpack_require__(5); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__utils_LogBox_js__ = __webpack_require__(26); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__ActiveScriptsUI_js__ = __webpack_require__(27); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Augmentations_js__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__BitNode_js__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__Company_js__ = __webpack_require__(17); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__Constants_js__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__CreateProgram_js__ = __webpack_require__(14); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__Faction_js__ = __webpack_require__(10); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__Location_js__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__Gang_js__ = __webpack_require__(29); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__HacknetNode_js__ = __webpack_require__(32); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__InteractiveTutorial_js__ = __webpack_require__(22); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__Literature_js__ = __webpack_require__(43); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__Message_js__ = __webpack_require__(24); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__NetscriptFunctions_js__ = __webpack_require__(39); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_20__NetscriptWorker_js__ = __webpack_require__(15); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_21__Player_js__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_22__Prestige_js__ = __webpack_require__(31); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__RedPill_js__ = __webpack_require__(44); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__ = __webpack_require__(58); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_25__Script_js__ = __webpack_require__(18); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_26__Server_js__ = __webpack_require__(6); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_27__Settings_js__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_28__SourceFile_js__ = __webpack_require__(30); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_29__SpecialServerIps_js__ = __webpack_require__(11); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_30__StockMarket_js__ = __webpack_require__(25); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_31__Terminal_js__ = __webpack_require__(19); +var ace = __webpack_require__(33); +__webpack_require__(35); +__webpack_require__(36); +__webpack_require__(49); +__webpack_require__(50); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* Shortcuts to navigate through the game + * Alt-t - Terminal + * Alt-c - Character + * Alt-e - Script editor + * Alt-s - Active scripts + * Alt-h - Hacknet Nodes + * Alt-w - City + * Alt-j - Job + * Alt-r - Travel Agency of current city + * Alt-p - Create program + * Alt-f - Factions + * Alt-a - Augmentations + * Alt-u - Tutorial + * Alt-o - Options + */ +$(document).keydown(function(e) { + if (!__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].isWorking && !__WEBPACK_IMPORTED_MODULE_23__RedPill_js__["b" /* redPillFlag */]) { + if (e.keyCode == 84 && e.altKey) { + e.preventDefault(); + Engine.loadTerminalContent(); + } else if (e.keyCode == 67 && e.altKey) { + e.preventDefault(); + Engine.loadCharacterContent(); + } else if (e.keyCode == 69 && e.altKey) { + e.preventDefault(); + Engine.loadScriptEditorContent(); + } else if (e.keyCode == 83 && e.altKey) { + e.preventDefault(); + Engine.loadActiveScriptsContent(); + } else if (e.keyCode == 72 && e.altKey) { + e.preventDefault(); + Engine.loadHacknetNodesContent(); + } else if (e.keyCode == 87 && e.altKey) { + e.preventDefault(); + Engine.loadWorldContent(); + } else if (e.keyCode == 74 && e.altKey) { + e.preventDefault(); + Engine.loadJobContent(); + } else if (e.keyCode == 82 && e.altKey) { + e.preventDefault(); + Engine.loadTravelContent(); + } else if (e.keyCode == 80 && e.altKey) { + e.preventDefault(); + Engine.loadCreateProgramContent(); + } else if (e.keyCode == 70 && e.altKey) { + e.preventDefault(); + Engine.loadFactionsContent(); + } else if (e.keyCode == 65 && e.altKey) { + e.preventDefault(); + Engine.loadAugmentationsContent(); + } else if (e.keyCode == 85 && e.altKey) { + e.preventDefault(); + Engine.loadTutorialContent(); + } + } + + if (e.keyCode == 79 && e.altKey) { + e.preventDefault(); + Object(__WEBPACK_IMPORTED_MODULE_1__utils_GameOptions_js__["b" /* gameOptionsBoxOpen */])(); + } +}); + +let Engine = { + version: "", + Debug: true, + + //Clickable objects + Clickables: { + //Main menu buttons + terminalMainMenuButton: null, + characterMainMenuButton: null, + scriptEditorMainMenuButton: null, + activeScriptsMainMenuButton: null, + hacknetNodesMainMenuButton: null, + worldMainMenuButton: null, + travelMainMenuButton: null, + jobMainMenuButton: null, + createProgramMainMenuButton: null, + factionsMainMenuButton: null, + augmentationsMainMenuButton: null, + tutorialMainMenuButton: null, + saveMainMenuButton: null, + deleteMainMenuButton: null, + + //Tutorial buttons + tutorialNetworkingButton: null, + tutorialHackingButton: null, + tutorialScriptsButton: null, + tutorialNetscriptButton: null, + tutorialTravelingButton: null, + tutorialCompaniesButton: null, + tutorialFactionsButton: null, + tutorialAugmentationsButton: null, + tutorialBackButton: null, + }, + + //Display objects + Display: { + //Progress bar + progress: null, + + //Display for status text (such as "Saved" or "Loaded") + statusText: null, + + hacking_skill: null, + + //Main menu content + terminalContent: null, + characterContent: null, + scriptEditorContent: null, + activeScriptsContent: null, + hacknetNodesContent: null, + worldContent: null, + createProgramContent: null, + factionsContent: null, + factionContent: null, + factionAugmentationsContent: null, + augmentationsContent: null, + tutorialContent: null, + infiltrationContent: null, + stockMarketContent: null, + locationContent: null, + workInProgressContent: null, + redPillContent: null, + + //Character info + characterInfo: null, + }, + + //Current page status + Page: { + Terminal: "Terminal", + CharacterInfo: "CharacterInfo", + ScriptEditor: "ScriptEditor", + ActiveScripts: "ActiveScripts", + HacknetNodes: "HacknetNodes", + World: "World", + CreateProgram: "CreateProgram", + Factions: "Factions", + Faction: "Faction", + Augmentations: "Augmentations", + Tutorial: "Tutorial", + Location: "Location", + workInProgress: "WorkInProgress", + RedPill: "RedPill", + Infiltration: "Infiltration", + StockMarket: "StockMarket", + Gang: "Gang", + }, + currentPage: null, + + + //Time variables (milliseconds unix epoch time) + _lastUpdate: new Date().getTime(), + _idleSpeed: 200, //Speed (in ms) at which the main loop is updated + + + /* Load content when a main menu button is clicked */ + loadTerminalContent: function() { + Engine.hideAllContent(); + Engine.Display.terminalContent.style.visibility = "visible"; + Engine.currentPage = Engine.Page.Terminal; + document.getElementById("terminal-menu-link").classList.add("active"); + }, + + loadCharacterContent: function() { + Engine.hideAllContent(); + Engine.Display.characterContent.style.visibility = "visible"; + Engine.displayCharacterInfo(); + Engine.currentPage = Engine.Page.CharacterInfo; + document.getElementById("stats-menu-link").classList.add("active"); + }, + + loadScriptEditorContent: function(filename = "", code = "") { + Engine.hideAllContent(); + Engine.Display.scriptEditorContent.style.visibility = "visible"; + var editor = ace.edit('javascript-editor'); + if (filename != "") { + document.getElementById("script-editor-filename").value = filename; + editor.setValue(code); + } + editor.focus(); + Object(__WEBPACK_IMPORTED_MODULE_25__Script_js__["f" /* updateScriptEditorContent */])(); + Engine.currentPage = Engine.Page.ScriptEditor; + document.getElementById("create-script-menu-link").classList.add("active"); + }, + + loadActiveScriptsContent: function() { + Engine.hideAllContent(); + Engine.Display.activeScriptsContent.style.visibility = "visible"; + Object(__WEBPACK_IMPORTED_MODULE_6__ActiveScriptsUI_js__["c" /* setActiveScriptsClickHandlers */])(); + Engine.currentPage = Engine.Page.ActiveScripts; + document.getElementById("active-scripts-menu-link").classList.add("active"); + }, + + loadHacknetNodesContent: function() { + Engine.hideAllContent(); + Engine.Display.hacknetNodesContent.style.visibility = "visible"; + Object(__WEBPACK_IMPORTED_MODULE_15__HacknetNode_js__["a" /* displayHacknetNodesContent */])(); + Engine.currentPage = Engine.Page.HacknetNodes; + document.getElementById("hacknet-nodes-menu-link").classList.add("active"); + }, + + loadWorldContent: function() { + Engine.hideAllContent(); + Engine.Display.worldContent.style.visibility = "visible"; + Engine.displayWorldInfo(); + Engine.currentPage = Engine.Page.World; + document.getElementById("city-menu-link").classList.add("active"); + }, + + loadCreateProgramContent: function() { + Engine.hideAllContent(); + Engine.Display.createProgramContent.style.visibility = "visible"; + Object(__WEBPACK_IMPORTED_MODULE_11__CreateProgram_js__["b" /* displayCreateProgramContent */])(); + Engine.currentPage = Engine.Page.CreateProgram; + document.getElementById("create-program-menu-link").classList.add("active"); + }, + + loadFactionsContent: function() { + Engine.hideAllContent(); + Engine.Display.factionsContent.style.visibility = "visible"; + Engine.displayFactionsInfo(); + Engine.currentPage = Engine.Page.Factions; + document.getElementById("factions-menu-link").classList.add("active"); + }, + + loadFactionContent: function() { + Engine.hideAllContent(); + Engine.Display.factionContent.style.visibility = "visible"; + Engine.currentPage = Engine.Page.Faction; + }, + + loadAugmentationsContent: function() { + Engine.hideAllContent(); + Engine.Display.augmentationsContent.style.visibility = "visible"; + Engine.displayAugmentationsContent(); + Engine.currentPage = Engine.Page.Augmentations; + document.getElementById("augmentations-menu-link").classList.add("active"); + }, + + loadTutorialContent: function() { + Engine.hideAllContent(); + Engine.Display.tutorialContent.style.visibility = "visible"; + Engine.displayTutorialContent(); + Engine.currentPage = Engine.Page.Tutorial; + document.getElementById("tutorial-menu-link").classList.add("active"); + }, + + loadLocationContent: function() { + Engine.hideAllContent(); + Engine.Display.locationContent.style.visibility = "visible"; + Object(__WEBPACK_IMPORTED_MODULE_13__Location_js__["b" /* displayLocationContent */])(); + Engine.currentPage = Engine.Page.Location; + }, + + loadTravelContent: function() { + switch(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].city) { + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Aevum: + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].AevumTravelAgency; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Chongqing: + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].ChongqingTravelAgency; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Sector12: + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Sector12TravelAgency; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].NewTokyo: + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].NewTokyoTravelAgency; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Ishima: + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].IshimaTravelAgency; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Volhaven: + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].VolhavenTravelAgency; + break; + default: + Object(__WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__["a" /* dialogBoxCreate */])("ERROR: Invalid city. This is a bug please contact game dev"); + break; + } + Engine.loadLocationContent(); + }, + + loadJobContent: function() { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].companyName == "") { + Object(__WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__["a" /* dialogBoxCreate */])("You do not currently have a job! You can visit various companies " + + "in the city and try to find a job."); + return; + } + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].location = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].companyName; + Engine.loadLocationContent(); + }, + + loadWorkInProgressContent: function() { + Engine.hideAllContent(); + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "hidden"; + Engine.Display.workInProgressContent.style.visibility = "visible"; + Engine.currentPage = Engine.Page.WorkInProgress; + }, + + loadRedPillContent: function() { + Engine.hideAllContent(); + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "hidden"; + Engine.Display.redPillContent.style.visibility = "visible"; + Engine.currentPage = Engine.Page.RedPill; + }, + + loadInfiltrationContent: function() { + Engine.hideAllContent(); + Engine.Display.infiltrationContent.style.visibility = "visible"; + Engine.currentPage = Engine.Page.Infiltration; + }, + + loadStockMarketContent: function() { + Engine.hideAllContent(); + Engine.Display.stockMarketContent.style.visibility = "visible"; + Object(__WEBPACK_IMPORTED_MODULE_30__StockMarket_js__["c" /* displayStockMarketContent */])(); + Engine.currentPage = Engine.Page.StockMarket; + }, + + loadGangContent: function() { + Engine.hideAllContent(); + if (document.getElementById("gang-container") || __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].inGang()) { + Object(__WEBPACK_IMPORTED_MODULE_14__Gang_js__["c" /* displayGangContent */])(); + Engine.currentPage = Engine.Page.Gang; + } else { + Engine.loadTerminalContent(); + Engine.currentPage = Engine.Page.Terminal; + } + + }, + + //Helper function that hides all content + hideAllContent: function() { + Engine.Display.terminalContent.style.visibility = "hidden"; + Engine.Display.characterContent.style.visibility = "hidden"; + Engine.Display.scriptEditorContent.style.visibility = "hidden"; + Engine.Display.activeScriptsContent.style.visibility = "hidden"; + Engine.Display.hacknetNodesContent.style.visibility = "hidden"; + Engine.Display.worldContent.style.visibility = "hidden"; + Engine.Display.createProgramContent.style.visibility = "hidden"; + Engine.Display.factionsContent.style.visibility = "hidden"; + Engine.Display.factionContent.style.visibility = "hidden"; + Engine.Display.factionAugmentationsContent.style.visibility = "hidden"; + Engine.Display.augmentationsContent.style.visibility = "hidden"; + Engine.Display.tutorialContent.style.visibility = "hidden"; + Engine.Display.locationContent.style.visibility = "hidden"; + Engine.Display.workInProgressContent.style.visibility = "hidden"; + Engine.Display.redPillContent.style.visibility = "hidden"; + Engine.Display.infiltrationContent.style.visibility = "hidden"; + Engine.Display.stockMarketContent.style.visibility = "hidden"; + if (document.getElementById("gang-container")) { + document.getElementById("gang-container").style.visibility = "hidden"; + } + + //Location lists + Engine.aevumLocationsList.style.display = "none"; + Engine.chongqingLocationsList.style.display = "none"; + Engine.sector12LocationsList.style.display = "none"; + Engine.newTokyoLocationsList.style.display = "none"; + Engine.ishimaLocationsList.style.display = "none"; + Engine.volhavenLocationsList.style.display = "none"; + + //Make nav menu tabs inactive + document.getElementById("terminal-menu-link").classList.remove("active"); + document.getElementById("create-script-menu-link").classList.remove("active"); + document.getElementById("active-scripts-menu-link").classList.remove("active"); + document.getElementById("create-program-menu-link").classList.remove("active"); + document.getElementById("stats-menu-link").classList.remove("active"); + document.getElementById("factions-menu-link").classList.remove("active"); + document.getElementById("augmentations-menu-link").classList.remove("active"); + document.getElementById("hacknet-nodes-menu-link").classList.remove("active"); + document.getElementById("city-menu-link").classList.remove("active"); + document.getElementById("tutorial-menu-link").classList.remove("active"); + document.getElementById("options-menu-link").classList.remove("active"); + }, + + displayCharacterOverviewInfo: function() { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hp == null) {__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hp = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].max_hp;} + document.getElementById("character-overview-text").innerHTML = + ("Hp: " + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hp + " / " + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].max_hp + "
" + + "Money: " + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].money.toNumber()).format('($0.000a)') + "
" + + "Hack: " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_skill).toLocaleString() + "
" + + "Str: " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].strength).toLocaleString() + "
" + + "Def: " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].defense).toLocaleString() + "
" + + "Dex: " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].dexterity).toLocaleString() + "
" + + "Agi: " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].agility).toLocaleString() + "
" + + "Cha: " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].charisma).toLocaleString() + ).replace( / /g, " " ); + }, + + /* Display character info */ + displayCharacterInfo: function() { + var companyPosition = ""; + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].companyPosition != "") { + companyPosition = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].companyPosition.positionName; + } + Engine.Display.characterInfo.innerHTML = + ('General

' + + 'Current City: ' + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].city + '

' + + 'Employer: ' + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].companyName + '
' + + 'Job Title: ' + companyPosition + '

' + + 'Money: $' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].money.toNumber(), 2)+ '


' + + 'Stats

' + + 'Hacking Level: ' + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_skill).toLocaleString() + + " (" + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_exp).format('(0.000a)') + ' experience)
' + + 'Strength: ' + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].strength).toLocaleString() + + " (" + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].strength_exp).format('(0.000a)') + ' experience)
' + + 'Defense: ' + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].defense).toLocaleString() + + " (" + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].defense_exp).format('(0.000a)')+ ' experience)
' + + 'Dexterity: ' + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].dexterity).toLocaleString() + + " (" + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].dexterity_exp).format('(0.000a)') + ' experience)
' + + 'Agility: ' + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].agility).toLocaleString() + + " (" + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].agility_exp).format('(0.000a)') + ' experience)
' + + 'Charisma: ' + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].charisma).toLocaleString() + + " (" + __WEBPACK_IMPORTED_MODULE_3__utils_numeral_min_js___default()(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].charisma_exp).format('(0.000a)') + ' experience)


' + + 'Multipliers

' + + 'Hacking Chance multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_chance_mult * 100, 2) + '%
' + + 'Hacking Speed multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_speed_mult * 100, 2) + '%
' + + 'Hacking Money multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_money_mult * 100, 2) + '%
' + + 'Hacking Growth multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_grow_mult * 100, 2) + '%

' + + 'Hacking Level multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_mult * 100, 2) + '%
' + + 'Hacking Experience multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacking_exp_mult * 100, 2) + '%

' + + 'Strength Level multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].strength_mult * 100, 2) + '%
' + + 'Strength Experience multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].strength_exp_mult * 100, 2) + '%

' + + 'Defense Level multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].defense_mult * 100, 2) + '%
' + + 'Defense Experience multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].defense_exp_mult * 100, 2) + '%

' + + 'Dexterity Level multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].dexterity_mult * 100, 2) + '%
' + + 'Dexterity Experience multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].dexterity_exp_mult * 100, 2) + '%

' + + 'Agility Level multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].agility_mult * 100, 2) + '%
' + + 'Agility Experience multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].agility_exp_mult * 100, 2) + '%

' + + 'Charisma Level multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].charisma_mult * 100, 2) + '%
' + + 'Charisma Experience multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].charisma_exp_mult * 100, 2) + '%

' + + 'Hacknet Node production multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacknet_node_money_mult * 100, 2) + '%
' + + 'Hacknet Node purchase cost multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacknet_node_purchase_cost_mult * 100, 2) + '%
' + + 'Hacknet Node RAM upgrade cost multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacknet_node_ram_cost_mult * 100, 2) + '%
' + + 'Hacknet Node Core purchase cost multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacknet_node_core_cost_mult * 100, 2) + '%
' + + 'Hacknet Node level upgrade cost multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacknet_node_level_cost_mult * 100, 2) + '%

' + + 'Company reputation gain multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].company_rep_mult * 100, 2) + '%
' + + 'Faction reputation gain multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].faction_rep_mult * 100, 2) + '%
' + + 'Salary multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].work_money_mult * 100, 2) + '%
' + + 'Crime success multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].crime_success_mult * 100, 2) + '%
' + + 'Crime money multiplier: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].crime_money_mult * 100, 2) + '%


' + + 'Misc

' + + 'Servers owned: ' + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].purchasedServers.length + '
' + + 'Hacknet Nodes owned: ' + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hacknetNodes.length + '
' + + 'Augmentations installed: ' + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].augmentations.length + '
' + + 'Time played since last Augmentation: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug) + '
' + + 'Time played: ' + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["b" /* convertTimeMsToTimeElapsedString */])(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime) + '


').replace( / /g, " " ); + }, + + /* Display locations in the world*/ + aevumLocationsList: null, + chongqingLocationsList: null, + sector12LocationsList: null, + newTokyoLocationsList: null, + ishimaLocationsList: null, + volhavenLocationsList: null, + + displayWorldInfo: function() { + Engine.aevumLocationsList.style.display = "none"; + Engine.chongqingLocationsList.style.display = "none"; + Engine.sector12LocationsList.style.display = "none"; + Engine.newTokyoLocationsList.style.display = "none"; + Engine.ishimaLocationsList.style.display = "none"; + Engine.volhavenLocationsList.style.display = "none"; + + document.getElementById("world-city-name").innerHTML = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].city; + var cityDesc = document.getElementById("world-city-desc"); //TODO + switch(__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].city) { + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Aevum: + Engine.aevumLocationsList.style.display = "inline"; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Chongqing: + Engine.chongqingLocationsList.style.display = "inline"; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Sector12: + Engine.sector12LocationsList.style.display = "inline"; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].NewTokyo: + Engine.newTokyoLocationsList.style.display = "inline"; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Ishima: + Engine.ishimaLocationsList.style.display = "inline"; + break; + case __WEBPACK_IMPORTED_MODULE_13__Location_js__["a" /* Locations */].Volhaven: + Engine.volhavenLocationsList.style.display = "inline"; + break; + default: + console.log("Invalid city value in Player object!"); + break; + } + + document.getElementById("generic-locations-list").style.display = "inline"; + }, + + displayFactionsInfo: function() { + //Clear the list of joined factions + var factionsList = document.getElementById("factions-list"); + while (factionsList.firstChild) { + factionsList.removeChild(factionsList.firstChild); + } + + //Re-add a link for each faction you are a member of + for (var i = 0; i < __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factions.length; ++i) { + (function () { + var factionName = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factions[i]; + + //Add the faction to the Factions page content + var item = document.createElement("li"); + var aElem = document.createElement("a"); + aElem.setAttribute("class", "a-link-button"); + aElem.innerHTML = factionName; + aElem.addEventListener("click", function() { + Engine.loadFactionContent(); + Object(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["c" /* displayFactionContent */])(factionName); + return false; + }); + item.appendChild(aElem); + factionsList.appendChild(item); + }()); //Immediate invocation + } + + //Clear the list of invitations + var invitationsList = document.getElementById("outstanding-faction-invitations-list"); + while (invitationsList.firstChild) { + invitationsList.removeChild(invitationsList.firstChild); + } + + //Add a link to accept for each faction you have invitiations for + for (var i = 0; i < __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factionInvitations.length; ++i) { + (function () { + var factionName = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factionInvitations[i]; + + var item = document.createElement("li"); + + var pElem = document.createElement("p"); + pElem.innerText = factionName; + pElem.style.display = "inline"; + pElem.style.margin = "4px"; + pElem.style.padding = "4px"; + + var aElem = document.createElement("a"); + aElem.innerText = "Accept Faction Invitation"; + aElem.setAttribute("class", "a-link-button"); + aElem.style.display = "inline"; + aElem.style.margin = "4px"; + aElem.style.padding = "4px"; + aElem.addEventListener("click", function() { + Object(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["h" /* joinFaction */])(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["b" /* Factions */][factionName]); + for (var i = 0; i < __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factionInvitations.length; ++i) { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factionInvitations[i] == factionName) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].factionInvitations.splice(i, 1); + break; + } + } + Engine.displayFactionsInfo(); + return false; + }); + + item.appendChild(pElem); + item.appendChild(aElem); + item.style.margin = "6px"; + item.style.padding = "6px"; + invitationsList.appendChild(item); + }()); + } + }, + + displayAugmentationsContent: function() { + //Purchased/queued augmentations + var queuedAugmentationsList = document.getElementById("queued-augmentations-list"); + + while (queuedAugmentationsList.firstChild) { + queuedAugmentationsList.removeChild(queuedAugmentationsList.firstChild); + } + + for (var i = 0; i < __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].queuedAugmentations.length; ++i) { + var augName = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].queuedAugmentations[i].name; + var aug = __WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["c" /* Augmentations */][augName]; + + var item = document.createElement("li"); + var hElem = document.createElement("h2"); + var pElem = document.createElement("p"); + + item.setAttribute("class", "installed-augmentation"); + hElem.innerHTML = augName; + if (augName == __WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["b" /* AugmentationNames */].NeuroFluxGovernor) { + hElem.innerHTML += " - Level " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].queuedAugmentations[i].level); + } + pElem.innerHTML = aug.info; + + item.appendChild(hElem); + item.appendChild(pElem); + + queuedAugmentationsList.appendChild(item); + } + + //Install Augmentations button + var installButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("install-augmentations-button"); + installButton.addEventListener("click", function() { + Object(__WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["h" /* installAugmentations */])(); + return false; + }); + + //Installed augmentations + var augmentationsList = document.getElementById("augmentations-list"); + + while (augmentationsList.firstChild) { + augmentationsList.removeChild(augmentationsList.firstChild); + } + + //Source Files - Temporary...Will probably put in a separate pane Later + for (var i = 0; i < __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].sourceFiles.length; ++i) { + var srcFileKey = "SourceFile" + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].sourceFiles[i].n; + var sourceFileObject = __WEBPACK_IMPORTED_MODULE_28__SourceFile_js__["b" /* SourceFiles */][srcFileKey]; + if (sourceFileObject == null) { + console.log("ERROR: Invalid source file number: " + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].sourceFiles[i].n); + continue; + } + var item = document.createElement("li"); + var hElem = document.createElement("h2"); + var pElem = document.createElement("p"); + + item.setAttribute("class", "installed-augmentation"); + hElem.innerHTML = sourceFileObject.name + "
"; + hElem.innerHTML += "Level " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].sourceFiles[i].lvl) + " / 3"; + pElem.innerHTML = sourceFileObject.info; + + item.appendChild(hElem); + item.appendChild(pElem); + + augmentationsList.appendChild(item); + } + + for (var i = 0; i < __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].augmentations.length; ++i) { + var augName = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].augmentations[i].name; + var aug = __WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["c" /* Augmentations */][augName]; + + var item = document.createElement("li"); + var hElem = document.createElement("h2"); + var pElem = document.createElement("p"); + + item.setAttribute("class", "installed-augmentation"); + hElem.innerHTML = augName; + if (augName == __WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["b" /* AugmentationNames */].NeuroFluxGovernor) { + hElem.innerHTML += " - Level " + (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].augmentations[i].level); + } + pElem.innerHTML = aug.info; + + item.appendChild(hElem); + item.appendChild(pElem); + + augmentationsList.appendChild(item); + } + }, + + displayTutorialContent: function() { + document.getElementById("tutorial-getting-started-link").style.display = "block"; + Engine.Clickables.tutorialNetworkingButton.style.display = "block"; + Engine.Clickables.tutorialHackingButton.style.display = "block"; + Engine.Clickables.tutorialScriptsButton.style.display = "block"; + Engine.Clickables.tutorialNetscriptButton.style.display = "block"; + Engine.Clickables.tutorialTravelingButton.style.display = "block"; + Engine.Clickables.tutorialCompaniesButton.style.display = "block"; + Engine.Clickables.tutorialFactionsButton.style.display = "block"; + Engine.Clickables.tutorialAugmentationsButton.style.display = "block"; + document.getElementById("tutorial-shortcuts-link").style.display = "block"; + + Engine.Clickables.tutorialBackButton.style.display = "none"; + document.getElementById("tutorial-text").style.display = "none"; + }, + + //Displays the text when a section of the Tutorial is opened + displayTutorialPage: function(text) { + document.getElementById("tutorial-getting-started-link").style.display = "none"; + Engine.Clickables.tutorialNetworkingButton.style.display = "none"; + Engine.Clickables.tutorialHackingButton.style.display = "none"; + Engine.Clickables.tutorialScriptsButton.style.display = "none"; + Engine.Clickables.tutorialNetscriptButton.style.display = "none"; + Engine.Clickables.tutorialTravelingButton.style.display = "none"; + Engine.Clickables.tutorialCompaniesButton.style.display = "none"; + Engine.Clickables.tutorialFactionsButton.style.display = "none"; + Engine.Clickables.tutorialAugmentationsButton.style.display = "none"; + document.getElementById("tutorial-shortcuts-link").style.display = "none"; + + Engine.Clickables.tutorialBackButton.style.display = "inline-block"; + document.getElementById("tutorial-text").style.display = "block"; + document.getElementById("tutorial-text").innerHTML = text; + }, + + /* Main Event Loop */ + idleTimer: function() { + //Get time difference + var _thisUpdate = new Date().getTime(); + var diff = _thisUpdate - Engine._lastUpdate; + var offset = diff % Engine._idleSpeed; + + //Divide this by cycle time to determine how many cycles have elapsed since last update + diff = Math.floor(diff / Engine._idleSpeed); + + if (diff > 0) { + //Update the game engine by the calculated number of cycles + Engine._lastUpdate = _thisUpdate - offset; + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].lastUpdate = _thisUpdate - offset; + Engine.updateGame(diff); + } + + window.requestAnimationFrame(Engine.idleTimer); + }, + + updateGame: function(numCycles = 1) { + //Update total playtime + var time = numCycles * Engine._idleSpeed; + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime == null) {__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime = 0;} + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug == null) {__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug = 0;} + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime += time; + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug += time; + + //Start Manual hack + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].startAction == true) { + Engine._totalActionTime = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].actionTime; + Engine._actionTimeLeft = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].actionTime; + Engine._actionInProgress = true; + Engine._actionProgressBarCount = 1; + Engine._actionProgressStr = "[ ]"; + Engine._actionTimeStr = "Time left: "; + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].startAction = false; + } + + //Working + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].isWorking) { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeFaction) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workForFaction(numCycles); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCreateProgram) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].createProgramWork(numCycles); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeStudyClass) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].takeClass(numCycles); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCrime) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].commitCrime(numCycles); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCompanyPartTime) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workPartTime(numCycles); + } else { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].work(numCycles); + } + } + + //Gang, if applicable + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].bitNodeN == 2 && __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].inGang()) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].gang.process(numCycles); + } + + //Counters + Engine.decrementAllCounters(numCycles); + Engine.checkCounters(); + + //Manual hacks + if (Engine._actionInProgress == true) { + Engine.updateHackProgress(numCycles); + } + + //Update the running time of all active scripts + Object(__WEBPACK_IMPORTED_MODULE_20__NetscriptWorker_js__["g" /* updateOnlineScriptTimes */])(numCycles); + + //Hacknet Nodes + Object(__WEBPACK_IMPORTED_MODULE_15__HacknetNode_js__["c" /* processAllHacknetNodeEarnings */])(numCycles); + }, + + //Counters for the main event loop. Represent the number of game cycles are required + //for something to happen. + Counters: { + autoSaveCounter: 300, //Autosave every minute + updateSkillLevelsCounter: 10, //Only update skill levels every 2 seconds. Might improve performance + updateDisplays: 3, //Update displays such as Active Scripts display and character display + updateDisplaysMed: 9, + updateDisplaysLong: 15, + createProgramNotifications: 10, //Checks whether any programs can be created and notifies + checkFactionInvitations: 100, //Check whether you qualify for any faction invitations + passiveFactionGrowth: 600, + messages: 150, + stockTick: 30, //Update stock prices + sCr: 1500, + updateScriptEditorDisplay: 5, + }, + + decrementAllCounters: function(numCycles = 1) { + for (var counter in Engine.Counters) { + if (Engine.Counters.hasOwnProperty(counter)) { + Engine.Counters[counter] = Engine.Counters[counter] - numCycles; + } + } + }, + + //Checks if any counters are 0 and if they are, executes whatever + //is necessary and then resets the counter + checkCounters: function() { + if (Engine.Counters.autoSaveCounter <= 0) { + __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */].saveGame(); + Engine.Counters.autoSaveCounter = 300; + } + + if (Engine.Counters.updateSkillLevelsCounter <= 0) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].updateSkillLevels(); + Engine.Counters.updateSkillLevelsCounter = 10; + } + + if (Engine.Counters.updateDisplays <= 0) { + Engine.displayCharacterOverviewInfo(); + if (Engine.currentPage == Engine.Page.CharacterInfo) { + Engine.displayCharacterInfo(); + } else if (Engine.currentPage == Engine.Page.HacknetNodes) { + Object(__WEBPACK_IMPORTED_MODULE_15__HacknetNode_js__["e" /* updateHacknetNodesContent */])(); + } else if (Engine.currentPage == Engine.Page.CreateProgram) { + Object(__WEBPACK_IMPORTED_MODULE_11__CreateProgram_js__["b" /* displayCreateProgramContent */])(); + } + + if (__WEBPACK_IMPORTED_MODULE_5__utils_LogBox_js__["b" /* logBoxOpened */]) { + Object(__WEBPACK_IMPORTED_MODULE_5__utils_LogBox_js__["c" /* logBoxUpdateText */])(); + } + + Engine.Counters.updateDisplays = 3; + } + + if (Engine.Counters.updateDisplaysMed <= 0) { + if (Engine.currentPage == Engine.Page.ActiveScripts) { + Object(__WEBPACK_IMPORTED_MODULE_6__ActiveScriptsUI_js__["d" /* updateActiveScriptsItems */])(); + } + Engine.Counters.updateDisplaysMed = 9; + } + + if (Engine.Counters.updateDisplaysLong <= 0) { + if (Engine.currentPage === Engine.Page.Gang) { + Object(__WEBPACK_IMPORTED_MODULE_14__Gang_js__["e" /* updateGangContent */])(); + } + Engine.Counters.updateDisplaysLong = 15; + } + + if (Engine.Counters.createProgramNotifications <= 0) { + var num = Object(__WEBPACK_IMPORTED_MODULE_11__CreateProgram_js__["c" /* getNumAvailableCreateProgram */])(); + var elem = document.getElementById("create-program-notification"); + if (num > 0) { + elem.innerHTML = num; + elem.setAttribute("class", "notification-on"); + } else { + elem.innerHTML = ""; + elem.setAttribute("class", "notification-off"); + } + Engine.Counters.createProgramNotifications = 10; + } + + if (Engine.Counters.checkFactionInvitations <= 0) { + var invitedFactions = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].checkForFactionInvitations(); + if (invitedFactions.length > 0) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].firstFacInvRecvd = true; + var randFaction = invitedFactions[Math.floor(Math.random() * invitedFactions.length)]; + Object(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["g" /* inviteToFaction */])(randFaction); + } + Engine.Counters.checkFactionInvitations = 100; + } + + if (Engine.Counters.passiveFactionGrowth <= 0) { + var adjustedCycles = Math.floor((600 - Engine.Counters.passiveFactionGrowth)); + Object(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["j" /* processPassiveFactionRepGain */])(adjustedCycles); + Engine.Counters.passiveFactionGrowth = 600; + } + + if (Engine.Counters.messages <= 0) { + Object(__WEBPACK_IMPORTED_MODULE_18__Message_js__["c" /* checkForMessagesToSend */])(); + Engine.Counters.messages = 150; + } + + if (Engine.Counters.stockTick <= 0) { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hasWseAccount) { + Object(__WEBPACK_IMPORTED_MODULE_30__StockMarket_js__["k" /* updateStockPrices */])(); + } + Engine.Counters.stockTick = 30; + } + + if (Engine.Counters.sCr <= 0) { + //Assume 4Sig will always indicate state of market + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hasWseAccount) { + Object(__WEBPACK_IMPORTED_MODULE_30__StockMarket_js__["i" /* stockMarketCycle */])(); + } + Engine.Counters.sCr = 1500; + } + + if (Engine.Counters.updateScriptEditorDisplay <= 0) { + if (Engine.currentPage == Engine.Page.ScriptEditor) { + Object(__WEBPACK_IMPORTED_MODULE_25__Script_js__["f" /* updateScriptEditorContent */])(); + } + Engine.Counters.updateScriptEditorDisplay = 5; + } + }, + + /* Calculates the hack progress for a manual (non-scripted) hack and updates the progress bar/time accordingly */ + _totalActionTime: 0, + _actionTimeLeft: 0, + _actionTimeStr: "Time left: ", + _actionProgressStr: "[ ]", + _actionProgressBarCount: 1, + _actionInProgress: false, + updateHackProgress: function(numCycles = 1) { + var timeElapsedMilli = numCycles * Engine._idleSpeed; + Engine._actionTimeLeft -= (timeElapsedMilli/ 1000); //Substract idle speed (ms) + Engine._actionTimeLeft = Math.max(Engine._actionTimeLeft, 0); + + //Calculate percent filled + var percent = Math.round((1 - Engine._actionTimeLeft / Engine._totalActionTime) * 100); + + //Update progress bar + while (Engine._actionProgressBarCount * 2 <= percent) { + Engine._actionProgressStr = Engine._actionProgressStr.replaceAt(Engine._actionProgressBarCount, "|"); + Engine._actionProgressBarCount += 1; + } + + //Update hack time remaining + Engine._actionTimeStr = "Time left: " + Math.max(0, Math.round(Engine._actionTimeLeft)).toString() + "s"; + document.getElementById("hack-progress").innerHTML = Engine._actionTimeStr; + + //Dynamically update progress bar + document.getElementById("hack-progress-bar").innerHTML = Engine._actionProgressStr.replace( / /g, " " ); + + //Once percent is 100, the hack is completed + if (percent >= 100) { + Engine._actionInProgress = false; + __WEBPACK_IMPORTED_MODULE_31__Terminal_js__["a" /* Terminal */].finishAction(); + } + }, + + _prevTimeout: null, + createStatusText: function(txt) { + if (Engine._prevTimeout != null) { + clearTimeout(Engine._prevTimeout); + Engine._prevTimeout = null; + } + var statusText = document.getElementById("status-text") + statusText.style.display = "inline-block"; + statusText.setAttribute("class", "status-text"); + statusText.innerHTML = txt; + Engine._prevTimeout = setTimeout(function() { + statusText.style.display = "none"; + statusText.removeAttribute("class"); + statusText.innerHTML = ""; + }, 3000); + }, + + removeLoadingScreen: function() { + var loader = document.getElementById("loader"); + if (!loader) {return;} + while(loader.firstChild) { + loader.removeChild(loader.firstChild); + } + loader.parentNode.removeChild(loader); + document.getElementById("entire-game-container").style.visibility = "visible"; + }, + + load: function() { + //Load script editor + var editor = ace.edit('javascript-editor'); + editor.getSession().setMode('ace/mode/javascript'); + editor.setTheme('ace/theme/monokai'); + document.getElementById('javascript-editor').style.fontSize='16px'; + editor.setOption("showPrintMargin", false); + + //Initialize main menu accordion panels to all start as "open" + var terminal = document.getElementById("terminal-tab"); + var createScript = document.getElementById("create-script-tab"); + var activeScripts = document.getElementById("active-scripts-tab"); + var createProgram = document.getElementById("create-program-tab"); + var stats = document.getElementById("stats-tab"); + var factions = document.getElementById("factions-tab"); + var augmentations = document.getElementById("augmentations-tab"); + var hacknetnodes = document.getElementById("hacknet-nodes-tab"); + var city = document.getElementById("city-tab"); + var travel = document.getElementById("travel-tab"); + var job = document.getElementById("job-tab"); + var tutorial = document.getElementById("tutorial-tab"); + var options = document.getElementById("options-tab"); + + //Load game from save or create new game + if (Object(__WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["a" /* loadGame */])(__WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */])) { + console.log("Loaded game from save"); + Object(__WEBPACK_IMPORTED_MODULE_8__BitNode_js__["d" /* initBitNodes */])(); + Object(__WEBPACK_IMPORTED_MODULE_8__BitNode_js__["c" /* initBitNodeMultipliers */])(); + Object(__WEBPACK_IMPORTED_MODULE_28__SourceFile_js__["d" /* initSourceFiles */])(); + Engine.setDisplayElements(); //Sets variables for important DOM elements + Engine.init(); //Initialize buttons, work, etc. + __WEBPACK_IMPORTED_MODULE_9__Company_js__["d" /* CompanyPositions */].init(); + Object(__WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["g" /* initAugmentations */])(); //Also calls Player.reapplyAllAugmentations() + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].reapplyAllSourceFiles(); + Object(__WEBPACK_IMPORTED_MODULE_30__StockMarket_js__["e" /* initStockSymbols */])(); + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].hasWseAccount) { + Object(__WEBPACK_IMPORTED_MODULE_30__StockMarket_js__["f" /* initSymbolToStockMap */])(); + } + Object(__WEBPACK_IMPORTED_MODULE_17__Literature_js__["a" /* initLiterature */])(); + Object(__WEBPACK_IMPORTED_MODULE_19__NetscriptFunctions_js__["c" /* initSingularitySFFlags */])(); + + //Calculate the number of cycles have elapsed while offline + Engine._lastUpdate = new Date().getTime(); + var lastUpdate = __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].lastUpdate; + var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed); + + /* Process offline progress */ + var offlineProductionFromScripts = Object(__WEBPACK_IMPORTED_MODULE_25__Script_js__["e" /* loadAllRunningScripts */])(); //This also takes care of offline production for those scripts + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].isWorking) { + console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds"); + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeFaction) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workForFaction(numCyclesOffline); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCreateProgram) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].createProgramWork(numCyclesOffline); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeStudyClass) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].takeClass(numCyclesOffline); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCrime) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].commitCrime(numCyclesOffline); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCompanyPartTime) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workPartTime(numCyclesOffline); + } else { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].work(numCyclesOffline); + } + } + + //Hacknet Nodes offline progress + var offlineProductionFromHacknetNodes = Object(__WEBPACK_IMPORTED_MODULE_15__HacknetNode_js__["c" /* processAllHacknetNodeEarnings */])(numCyclesOffline); + + //Passive faction rep gain offline + Object(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["j" /* processPassiveFactionRepGain */])(numCyclesOffline); + + //Gang progress for BitNode 2 + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].bitNodeN != null && __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].bitNodeN == 2 && __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].inGang()) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].gang.process(numCyclesOffline); + } + + //Update total playtime + var time = numCyclesOffline * Engine._idleSpeed; + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime == null) {__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime = 0;} + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug == null) {__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug = 0;} + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].totalPlaytime += time; + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].playtimeSinceLastAug += time; + + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].lastUpdate = Engine._lastUpdate; + Engine.start(); //Run main game loop and Scripts loop + Engine.removeLoadingScreen(); + Object(__WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__["a" /* dialogBoxCreate */])("While you were offline, your scripts generated $" + + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(offlineProductionFromScripts, 2) + " and your Hacknet Nodes generated $" + + Object(__WEBPACK_IMPORTED_MODULE_4__utils_StringHelperFunctions_js__["c" /* formatNumber */])(offlineProductionFromHacknetNodes, 2)); + //Close main menu accordions for loaded game + terminal.style.maxHeight = null; + terminal.style.opacity = 0; + terminal.style.pointerEvents = "none"; + createScript.style.maxHeight = null; + createScript.style.opacity = 0; + createScript.style.pointerEvents = "none"; + activeScripts.style.maxHeight = null; + activeScripts.style.opacity = 0; + activeScripts.style.pointerEvents = "none"; + createProgram.style.maxHeight = null; + createProgram.style.opacity = 0; + createProgram.style.pointerEvents = "none"; + stats.style.maxHeight = null; + stats.style.opacity = 0; + stats.style.pointerEvents = "none"; + factions.style.maxHeight = null; + factions.style.opacity = 0; + factions.style.pointerEvents = "none"; + augmentations.style.maxHeight = null; + augmentations.style.opacity = 0; + augmentations.style.pointerEvents = "none"; + hacknetnodes.style.maxHeight = null; + hacknetnodes.style.opacity = 0; + hacknetnodes.style.pointerEvents = "none"; + city.style.maxHeight = null; + city.style.opacity = 0; + city.style.pointerEvents = "none"; + travel.style.maxHeight = null; + travel.style.opacity = 0; + travel.style.pointerEvents = "none"; + job.style.maxHeight = null; + job.style.opacity = 0; + job.style.pointerEvents = "none"; + tutorial.style.maxHeight = null; + tutorial.style.opacity = 0; + tutorial.style.pointerEvents = "none"; + options.style.maxHeight = null; + options.style.opacity = 0; + options.style.pointerEvents = "none"; + } else { + //No save found, start new game + console.log("Initializing new game"); + Object(__WEBPACK_IMPORTED_MODULE_8__BitNode_js__["d" /* initBitNodes */])(); + Object(__WEBPACK_IMPORTED_MODULE_8__BitNode_js__["c" /* initBitNodeMultipliers */])(); + Object(__WEBPACK_IMPORTED_MODULE_28__SourceFile_js__["d" /* initSourceFiles */])(); + Object(__WEBPACK_IMPORTED_MODULE_29__SpecialServerIps_js__["c" /* initSpecialServerIps */])(); + Engine.setDisplayElements(); //Sets variables for important DOM elements + Engine.start(); //Run main game loop and Scripts loop + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].init(); + Object(__WEBPACK_IMPORTED_MODULE_26__Server_js__["f" /* initForeignServers */])(); + Object(__WEBPACK_IMPORTED_MODULE_9__Company_js__["h" /* initCompanies */])(); + Object(__WEBPACK_IMPORTED_MODULE_12__Faction_js__["f" /* initFactions */])(); + __WEBPACK_IMPORTED_MODULE_9__Company_js__["d" /* CompanyPositions */].init(); + Object(__WEBPACK_IMPORTED_MODULE_7__Augmentations_js__["g" /* initAugmentations */])(); + Object(__WEBPACK_IMPORTED_MODULE_18__Message_js__["d" /* initMessages */])(); + Object(__WEBPACK_IMPORTED_MODULE_30__StockMarket_js__["e" /* initStockSymbols */])(); + Object(__WEBPACK_IMPORTED_MODULE_17__Literature_js__["a" /* initLiterature */])(); + Object(__WEBPACK_IMPORTED_MODULE_19__NetscriptFunctions_js__["c" /* initSingularitySFFlags */])(); + + //Open main menu accordions for new game + //Main menu accordions + var hackingHdr = document.getElementById("hacking-menu-header"); + hackingHdr.classList.toggle("opened"); + var characterHdr = document.getElementById("character-menu-header"); + characterHdr.classList.toggle("opened"); + var worldHdr = document.getElementById("world-menu-header"); + worldHdr.classList.toggle("opened"); + var helpHdr = document.getElementById("help-menu-header"); + helpHdr.classList.toggle("opened"); + terminal.style.maxHeight = terminal.scrollHeight + "px"; + terminal.style.display = "block"; + createScript.style.maxHeight = createScript.scrollHeight + "px"; + createScript.style.display = "block"; + activeScripts.style.maxHeight = activeScripts.scrollHeight + "px"; + activeScripts.style.display = "block"; + createProgram.style.maxHeight = createProgram.scrollHeight + "px"; + createProgram.style.display = "block"; + stats.style.maxHeight = stats.scrollHeight + "px"; + stats.style.display = "block"; + factions.style.maxHeight = factions.scrollHeight + "px"; + factions.style.display = "block"; + augmentations.style.maxHeight = augmentations.scrollHeight + "px"; + augmentations.style.display = "block"; + hacknetnodes.style.maxHeight = hacknetnodes.scrollHeight + "px"; + hacknetnodes.style.display = "block"; + city.style.maxHeight = city.scrollHeight + "px"; + city.style.display = "block"; + travel.style.maxHeight = travel.scrollHeight + "px"; + travel.style.display = "block"; + job.style.maxHeight = job.scrollHeight + "px"; + job.style.display = "block"; + tutorial.style.maxHeight = tutorial.scrollHeight + "px"; + tutorial.style.display = "block"; + options.style.maxHeight = options.scrollHeight + "px"; + options.style.display = "block"; + + //Start interactive tutorial + Object(__WEBPACK_IMPORTED_MODULE_16__InteractiveTutorial_js__["d" /* iTutorialStart */])(); + Engine.removeLoadingScreen(); + } + //Initialize labels on game settings + Object(__WEBPACK_IMPORTED_MODULE_27__Settings_js__["d" /* setSettingsLabels */])(); + }, + + setDisplayElements: function() { + //Content elements + Engine.Display.terminalContent = document.getElementById("terminal-container"); + Engine.currentPage = Engine.Page.Terminal; + + Engine.Display.characterContent = document.getElementById("character-container"); + Engine.Display.characterContent.style.visibility = "hidden"; + + Engine.Display.scriptEditorContent = document.getElementById("script-editor-container"); + Engine.Display.scriptEditorContent.style.visibility = "hidden"; + + Engine.Display.activeScriptsContent = document.getElementById("active-scripts-container"); + Engine.Display.activeScriptsContent.style.visibility = "hidden"; + + Engine.Display.hacknetNodesContent = document.getElementById("hacknet-nodes-container"); + Engine.Display.hacknetNodesContent.style.visibility = "hidden"; + + Engine.Display.worldContent = document.getElementById("world-container"); + Engine.Display.worldContent.style.visibility = "hidden"; + + Engine.Display.createProgramContent = document.getElementById("create-program-container"); + Engine.Display.createProgramContent.style.visibility = "hidden"; + + Engine.Display.factionsContent = document.getElementById("factions-container"); + Engine.Display.factionsContent.style.visibility = "hidden"; + + + Engine.Display.factionContent = document.getElementById("faction-container"); + Engine.Display.factionContent.style.visibility = "hidden"; + + Engine.Display.factionAugmentationsContent = document.getElementById("faction-augmentations-container"); + Engine.Display.factionAugmentationsContent.style.visibility = "hidden"; + + Engine.Display.augmentationsContent = document.getElementById("augmentations-container"); + Engine.Display.augmentationsContent.style.visibility = "hidden"; + + Engine.Display.tutorialContent = document.getElementById("tutorial-container"); + Engine.Display.tutorialContent.style.visibility = "hidden"; + + Engine.Display.infiltrationContent = document.getElementById("infiltration-container"); + Engine.Display.infiltrationContent.style.visibility = "hidden"; + + Engine.Display.stockMarketContent = document.getElementById("stock-market-container"); + Engine.Display.stockMarketContent.style.visibility = "hidden"; + + + //Character info + Engine.Display.characterInfo = document.getElementById("character-info"); + + //Location lists + Engine.aevumLocationsList = document.getElementById("aevum-locations-list"); + Engine.chongqingLocationsList = document.getElementById("chongqing-locations-list"); + Engine.sector12LocationsList = document.getElementById("sector12-locations-list"); + Engine.newTokyoLocationsList = document.getElementById("newtokyo-locations-list"); + Engine.ishimaLocationsList = document.getElementById("ishima-locations-list"); + Engine.volhavenLocationsList = document.getElementById("volhaven-locations-list"); + + //Location page (page that shows up when you visit a specific location in World) + Engine.Display.locationContent = document.getElementById("location-container"); + Engine.Display.locationContent.style.visibility = "hidden"; + + //Work In Progress + Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container"); + Engine.Display.workInProgressContent.style.visibility = "hidden"; + + //Red Pill / Hack World Daemon + Engine.Display.redPillContent = document.getElementById("red-pill-container"); + Engine.Display.redPillContent.style.visibility = "hidden"; + + //Init Location buttons + Object(__WEBPACK_IMPORTED_MODULE_13__Location_js__["c" /* initLocationButtons */])(); + + //Tutorial buttons + Engine.Clickables.tutorialNetworkingButton = document.getElementById("tutorial-networking-link"); + Engine.Clickables.tutorialNetworkingButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialNetworkingText); + }); + + Engine.Clickables.tutorialHackingButton = document.getElementById("tutorial-hacking-link"); + Engine.Clickables.tutorialHackingButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialHackingText); + }); + + Engine.Clickables.tutorialScriptsButton = document.getElementById("tutorial-scripts-link"); + Engine.Clickables.tutorialScriptsButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialScriptsText); + }); + + Engine.Clickables.tutorialNetscriptButton = document.getElementById("tutorial-netscript-link"); + Engine.Clickables.tutorialNetscriptButton.addEventListener("click", function() { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].bitNodeN === 4 || __WEBPACK_IMPORTED_MODULE_19__NetscriptFunctions_js__["b" /* hasSingularitySF */]) { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialNetscriptText + __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialSingularityFunctionsText); + } else { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialNetscriptText); + } + + }); + + Engine.Clickables.tutorialTravelingButton = document.getElementById("tutorial-traveling-link"); + Engine.Clickables.tutorialTravelingButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialTravelingText); + }); + + Engine.Clickables.tutorialCompaniesButton = document.getElementById("tutorial-jobs-link"); + Engine.Clickables.tutorialCompaniesButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialCompaniesText); + }); + + Engine.Clickables.tutorialFactionsButton = document.getElementById("tutorial-factions-link"); + Engine.Clickables.tutorialFactionsButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialFactionsText); + }); + + Engine.Clickables.tutorialAugmentationsButton = document.getElementById("tutorial-augmentations-link"); + Engine.Clickables.tutorialAugmentationsButton.addEventListener("click", function() { + Engine.displayTutorialPage(__WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].TutorialAugmentationsText); + }); + + Engine.Clickables.tutorialBackButton = document.getElementById("tutorial-back-button"); + Engine.Clickables.tutorialBackButton.addEventListener("click", function() { + Engine.displayTutorialContent(); + }); + + //If DarkWeb already purchased, disable the button + if (__WEBPACK_IMPORTED_MODULE_29__SpecialServerIps_js__["a" /* SpecialServerIps */].hasOwnProperty("Darkweb Server")) { + document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button-inactive"); + } + }, + + /* Initialization */ + init: function() { + //Import game link + document.getElementById("import-game-link").onclick = function() { + __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */].importGame(); + }; + + //Main menu accordions + var hackingHdr = document.getElementById("hacking-menu-header"); + //hackingHdr.classList.toggle("opened"); + var characterHdr = document.getElementById("character-menu-header"); + //characterHdr.classList.toggle("opened"); + var worldHdr = document.getElementById("world-menu-header"); + //worldHdr.classList.toggle("opened"); + var helpHdr = document.getElementById("help-menu-header"); + //helpHdr.classList.toggle("opened"); + + hackingHdr.onclick = function() { + var terminal = document.getElementById("terminal-tab"); + var terminalLink = document.getElementById("terminal-menu-link"); + var createScript = document.getElementById("create-script-tab"); + var createScriptLink = document.getElementById("create-script-menu-link"); + var activeScripts = document.getElementById("active-scripts-tab"); + var activeScriptsLink = document.getElementById("active-scripts-menu-link"); + var createProgram = document.getElementById("create-program-tab"); + var createProgramLink = document.getElementById("create-program-menu-link"); + var createProgramNot = document.getElementById("create-program-notification"); + this.classList.toggle("opened"); + if (terminal.style.maxHeight) { + terminal.style.opacity = 0; + terminal.style.maxHeight = null; + terminalLink.style.opacity = 0; + terminalLink.style.maxHeight = null; + terminalLink.style.pointerEvents = "none"; + + createScript.style.opacity = 0; + createScript.style.maxHeight = null; + createScriptLink.style.opacity = 0; + createScriptLink.style.maxHeight = null; + createScriptLink.style.pointerEvents = "none"; + + activeScripts.style.opacity = 0; + activeScripts.style.maxHeight = null; + activeScriptsLink.style.opacity = 0; + activeScriptsLink.style.maxHeight = null; + activeScriptsLink.style.pointerEvents = "none"; + + createProgram.style.opacity = 0; + createProgram.style.maxHeight = null; + createProgramLink.style.opacity = 0; + createProgramLink.style.maxHeight = null; + createProgramLink.style.pointerEvents = "none"; + + createProgramNot.style.display = "none"; + } else { + terminal.style.maxHeight = terminal.scrollHeight + "px"; + terminal.style.opacity = 1; + terminalLink.style.maxHeight = terminalLink.scrollHeight + "px"; + terminalLink.style.opacity = 1; + terminalLink.style.pointerEvents = "auto"; + + createScript.style.maxHeight = createScript.scrollHeight + "px"; + createScript.style.opacity = 1; + createScriptLink.style.maxHeight = createScriptLink.scrollHeight + "px"; + createScriptLink.style.opacity = 1; + createScriptLink.style.pointerEvents = "auto"; + + activeScripts.style.maxHeight = activeScripts.scrollHeight + "px"; + activeScripts.style.opacity = 1; + activeScriptsLink.style.maxHeight = activeScriptsLink.scrollHeight + "px"; + activeScriptsLink.style.opacity = 1; + activeScriptsLink.style.pointerEvents = "auto"; + + createProgram.style.maxHeight = createProgram.scrollHeight + "px"; + createProgram.style.opacity = 1; + createProgramLink.style.maxHeight = createProgramLink.scrollHeight + "px"; + createProgramLink.style.opacity = 1; + createProgramLink.style.pointerEvents = "auto"; + createProgramNot.style.display = "block" + } + } + + characterHdr.onclick = function() { + var stats = document.getElementById("stats-tab"); + var statsLink = document.getElementById("stats-menu-link"); + var factions = document.getElementById("factions-tab"); + var factionsLink = document.getElementById("factions-menu-link"); + var augmentations = document.getElementById("augmentations-tab"); + var augmentationsLink = document.getElementById("augmentations-menu-link"); + var hacknetnodes = document.getElementById("hacknet-nodes-tab"); + var hacknetnodesLink = document.getElementById("hacknet-nodes-menu-link"); + this.classList.toggle("opened"); + if (stats.style.maxHeight) { + stats.style.opacity = 0; + stats.style.maxHeight = null; + statsLink.style.opacity = 0; + statsLink.style.maxHeight = null; + statsLink.style.pointerEvents = "none"; + + factions.style.opacity = 0; + factions.style.maxHeight = null; + factionsLink.style.opacity = 0; + factionsLink.style.maxHeight = null; + factionsLink.style.pointerEvents = "none"; + + augmentations.style.opacity = 0; + augmentations.style.maxHeight = null; + augmentationsLink.style.opacity = 0; + augmentationsLink.style.maxHeight = null; + augmentationsLink.style.pointerEvents = "none"; + + hacknetnodes.style.opacity = 0; + hacknetnodes.style.maxHeight = null; + hacknetnodesLink.style.opacity = 0; + hacknetnodesLink.style.maxHeight = null; + hacknetnodesLink.style.pointerEvents = "none"; + } else { + stats.style.maxHeight = stats.scrollHeight + "px"; + stats.style.opacity = 1; + statsLink.style.maxHeight = statsLink.scrollHeight + "px"; + statsLink.style.opacity = 1; + statsLink.style.pointerEvents = "auto"; + + factions.style.maxHeight = factions.scrollHeight + "px"; + factions.style.opacity = 1; + factionsLink.style.maxHeight = factionsLink.scrollHeight + "px"; + factionsLink.style.opacity = 1; + factionsLink.style.pointerEvents = "auto"; + + augmentations.style.maxHeight = augmentations.scrollHeight + "px"; + augmentations.style.opacity = 1; + augmentationsLink.style.maxHeight = augmentationsLink.scrollHeight + "px"; + augmentationsLink.style.opacity = 1; + augmentationsLink.style.pointerEvents = "auto"; + + hacknetnodes.style.maxHeight = hacknetnodes.scrollHeight + "px"; + hacknetnodes.style.opacity = 1; + hacknetnodesLink.style.maxHeight = hacknetnodesLink.scrollHeight + "px"; + hacknetnodesLink.style.opacity = 1; + hacknetnodesLink.style.pointerEvents = "auto"; + } + } + + worldHdr.onclick = function() { + var city = document.getElementById("city-tab"); + var cityLink = document.getElementById("city-menu-link"); + var travel = document.getElementById("travel-tab"); + var travelLink = document.getElementById("travel-menu-link"); + var job = document.getElementById("job-tab"); + var jobLink = document.getElementById("job-menu-link"); + this.classList.toggle("opened"); + if (city.style.maxHeight) { + city.style.opacity = 0; + city.style.maxHeight = null; + cityLink.style.opacity = 0; + cityLink.style.maxHeight = null; + cityLink.style.pointerEvents = "none"; + + travel.style.opacity = 0; + travel.style.maxHeight = null; + travelLink.style.opacity = 0; + travelLink.style.maxHeight = null; + travelLink.style.pointerEvents = "none"; + + job.style.opacity = 0; + job.style.maxHeight = null; + jobLink.style.opacity = 0; + jobLink.style.maxHeight = null; + jobLink.style.pointerEvents = "none"; + } else { + city.style.maxHeight = city.scrollHeight + "px"; + city.style.opacity = 1; + cityLink.style.maxHeight = cityLink.scrollHeight + "px"; + cityLink.style.opacity = 1; + cityLink.style.pointerEvents = "auto"; + + travel.style.maxHeight = travel.scrollHeight + "px"; + travel.style.opacity = 1; + travelLink.style.maxHeight = travelLink.scrollHeight + "px"; + travelLink.style.opacity = 1; + travelLink.style.pointerEvents = "auto"; + + job.style.maxHeight = job.scrollHeight + "px"; + job.style.opacity = 1; + jobLink.style.maxHeight = jobLink.scrollHeight + "px"; + jobLink.style.opacity = 1; + jobLink.style.pointerEvents = "auto"; + } + } + + helpHdr.onclick = function() { + var tutorial = document.getElementById("tutorial-tab"); + var tutorialLink = document.getElementById("tutorial-menu-link"); + var options = document.getElementById("options-tab"); + var optionsLink = document.getElementById("options-menu-link"); + this.classList.toggle("opened"); + if (tutorial.style.maxHeight) { + tutorial.style.opacity = 0; + tutorial.style.maxHeight = null; + tutorialLink.style.opacity = 0; + tutorialLink.style.maxHeight = null; + tutorialLink.style.pointerEvents = "none"; + + options.style.opacity = 0; + options.style.maxHeight = null; + optionsLink.style.opacity = 0; + optionsLink.style.maxHeight = null; + optionsLink.style.pointerEvents = "none"; + } else { + tutorial.style.maxHeight = tutorial.scrollHeight + "px"; + tutorial.style.opacity = 1; + tutorialLink.style.maxHeight = tutorialLink.scrollHeight + "px"; + tutorialLink.style.opacity = 1; + tutorialLink.style.pointerEvents = "auto"; + + options.style.maxHeight = options.scrollHeight + "px"; + options.style.opacity = 1; + optionsLink.style.maxHeight = optionsLink.scrollHeight + "px"; + optionsLink.style.opacity = 1; + optionsLink.style.pointerEvents = "auto"; + } + } + + //Main menu buttons and content + Engine.Clickables.terminalMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("terminal-menu-link"); + Engine.Clickables.terminalMainMenuButton.addEventListener("click", function() { + Engine.loadTerminalContent(); + return false; + }); + + Engine.Clickables.characterMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("stats-menu-link"); + Engine.Clickables.characterMainMenuButton.addEventListener("click", function() { + Engine.loadCharacterContent(); + return false; + }); + + Engine.Clickables.scriptEditorMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("create-script-menu-link"); + Engine.Clickables.scriptEditorMainMenuButton.addEventListener("click", function() { + Engine.loadScriptEditorContent(); + return false; + }); + + Engine.Clickables.activeScriptsMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("active-scripts-menu-link"); + Engine.Clickables.activeScriptsMainMenuButton.addEventListener("click", function() { + Engine.loadActiveScriptsContent(); + return false; + }); + + Engine.Clickables.hacknetNodesMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("hacknet-nodes-menu-link"); + Engine.Clickables.hacknetNodesMainMenuButton.addEventListener("click", function() { + Engine.loadHacknetNodesContent(); + return false; + }); + + Engine.Clickables.worldMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("city-menu-link"); + Engine.Clickables.worldMainMenuButton.addEventListener("click", function() { + Engine.loadWorldContent(); + return false; + }); + + Engine.Clickables.travelMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("travel-menu-link"); + Engine.Clickables.travelMainMenuButton.addEventListener("click", function() { + Engine.loadTravelContent(); + return false; + }); + + Engine.Clickables.jobMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("job-menu-link"); + Engine.Clickables.jobMainMenuButton.addEventListener("click", function() { + Engine.loadJobContent(); + return false; + }); + + + Engine.Clickables.createProgramMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("create-program-menu-link"); + Engine.Clickables.createProgramMainMenuButton.addEventListener("click", function() { + Engine.loadCreateProgramContent(); + return false; + }); + + Engine.Clickables.factionsMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("factions-menu-link"); + Engine.Clickables.factionsMainMenuButton.addEventListener("click", function() { + Engine.loadFactionsContent(); + return false; + }); + + Engine.Clickables.augmentationsMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("augmentations-menu-link"); + Engine.Clickables.augmentationsMainMenuButton.addEventListener("click", function() { + Engine.loadAugmentationsContent(); + return false; + }); + + Engine.Clickables.tutorialMainMenuButton = Object(__WEBPACK_IMPORTED_MODULE_2__utils_HelperFunctions_js__["b" /* clearEventListeners */])("tutorial-menu-link"); + Engine.Clickables.tutorialMainMenuButton.addEventListener("click", function() { + Engine.loadTutorialContent(); + return false; + }); + + //Active scripts list + Engine.ActiveScriptsList = document.getElementById("active-scripts-list"); + + //Save, Delete, Import/Export buttons + Engine.Clickables.saveMainMenuButton = document.getElementById("save-game-link"); + Engine.Clickables.saveMainMenuButton.addEventListener("click", function() { + __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */].saveGame(); + return false; + }); + + Engine.Clickables.deleteMainMenuButton = document.getElementById("delete-game-link"); + Engine.Clickables.deleteMainMenuButton.addEventListener("click", function() { + __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */].deleteGame(); + return false; + }); + + document.getElementById("export-game-link").addEventListener("click", function() { + __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */].exportGame(); + return false; + }); + + //Character Overview buttons + document.getElementById("character-overview-save-button").addEventListener("click", function() { + __WEBPACK_IMPORTED_MODULE_24__SaveObject_js__["b" /* saveObject */].saveGame(); + return false; + }); + + document.getElementById("character-overview-options-button").addEventListener("click", function() { + Object(__WEBPACK_IMPORTED_MODULE_1__utils_GameOptions_js__["b" /* gameOptionsBoxOpen */])(); + return false; + }); + + //Create Program buttons + Object(__WEBPACK_IMPORTED_MODULE_11__CreateProgram_js__["d" /* initCreateProgramButtons */])(); + + //Message at the top of terminal + Object(__WEBPACK_IMPORTED_MODULE_31__Terminal_js__["c" /* postNetburnerText */])(); + + //Player was working cancel button + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].isWorking) { + var cancelButton = document.getElementById("work-in-progress-cancel-button"); + cancelButton.addEventListener("click", function() { + if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeFaction) { + var fac = __WEBPACK_IMPORTED_MODULE_12__Faction_js__["b" /* Factions */][__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].currentWorkFactionName]; + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].finishFactionWork(true); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCreateProgram) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].finishCreateProgramWork(true); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeStudyClass) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].finishClass(); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCrime) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].finishCrime(true); + } else if (__WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].workType == __WEBPACK_IMPORTED_MODULE_10__Constants_js__["a" /* CONSTANTS */].WorkTypeCompanyPartTime) { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].finishWorkPartTime(); + } else { + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].finishWork(true); + } + }); + Engine.loadWorkInProgressContent(); + } + + //character overview screen + document.getElementById("character-overview-container").style.display = "block"; + + //Remove classes from links (they might be set from tutorial) + document.getElementById("terminal-menu-link").removeAttribute("class"); + document.getElementById("stats-menu-link").removeAttribute("class"); + document.getElementById("create-script-menu-link").removeAttribute("class"); + document.getElementById("active-scripts-menu-link").removeAttribute("class"); + document.getElementById("hacknet-nodes-menu-link").removeAttribute("class"); + document.getElementById("city-menu-link").removeAttribute("class"); + document.getElementById("tutorial-menu-link").removeAttribute("class"); + + //DEBUG Delete active Scripts on home + document.getElementById("debug-delete-scripts-link").addEventListener("click", function() { + console.log("Deleting running scripts on home computer"); + __WEBPACK_IMPORTED_MODULE_21__Player_js__["a" /* Player */].getHomeComputer().runningScripts = []; + Object(__WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Forcefully deleted all running scripts on home computer. Please save and refresh page"); + Object(__WEBPACK_IMPORTED_MODULE_1__utils_GameOptions_js__["a" /* gameOptionsBoxClose */])(); + return false; + }); + + //DEBUG Soft Reset + document.getElementById("debug-soft-reset").addEventListener("click", function() { + Object(__WEBPACK_IMPORTED_MODULE_0__utils_DialogBox_js__["a" /* dialogBoxCreate */])("Soft Reset!"); + Object(__WEBPACK_IMPORTED_MODULE_22__Prestige_js__["a" /* prestigeAugmentation */])(); + Object(__WEBPACK_IMPORTED_MODULE_1__utils_GameOptions_js__["a" /* gameOptionsBoxClose */])(); + return false; + }); + }, + + start: function() { + //Run main loop + Engine.idleTimer(); + + //Scripts + Object(__WEBPACK_IMPORTED_MODULE_20__NetscriptWorker_js__["f" /* runScriptsLoop */])(); + } +}; + +window.onload = function() { + Engine.load(); +}; + + + +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(8))) + +/***/ }), +/* 5 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* unused harmony export getIndicesOf */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return convertTimeMsToTimeElapsedString; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "f", function() { return longestCommonStart; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "e", function() { return isString; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return isPositiveNumber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return containsAllStrings; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return formatNumber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "h", function() { return numOccurrences; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "g", function() { return numNetscriptOperators; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__DialogBox_js__ = __webpack_require__(2); + + +//Netburner String helper functions + +//Searches for every occurence of searchStr within str and returns an array of the indices of +//all these occurences +function getIndicesOf(searchStr, str, caseSensitive) { + var searchStrLen = searchStr.length; + if (searchStrLen == 0) { + return []; + } + var startIndex = 0, index, indices = []; + if (!caseSensitive) { + str = str.toLowerCase(); + searchStr = searchStr.toLowerCase(); + } + while ((index = str.indexOf(searchStr, startIndex)) > -1) { + indices.push(index); + startIndex = index + searchStrLen; + } + return indices; +} + +//Replaces the character at an index with a new character +String.prototype.replaceAt=function(index, character) { + return this.substr(0, index) + character + this.substr(index+character.length); +} + +//Converts a date representing time in milliseconds to a string with the format +// H hours M minutes and S seconds +// e.g. 10000 -> "0 hours 0 minutes and 10 seconds" +// 120000 -> "0 0 hours 2 minutes and 0 seconds" +function convertTimeMsToTimeElapsedString(time) { + //Convert ms to seconds, since we only have second-level precision + time = Math.floor(time / 1000); + + var days = Math.floor(time / 86400); + time %= 86400; + + var hours = Math.floor(time / 3600); + time %= 3600; + + var minutes = Math.floor(time / 60); + time %= 60; + + var seconds = time; + + var res = ""; + if (days) {res += days + " days ";} + if (hours) {res += hours + " hours ";} + if (minutes) {res += minutes + " minutes ";} + res += seconds + " seconds "; + return res; +} + +//Finds the longest common starting substring in a set of strings +function longestCommonStart(strings) { + if (!containsAllStrings(strings)) {return;} + if (strings.length == 0) {return;} + + var A = strings.concat().sort(), + a1= A[0], a2= A[A.length-1], L= a1.length, i= 0; + while(i= 0) { + ++n; + pos += step; + } else break; + } + return n; +} + +//Counters the number of Netscript operators in a string +function numNetscriptOperators(string) { + var total = 0; + total += numOccurrences(string, "+"); + total += numOccurrences(string, "-"); + total += numOccurrences(string, "*"); + total += numOccurrences(string, "/"); + total += numOccurrences(string, "%"); + total += numOccurrences(string, "&&"); + total += numOccurrences(string, "||"); + total += numOccurrences(string, "<"); + total += numOccurrences(string, ">"); + total += numOccurrences(string, "<="); + total += numOccurrences(string, ">="); + total += numOccurrences(string, "=="); + total += numOccurrences(string, "!="); + if (isNaN(total)) { + Object(__WEBPACK_IMPORTED_MODULE_0__DialogBox_js__["a" /* dialogBoxCreate */])("ERROR in counting number of operators in script. This is a bug, please report to game developer"); + total = 0; + } + return total; +} + + + + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return Server; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return AllServers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "e", function() { return getServer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return GetServerByHostname; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "g", function() { return loadAllServers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return AddToAllServers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "j", function() { return processSingleServerGrowth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "f", function() { return initForeignServers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "h", function() { return prestigeAllServers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "i", function() { return prestigeHomeComputer; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__BitNode_js__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Constants_js__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__CreateProgram_js__ = __webpack_require__(14); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Player_js__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Script_js__ = __webpack_require__(18); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__ = __webpack_require__(11); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__ = __webpack_require__(21); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__utils_JSONReviver_js__ = __webpack_require__(7); + + + + + + + + + + +function Server(ip=Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), hostname="", organizationName="", + isConnectedTo=false, adminRights=false, purchasedByPlayer=false, maxRam=0) { + /* Properties */ + //Connection information + this.ip = ip; + var i = 0; + while (GetServerByHostname(hostname) != null) { + //Server already exists + hostname = hostname + "-" + i; + ++i; + } + this.hostname = hostname; + this.organizationName = organizationName; + this.isConnectedTo = isConnectedTo; //Whether the player is connected to this server + + //Access information + this.hasAdminRights = adminRights; //Whether player has admin rights + this.purchasedByPlayer = purchasedByPlayer; + this.manuallyHacked = false; //Flag that tracks whether or not the server has been hacked at least once + + //RAM, CPU speed and Scripts + this.maxRam = maxRam; //GB + this.ramUsed = 0; + this.cpuSpeed = 1; //MHz + + this.scripts = []; + this.runningScripts = []; //Stores RunningScript objects + this.programs = []; + this.messages = []; + + /* Hacking information (only valid for "foreign" aka non-purchased servers) */ + //Skill required to attempt a hack. Whether a hack is successful will be determined + //by a separate formula + this.requiredHackingSkill = 1; + + //Total money available on this server + this.moneyAvailable = 0; + this.moneyMax = 0; + + //Parameters used in formulas that dictate how moneyAvailable and requiredHackingSkill change. + this.hackDifficulty = 1; //Affects hack success rate and how the requiredHackingSkill increases over time (1-100) + this.baseDifficulty = 1; //Starting difficulty + this.minDifficulty = 1; + this.serverGrowth = 0; //Affects how the moneyAvailable increases (0-100) + this.timesHacked = 0; + + //The IP's of all servers reachable from this one (what shows up if you run scan/netstat) + // NOTE: Only contains IP and not the Server objects themselves + this.serversOnNetwork = []; + + //Port information, required for porthacking servers to get admin rights + this.numOpenPortsRequired = 5; + this.sshPortOpen = false; //Port 22 + this.ftpPortOpen = false; //Port 21 + this.smtpPortOpen = false; //Port 25 + this.httpPortOpen = false; //Port 80 + this.sqlPortOpen = false; //Port 1433 + this.openPortCount = 0; +}; + +//Set the hacking properties of a server +Server.prototype.setHackingParameters = function(requiredHackingSkill, moneyAvailable, hackDifficulty, serverGrowth) { + this.requiredHackingSkill = requiredHackingSkill; + if (isNaN(moneyAvailable)) { + this.moneyAvailable = 1000000; + } else { + this.moneyAvailable = moneyAvailable * __WEBPACK_IMPORTED_MODULE_0__BitNode_js__["a" /* BitNodeMultipliers */].ServerStartingMoney; + } + this.moneyMax = 25 * this.moneyAvailable * __WEBPACK_IMPORTED_MODULE_0__BitNode_js__["a" /* BitNodeMultipliers */].ServerMaxMoney; + this.hackDifficulty = hackDifficulty; + this.baseDifficulty = hackDifficulty; + this.minDifficulty = Math.max(1, Math.round(hackDifficulty / 3)); + this.serverGrowth = serverGrowth; +} + +//Set the port properties of a server +//Right now its only the number of open ports needed to PortHack the server. +Server.prototype.setPortProperties = function(numOpenPortsReq) { + this.numOpenPortsRequired = numOpenPortsReq; +} + +Server.prototype.setMaxRam = function(ram) { + this.maxRam = ram; +} + +//The serverOnNetwork array holds the IP of all the servers. This function +//returns the actual Server objects +Server.prototype.getServerOnNetwork = function(i) { + if (i > this.serversOnNetwork.length) { + console.log("Tried to get server on network that was out of range"); + return; + } + return AllServers[this.serversOnNetwork[i]]; +} + +//Given the name of the script, returns the corresponding +//script object on the server (if it exists) +Server.prototype.getScript = function(scriptName) { + for (var i = 0; i < this.scripts.length; i++) { + if (this.scripts[i].filename == scriptName) { + return this.scripts[i]; + } + } + return null; +} + +//Strengthens a server's security level (difficulty) by the specified amount +Server.prototype.fortify = function(amt) { + this.hackDifficulty += amt; + if (this.hackDifficulty > 99) {this.hackDifficulty = 99;} +} + +Server.prototype.weaken = function(amt) { + this.hackDifficulty -= (amt * __WEBPACK_IMPORTED_MODULE_0__BitNode_js__["a" /* BitNodeMultipliers */].ServerWeakenRate); + if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;} + if (this.hackDifficulty < 1) {this.hackDifficulty = 1;} +} + +//Functions for loading and saving a Server +Server.prototype.toJSON = function() { + return Object(__WEBPACK_IMPORTED_MODULE_8__utils_JSONReviver_js__["b" /* Generic_toJSON */])("Server", this); +} + +Server.fromJSON = function(value) { + return Object(__WEBPACK_IMPORTED_MODULE_8__utils_JSONReviver_js__["a" /* Generic_fromJSON */])(Server, value.data); +} + +__WEBPACK_IMPORTED_MODULE_8__utils_JSONReviver_js__["c" /* Reviver */].constructors.Server = Server; + +function initForeignServers() { + //MegaCorporations + var ECorpServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "ecorp", "ECorp", false, false, false, 0); + ECorpServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1150, 1300), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(30000000000, 70000000000), 99, 99); + ECorpServer.setPortProperties(5); + AddToAllServers(ECorpServer); + + var MegaCorpServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "megacorp", "MegaCorp", false, false, false, 0); + MegaCorpServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1150, 1300), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40000000000, 60000000000), 99, 99); + MegaCorpServer.setPortProperties(5); + AddToAllServers(MegaCorpServer); + + var BachmanAndAssociatesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "b-and-a", "Bachman & Associates", false, false, false, 0); + BachmanAndAssociatesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000, 1050), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(20000000000, 25000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(75, 85), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(65, 75)); + BachmanAndAssociatesServer.setPortProperties(5); + AddToAllServers(BachmanAndAssociatesServer); + + var BladeIndustriesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "blade", "Blade Industries", false, false, false, 0); + BladeIndustriesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000, 1100), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(12000000000, 20000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(90, 95), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 75)); + BladeIndustriesServer.setPortProperties(5); + BladeIndustriesServer.messages.push("beyond-man.lit"); + AddToAllServers(BladeIndustriesServer); + + var NWOServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "nwo", "New World Order", false, false, false, 0); + NWOServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000, 1200), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(25000000000, 35000000000), 99, Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(75, 85)); + NWOServer.setPortProperties(5); + NWOServer.messages.push("the-hidden-world.lit"); + AddToAllServers(NWOServer); + + var ClarkeIncorporatedServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "clarkeinc", "Clarke Incorporated", false, false, false, 0); + ClarkeIncorporatedServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000, 1200), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(15000000000, 25000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 60), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 70)); + ClarkeIncorporatedServer.setPortProperties(5); + ClarkeIncorporatedServer.messages.push("beyond-man.lit"); + ClarkeIncorporatedServer.messages.push("cost-of-immortality.lit"); + AddToAllServers(ClarkeIncorporatedServer); + + var OmniTekIncorporatedServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "omnitek", "OmniTek Incorporated", false, false, false, 0); + OmniTekIncorporatedServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(900, 1100), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(15000000000, 20000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(90, 99), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(95, 99)); + OmniTekIncorporatedServer.setPortProperties(5); + OmniTekIncorporatedServer.messages.push("coded-intelligence.lit"); + AddToAllServers(OmniTekIncorporatedServer); + + var FourSigmaServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "4sigma", "FourSigma", false, false, false, 0); + FourSigmaServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(950, 1200), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(15000000000, 25000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 70), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(75, 99)); + FourSigmaServer.setPortProperties(5); + AddToAllServers(FourSigmaServer); + + var KuaiGongInternationalServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "kuai-gong", "KuaiGong International", false, false, false, 0); + KuaiGongInternationalServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000, 1250), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(20000000000, 30000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(95, 99), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(90, 99)); + KuaiGongInternationalServer.setPortProperties(5); + AddToAllServers(KuaiGongInternationalServer); + + //Technology and communications companies (large targets) + var FulcrumTechnologiesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "fulcrumtech", "Fulcrum Technologies", false, false, false, 64); + FulcrumTechnologiesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000, 1200), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1400000000, 1800000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(85, 95), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 99)); + FulcrumTechnologiesServer.setPortProperties(5); + FulcrumTechnologiesServer.messages.push("simulated-reality.lit"); + AddToAllServers(FulcrumTechnologiesServer); + + var FulcrumSecretTechnologiesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "fulcrumassets", "Fulcrum Technologies Assets", false, false, false, 0); + FulcrumSecretTechnologiesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1200, 1500), 1000000, 99, 1); + FulcrumSecretTechnologiesServer.setPortProperties(5); + AddToAllServers(FulcrumSecretTechnologiesServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].FulcrumSecretTechnologies, FulcrumSecretTechnologiesServer.ip); + + var StormTechnologiesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "stormtech", "Storm Technologies", false, false, false, 0); + StormTechnologiesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(900, 1050), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000000000, 1200000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 90), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 90)); + StormTechnologiesServer.setPortProperties(5); + AddToAllServers(StormTechnologiesServer); + + var DefCommServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "defcomm", "DefComm", false, false, false, 0); + DefCommServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(900, 1000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800000000, 950000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(85, 95), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 70)); + DefCommServer.setPortProperties(5); + AddToAllServers(DefCommServer); + + var InfoCommServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "infocomm", "InfoComm", false, false, false, 0); + InfoCommServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(875, 950), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(600000000, 900000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 90), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(35, 75)); + InfoCommServer.setPortProperties(5); + AddToAllServers(InfoCommServer); + + var HeliosLabsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "helios", "Helios Labs", false, false, false, 0); + HeliosLabsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800, 900), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(550000000, 750000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(85, 95), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80)); + HeliosLabsServer.setPortProperties(5); + HeliosLabsServer.messages.push("beyond-man.lit"); + AddToAllServers(HeliosLabsServer); + + var VitaLifeServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "vitalife", "VitaLife", false, false, false, 32); + VitaLifeServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(775, 900), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(700000000, 800000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 90), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80)); + VitaLifeServer.setPortProperties(5); + VitaLifeServer.messages.push("A-Green-Tomorrow.lit"); + AddToAllServers(VitaLifeServer); + + var IcarusMicrosystemsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "icarus", "Icarus Microsystems", false, false, false, 0); + IcarusMicrosystemsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(850, 925), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(900000000, 1000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(85, 95), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(85, 95)); + IcarusMicrosystemsServer.setPortProperties(5); + AddToAllServers(IcarusMicrosystemsServer); + + var UniversalEnergyServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "univ-energy", "Universal Energy", false, false, false, 32); + UniversalEnergyServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800, 900), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1100000000, 1200000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 90), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 90)); + UniversalEnergyServer.setPortProperties(4); + AddToAllServers(UniversalEnergyServer); + + var TitanLabsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "titan-labs", "Titan Laboratories", false, false, false, 32); + TitanLabsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800, 875), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(750000000, 900000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80)); + TitanLabsServer.setPortProperties(5); + TitanLabsServer.messages.push("coded-intelligence.lit"); + AddToAllServers(TitanLabsServer); + + var MicrodyneTechnologiesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "microdyne", "Microdyne Technologies", false, false, false, 16); + MicrodyneTechnologiesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800, 875), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(500000000, 700000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(65, 75), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 90)); + MicrodyneTechnologiesServer.setPortProperties(5); + MicrodyneTechnologiesServer.messages.push("synthetic-muscles.lit"); + AddToAllServers(MicrodyneTechnologiesServer); + + var TaiYangDigitalServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "taiyang-digital", "Taiyang Digital", false, false, false, 0); + TaiYangDigitalServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(850, 950), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800000000, 900000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80)); + TaiYangDigitalServer.setPortProperties(5); + TaiYangDigitalServer.messages.push("A-Green-Tomorrow.lit"); + TaiYangDigitalServer.messages.push("brighter-than-the-sun.lit"); + AddToAllServers(TaiYangDigitalServer); + + var GalacticCyberSystemsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "galactic-cyber", "Galactic Cybersystems", false, false, false, 0); + GalacticCyberSystemsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(825, 875), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(750000000, 850000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(55, 65), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 90)); + GalacticCyberSystemsServer.setPortProperties(5); + AddToAllServers(GalacticCyberSystemsServer); + + //Defense Companies ("Large" Companies) + var AeroCorpServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "aerocorp", "AeroCorp", false, false, false, 0); + AeroCorpServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(850, 925), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000000000, 1200000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 90), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(55, 65)); + AeroCorpServer.setPortProperties(5); + AeroCorpServer.messages.push("man-and-machine.lit"); + AddToAllServers(AeroCorpServer); + + var OmniaCybersystemsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "omnia", "Omnia Cybersystems", false, false, false, 0); + OmniaCybersystemsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(850, 950), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(900000000, 1000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(85, 95), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 70)); + OmniaCybersystemsServer.setPortProperties(5); + AddToAllServers(OmniaCybersystemsServer); + + var ZBDefenseServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "zb-def", "ZB Defense Industries", false, false, false, 0); + ZBDefenseServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(775, 825), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(900000000, 1100000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(55, 65), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(65, 75)); + ZBDefenseServer.setPortProperties(4); + ZBDefenseServer.messages.push("synthetic-muscles.lit"); + AddToAllServers(ZBDefenseServer); + + var AppliedEnergeticsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "applied-energetics", "Applied Energetics", false, false, false, 0); + AppliedEnergeticsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(775, 850), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(700000000, 1000000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 75)); + AppliedEnergeticsServer.setPortProperties(4); + AddToAllServers(AppliedEnergeticsServer); + + var SolarisSpaceSystemsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "solaris", "Solaris Space Systems", false, false, false, 0); + SolarisSpaceSystemsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(750, 850), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(700000000, 900000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80)); + SolarisSpaceSystemsServer.setPortProperties(5); + SolarisSpaceSystemsServer.messages.push("A-Green-Tomorrow.lit"); + SolarisSpaceSystemsServer.messages.push("the-failed-frontier.lit"); + AddToAllServers(SolarisSpaceSystemsServer); + + var DeltaOneServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "deltaone", "Delta One", false, false, false, 0); + DeltaOneServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800, 900), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1300000000, 1700000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(75, 85), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 70)); + DeltaOneServer.setPortProperties(5); + AddToAllServers(DeltaOneServer); + + //Health, medicine, pharmaceutical companies ("Large" targets) + var GlobalPharmaceuticalsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "global-pharm", "Global Pharmaceuticals", false, false, false, 16); + GlobalPharmaceuticalsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(750, 850), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1500000000, 1750000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(75, 85), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(80, 90)); + GlobalPharmaceuticalsServer.setPortProperties(4); + GlobalPharmaceuticalsServer.messages.push("A-Green-Tomorrow.lit"); + AddToAllServers(GlobalPharmaceuticalsServer); + + var NovaMedicalServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "nova-med", "Nova Medical", false, false, false, 0); + NovaMedicalServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(775, 850), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1100000000, 1250000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(65, 85)); + NovaMedicalServer.setPortProperties(4); + AddToAllServers(NovaMedicalServer); + + var ZeusMedicalServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "zeus-med", "Zeus Medical", false, false, false, 0); + ZeusMedicalServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800, 850), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1300000000, 1500000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 90), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80)); + ZeusMedicalServer.setPortProperties(5); + AddToAllServers(ZeusMedicalServer); + + var UnitaLifeGroupServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "unitalife", "UnitaLife Group", false, false, false, 32); + UnitaLifeGroupServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(775, 825), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(1000000000, 1100000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80)); + UnitaLifeGroupServer.setPortProperties(4); + AddToAllServers(UnitaLifeGroupServer); + + //"Medium level" targets + var LexoCorpServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "lexo-corp", "Lexo Corporation", false, false, false, 16); + LexoCorpServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(650, 750), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(700000000, 800000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(55, 65)); + LexoCorpServer.setPortProperties(4); + AddToAllServers(LexoCorpServer); + + var RhoConstructionServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "rho-construction", "Rho Construction", false, false, false, 0); + RhoConstructionServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(475, 525), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(500000000, 700000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40, 60), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40, 60)); + RhoConstructionServer.setPortProperties(3); + AddToAllServers(RhoConstructionServer); + + var AlphaEnterprisesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "alpha-ent", "Alpha Enterprises", false, false, false, 0); + AlphaEnterprisesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(500, 600), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(600000000, 750000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 70), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 60)); + AlphaEnterprisesServer.setPortProperties(4); + AlphaEnterprisesServer.messages.push("sector-12-crime.lit"); + AddToAllServers(AlphaEnterprisesServer); + + var AevumPoliceServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "aevum-police", "Aevum Police Network", false, false, false, 0); + AevumPoliceServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(400, 450), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(200000000, 400000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(30, 50)); + AevumPoliceServer.setPortProperties(4); + AddToAllServers(AevumPoliceServer); + + var RothmanUniversityServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "rothman-uni", "Rothman University Network", false, false, false, 4); + RothmanUniversityServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(370, 430), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(175000000, 250000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(45, 55), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(35, 45)); + RothmanUniversityServer.setPortProperties(3); + RothmanUniversityServer.messages.push("secret-societies.lit"); + RothmanUniversityServer.messages.push("the-failed-frontier.lit"); + RothmanUniversityServer.messages.push("tensions-in-tech-race.lit"); + AddToAllServers(RothmanUniversityServer); + + var ZBInstituteOfTechnologyServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "zb-institute", "ZB Institute of Technology Network", false, false, false, 4); + ZBInstituteOfTechnologyServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(725, 775), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(800000000, 1100000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(65, 85), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(75, 85)); + ZBInstituteOfTechnologyServer.setPortProperties(5); + AddToAllServers(ZBInstituteOfTechnologyServer); + + var SummitUniversityServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "summit-uni", "Summit University Network", false, false, false, 4); + SummitUniversityServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(425, 475), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(200000000, 350000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(45, 65), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40, 60)); + SummitUniversityServer.setPortProperties(3); + SummitUniversityServer.messages.push("secret-societies.lit"); + SummitUniversityServer.messages.push("the-failed-frontier.lit"); + SummitUniversityServer.messages.push("synthetic-muscles.lit"); + AddToAllServers(SummitUniversityServer); + + var SysCoreSecuritiesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "syscore", "SysCore Securities", false, false, false, 0); + SysCoreSecuritiesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(550, 650), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(400000000, 600000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 70)); + SysCoreSecuritiesServer.setPortProperties(4); + AddToAllServers(SysCoreSecuritiesServer); + + var CatalystVenturesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "catalyst", "Catalyst Ventures", false, false, false, 0); + CatalystVenturesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(400, 450), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(300000000, 550000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 70), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(25, 55)); + CatalystVenturesServer.setPortProperties(3); + CatalystVenturesServer.messages.push("tensions-in-tech-race.lit"); + AddToAllServers(CatalystVenturesServer); + + var TheHubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "the-hub", "The Hub", false, false, false, 0); + TheHubServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(275, 325), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(150000000, 200000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(35, 45), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(45, 55)); + TheHubServer.setPortProperties(2); + AddToAllServers(TheHubServer); + + var CompuTekServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "comptek", "CompuTek", false, false, false, 8); + CompuTekServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(300, 400), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(220000000, 250000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(55, 65), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(45, 65)); + CompuTekServer.setPortProperties(3); + CompuTekServer.messages.push("man-and-machine.lit"); + AddToAllServers(CompuTekServer); + + var NetLinkTechnologiesServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "netlink", "NetLink Technologies", false, false, false, 0); + NetLinkTechnologiesServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(375, 425), 275000000, Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60, 80), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(45, 75)); + NetLinkTechnologiesServer.setPortProperties(3); + NetLinkTechnologiesServer.messages.push("simulated-reality.lit"); + AddToAllServers(NetLinkTechnologiesServer); + + var JohnsonOrthopedicsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "johnson-ortho", "Johnson Orthopedics", false, false, false, 4); + JohnsonOrthopedicsServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(250, 300), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(70000000, 85000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(35, 65), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(35, 65)); + JohnsonOrthopedicsServer.setPortProperties(2); + AddToAllServers(JohnsonOrthopedicsServer); + + //"Low level" targets + var FoodNStuffServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 8); + FoodNStuffServer.setHackingParameters(1, 2000000, 10, 5); + FoodNStuffServer.setPortProperties(0); + FoodNStuffServer.messages.push("sector-12-crime.lit"); + AddToAllServers(FoodNStuffServer); + + var SigmaCosmeticsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 8); + SigmaCosmeticsServer.setHackingParameters(5, 2300000, 10, 10); + SigmaCosmeticsServer.setPortProperties(0); + AddToAllServers(SigmaCosmeticsServer); + + var JoesGunsServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "joesguns", "Joe's Guns", false, false, false, 8); + JoesGunsServer.setHackingParameters(10, 2500000, 15, 20); + JoesGunsServer.setPortProperties(0); + AddToAllServers(JoesGunsServer); + + var Zer0NightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "zer0", "ZER0 Nightclub", false, false, false, 4); + Zer0NightclubServer.setHackingParameters(75, 7500000, 25, 40); + Zer0NightclubServer.setPortProperties(1); + AddToAllServers(Zer0NightclubServer); + + var NectarNightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "nectar-net", "Nectar Nightclub Network", false, false, false, 8); + NectarNightclubServer.setHackingParameters(20, 2750000, 20, 25); + NectarNightclubServer.setPortProperties(0); + AddToAllServers(NectarNightclubServer); + + var NeoNightclubServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "neo-net", "Neo Nightclub Network", false, false, false, 4); + NeoNightclubServer.setHackingParameters(50, 5000000, 25, 25); + NeoNightclubServer.setPortProperties(1); + NeoNightclubServer.messages.push("the-hidden-world.lit"); + AddToAllServers(NeoNightclubServer); + + var SilverHelixServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "silver-helix", "Silver Helix", false, false, false, 2); + SilverHelixServer.setHackingParameters(150, 45000000, 30, 30); + SilverHelixServer.setPortProperties(2); + SilverHelixServer.messages.push("new-triads.lit"); + AddToAllServers(SilverHelixServer); + + var HongFangTeaHouseServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 8); + HongFangTeaHouseServer.setHackingParameters(30, 3000000, 15, 20); + HongFangTeaHouseServer.setPortProperties(0); + HongFangTeaHouseServer.messages.push("brighter-than-the-sun.lit"); + AddToAllServers(HongFangTeaHouseServer); + + var HaraKiriSushiBarServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 8); + HaraKiriSushiBarServer.setHackingParameters(40, 4000000, 15, 40); + HaraKiriSushiBarServer.setPortProperties(0); + AddToAllServers(HaraKiriSushiBarServer); + + var PhantasyServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "phantasy", "Phantasy Club", false, false, false, 0); + PhantasyServer.setHackingParameters(100, 24000000, 20, 35); + PhantasyServer.setPortProperties(2); + AddToAllServers(PhantasyServer); + + var MaxHardwareServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "max-hardware", "Max Hardware Store", false, false, false, 4); + MaxHardwareServer.setHackingParameters(80, 10000000, 15, 30); + MaxHardwareServer.setPortProperties(1); + AddToAllServers(MaxHardwareServer); + + var OmegaSoftwareServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "omega-net", "Omega Software", false, false, false, 8); + OmegaSoftwareServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(180, 220), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(60000000, 70000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(25, 35), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(30, 40)); + OmegaSoftwareServer.setPortProperties(2); + OmegaSoftwareServer.messages.push("the-new-god.lit"); + AddToAllServers(OmegaSoftwareServer); + + //Gyms + var CrushFitnessGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "crush-fitness", "Crush Fitness", false, false, false, 0); + CrushFitnessGymServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(225, 275), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40000000, 60000000), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(35, 45), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(27, 33)); + CrushFitnessGymServer.setPortProperties(2); + AddToAllServers(CrushFitnessGymServer); + + var IronGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "iron-gym", "Iron Gym Network", false, false, false, 4); + IronGymServer.setHackingParameters(100, 20000000, 30, 20); + IronGymServer.setPortProperties(1); + AddToAllServers(IronGymServer); + + var MilleniumFitnessGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "millenium-fitness", "Millenium Fitness Network", false, false, false, 0); + MilleniumFitnessGymServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(475, 525), 250000000, Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(45, 55), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(25, 45)); + MilleniumFitnessGymServer.setPortProperties(3); + AddToAllServers(MilleniumFitnessGymServer); + + var PowerhouseGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "powerhouse-fitness", "Powerhouse Fitness", false, false, false, 0); + PowerhouseGymServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(950, 1100), 900000000, Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(55, 65), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(50, 60)); + PowerhouseGymServer.setPortProperties(5); + AddToAllServers(PowerhouseGymServer); + + var SnapFitnessGymServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "snap-fitness", "Snap Fitness", false, false, false, 0); + SnapFitnessGymServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(675, 800), 450000000, Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40, 60), Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(40, 60)); + SnapFitnessGymServer.setPortProperties(4); + AddToAllServers(SnapFitnessGymServer); + + //Faction servers, cannot hack money from these + var BitRunnersServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "run4theh111z", "The Runners", false, false, false, 0); + BitRunnersServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(505, 550), 0, 0, 0); + BitRunnersServer.setPortProperties(4); + BitRunnersServer.messages.push("simulated-reality.lit"); + BitRunnersServer.messages.push("the-new-god.lit"); + AddToAllServers(BitRunnersServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].BitRunnersServer, BitRunnersServer.ip); + + var TheBlackHandServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "I.I.I.I", "I.I.I.I", false, false, false, 0); + TheBlackHandServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(340, 365), 0, 0, 0); + TheBlackHandServer.setPortProperties(3); + TheBlackHandServer.messages.push("democracy-is-dead.lit"); + AddToAllServers(TheBlackHandServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].TheBlackHandServer, TheBlackHandServer.ip); + + var NiteSecServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "avmnite-02h", "NiteSec", false, false, false, 0); + NiteSecServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(202, 220), 0, 0, 0); + NiteSecServer.setPortProperties(2); + NiteSecServer.messages.push("democracy-is-dead.lit"); + AddToAllServers(NiteSecServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].NiteSecServer, NiteSecServer.ip); + + var DarkArmyServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), ".", ".", false, false, false, 0); + DarkArmyServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(505, 550), 0, 0, 0); + DarkArmyServer.setPortProperties(4); + AddToAllServers(DarkArmyServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].TheDarkArmyServer, DarkArmyServer.ip); + + var CyberSecServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "CSEC", "CyberSec", false, false, false, 0); + CyberSecServer.setHackingParameters(Object(__WEBPACK_IMPORTED_MODULE_6__utils_HelperFunctions_js__["d" /* getRandomInt */])(51, 60), 0, 0, 0); + CyberSecServer.setPortProperties(1); + CyberSecServer.messages.push("democracy-is-dead.lit"); + AddToAllServers(CyberSecServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].CyberSecServer, CyberSecServer.ip); + + var DaedalusServer = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), "The-Cave", "Helios", false, false, false, 0); + DaedalusServer.setHackingParameters(925, 0, 0, 0); + DaedalusServer.setPortProperties(5); + DaedalusServer.messages.push("alpha-omega.lit"); + AddToAllServers(DaedalusServer); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].DaedalusServer, DaedalusServer.ip); + + //Super special Servers + var WorldDaemon = new Server(Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["a" /* createRandomIp */])(), __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].WorldDaemon, __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].WorldDaemon, false, false, false, 0); + WorldDaemon.setHackingParameters(3000, 0, 0, 0); + WorldDaemon.setPortProperties(5); + AddToAllServers(WorldDaemon); + __WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["a" /* SpecialServerIps */].addIp(__WEBPACK_IMPORTED_MODULE_5__SpecialServerIps_js__["b" /* SpecialServerNames */].WorldDaemon, WorldDaemon.ip); + + /* Create a randomized network for all the foreign servers */ + //Groupings for creating a randomized network + var NetworkGroup1 = [IronGymServer, FoodNStuffServer, SigmaCosmeticsServer, JoesGunsServer, HongFangTeaHouseServer, HaraKiriSushiBarServer]; + var NetworkGroup2 = [MaxHardwareServer, NectarNightclubServer, Zer0NightclubServer, CyberSecServer]; + var NetworkGroup3 = [OmegaSoftwareServer, PhantasyServer, SilverHelixServer, NeoNightclubServer]; + var NetworkGroup4 = [CrushFitnessGymServer, NetLinkTechnologiesServer, CompuTekServer, TheHubServer, JohnsonOrthopedicsServer, NiteSecServer]; + var NetworkGroup5 = [CatalystVenturesServer, SysCoreSecuritiesServer, SummitUniversityServer, ZBInstituteOfTechnologyServer, RothmanUniversityServer, TheBlackHandServer]; + var NetworkGroup6 = [LexoCorpServer, RhoConstructionServer, AlphaEnterprisesServer, AevumPoliceServer, MilleniumFitnessGymServer]; + var NetworkGroup7 = [GlobalPharmaceuticalsServer, AeroCorpServer, GalacticCyberSystemsServer, SnapFitnessGymServer]; + var NetworkGroup8 = [DeltaOneServer, UnitaLifeGroupServer, OmniaCybersystemsServer]; + var NetworkGroup9 = [ZeusMedicalServer, SolarisSpaceSystemsServer, UniversalEnergyServer, IcarusMicrosystemsServer, DefCommServer]; + var NetworkGroup10 = [NovaMedicalServer, ZBDefenseServer, TaiYangDigitalServer, InfoCommServer]; + var NetworkGroup11 = [AppliedEnergeticsServer, MicrodyneTechnologiesServer, TitanLabsServer, BitRunnersServer]; + var NetworkGroup12 = [VitaLifeServer, HeliosLabsServer, StormTechnologiesServer, FulcrumTechnologiesServer]; + var NetworkGroup13 = [KuaiGongInternationalServer, FourSigmaServer, OmniTekIncorporatedServer, DarkArmyServer]; + var NetworkGroup14 = [PowerhouseGymServer, ClarkeIncorporatedServer, NWOServer, BladeIndustriesServer, BachmanAndAssociatesServer]; + var NetworkGroup15 = [FulcrumSecretTechnologiesServer, MegaCorpServer, ECorpServer, DaedalusServer]; + + for (var i = 0; i < NetworkGroup2.length; i++) { + var randomServerFromPrevGroup = NetworkGroup1[Math.floor(Math.random() * NetworkGroup1.length)]; + NetworkGroup2[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup2[i].ip); + } + + for (var i = 0; i < NetworkGroup3.length; i++) { + var randomServerFromPrevGroup = NetworkGroup2[Math.floor(Math.random() * NetworkGroup2.length)]; + NetworkGroup3[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup3[i].ip); + } + + for (var i = 0; i < NetworkGroup4.length; i++) { + var randomServerFromPrevGroup = NetworkGroup3[Math.floor(Math.random() * NetworkGroup3.length)]; + NetworkGroup4[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup4[i].ip); + } + + for (var i = 0; i < NetworkGroup5.length; i++) { + var randomServerFromPrevGroup = NetworkGroup4[Math.floor(Math.random() * NetworkGroup4.length)]; + NetworkGroup5[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup5[i].ip); + } + + for (var i = 0; i < NetworkGroup6.length; i++) { + var randomServerFromPrevGroup = NetworkGroup5[Math.floor(Math.random() * NetworkGroup5.length)]; + NetworkGroup6[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup6[i].ip); + } + + for (var i = 0; i < NetworkGroup7.length; i++) { + var randomServerFromPrevGroup = NetworkGroup6[Math.floor(Math.random() * NetworkGroup6.length)]; + NetworkGroup7[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup7[i].ip); + } + + for (var i = 0; i < NetworkGroup8.length; i++) { + var randomServerFromPrevGroup = NetworkGroup7[Math.floor(Math.random() * NetworkGroup7.length)]; + NetworkGroup8[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup8[i].ip); + } + + for (var i = 0; i < NetworkGroup9.length; i++) { + var randomServerFromPrevGroup = NetworkGroup8[Math.floor(Math.random() * NetworkGroup8.length)]; + NetworkGroup9[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup9[i].ip); + } + + for (var i = 0; i < NetworkGroup10.length; i++) { + var randomServerFromPrevGroup = NetworkGroup9[Math.floor(Math.random() * NetworkGroup9.length)]; + NetworkGroup10[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup10[i].ip); + } + + for (var i = 0; i < NetworkGroup11.length; i++) { + var randomServerFromPrevGroup = NetworkGroup10[Math.floor(Math.random() * NetworkGroup10.length)]; + NetworkGroup11[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup11[i].ip); + } + + for (var i = 0; i < NetworkGroup12.length; i++) { + var randomServerFromPrevGroup = NetworkGroup11[Math.floor(Math.random() * NetworkGroup11.length)]; + NetworkGroup12[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup12[i].ip); + } + + for (var i = 0; i < NetworkGroup13.length; i++) { + var randomServerFromPrevGroup = NetworkGroup12[Math.floor(Math.random() * NetworkGroup12.length)]; + NetworkGroup13[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup13[i].ip); + } + + for (var i = 0; i < NetworkGroup14.length; i++) { + var randomServerFromPrevGroup = NetworkGroup13[Math.floor(Math.random() * NetworkGroup13.length)]; + NetworkGroup14[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup14[i].ip); + } + + for (var i = 0; i < NetworkGroup15.length; i++) { + var randomServerFromPrevGroup = NetworkGroup14[Math.floor(Math.random() * NetworkGroup14.length)]; + NetworkGroup15[i].serversOnNetwork.push(randomServerFromPrevGroup.ip); + randomServerFromPrevGroup.serversOnNetwork.push(NetworkGroup15[i].ip); + } + + //Connect the first tier of servers to the player's home computer + for (var i = 0; i < NetworkGroup1.length; i++) { + __WEBPACK_IMPORTED_MODULE_3__Player_js__["a" /* Player */].getHomeComputer().serversOnNetwork.push(NetworkGroup1[i].ip); + NetworkGroup1[i].serversOnNetwork.push(__WEBPACK_IMPORTED_MODULE_3__Player_js__["a" /* Player */].homeComputer); + } +} + +//Applied server growth for a single server. Returns the percentage growth +function processSingleServerGrowth(server, numCycles) { + //Server growth processed once every 450 game cycles + var numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0); + + //Get adjusted growth rate, which accounts for server security + var growthRate = __WEBPACK_IMPORTED_MODULE_1__Constants_js__["a" /* CONSTANTS */].ServerBaseGrowthRate; + var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty; + if (adjGrowthRate > __WEBPACK_IMPORTED_MODULE_1__Constants_js__["a" /* CONSTANTS */].ServerMaxGrowthRate) {adjGrowthRate = __WEBPACK_IMPORTED_MODULE_1__Constants_js__["a" /* CONSTANTS */].ServerMaxGrowthRate;} + + //Calculate adjusted server growth rate based on parameters + var serverGrowthPercentage = server.serverGrowth / 100; + var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * __WEBPACK_IMPORTED_MODULE_0__BitNode_js__["a" /* BitNodeMultipliers */].ServerGrowthRate; + + //Apply serverGrowth for the calculated number of growth cycles + var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * __WEBPACK_IMPORTED_MODULE_3__Player_js__["a" /* Player */].hacking_grow_mult); + if (serverGrowth < 1) { + console.log("WARN: serverGrowth calculated to be less than 1"); + serverGrowth = 1; + } + + server.moneyAvailable *= serverGrowth; + if (server.moneyMax && isNaN(server.moneyAvailable)) { + server.moneyAvailable = server.moneyMax; + } + if (server.moneyMax && server.moneyAvailable > server.moneyMax) { + server.moneyAvailable = server.moneyMax; + return 1; + } + + //Growing increases server security twice as much as hacking + server.fortify(2 * __WEBPACK_IMPORTED_MODULE_1__Constants_js__["a" /* CONSTANTS */].ServerFortifyAmount * numServerGrowthCycles); + return serverGrowth; +} + +function prestigeHomeComputer(homeComp) { + homeComp.programs.length = 0; + homeComp.runningScripts = []; + homeComp.serversOnNetwork = []; + homeComp.isConnectedTo = true; + homeComp.ramUsed = 0; + homeComp.programs.push(__WEBPACK_IMPORTED_MODULE_2__CreateProgram_js__["a" /* Programs */].NukeProgram); + + homeComp.messages.length = 0; +} + +//List of all servers that exist in the game, indexed by their ip +let AllServers = {}; + +function prestigeAllServers() { + for (var member in AllServers) { + delete AllServers[member]; + } + AllServers = {}; +} + +function loadAllServers(saveString) { + AllServers = JSON.parse(saveString, __WEBPACK_IMPORTED_MODULE_8__utils_JSONReviver_js__["c" /* Reviver */]); +} + +function SizeOfAllServers() { + var size = 0, key; + for (key in AllServers) { + if (AllServers.hasOwnProperty(key)) size++; + } + return size; +} + +//Add a server onto the map of all servers in the game +function AddToAllServers(server) { + var serverIp = server.ip; + if (Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["b" /* ipExists */])(serverIp)) { + console.log("IP of server that's being added: " + serverIp); + console.log("Hostname of the server thats being added: " + server.hostname); + console.log("The server that already has this IP is: " + AllServers[serverIp].hostname); + throw new Error("Error: Trying to add a server with an existing IP"); + return; + } + AllServers[serverIp] = server; +} + +//Returns server object with corresponding hostname +// Relatively slow, would rather not use this a lot +function GetServerByHostname(hostname) { + for (var ip in AllServers) { + if (AllServers.hasOwnProperty(ip)) { + if (AllServers[ip].hostname == hostname) { + return AllServers[ip]; + } + } + } + return null; +} + +//Get server by IP or hostname. Returns null if invalid +function getServer(s) { + if (!Object(__WEBPACK_IMPORTED_MODULE_7__utils_IPAddress_js__["c" /* isValidIPAddress */])(s)) { + return GetServerByHostname(s); + } else { + return AllServers[s]; + } +} + +//Debugging tool +function PrintAllServers() { + for (var ip in AllServers) { + if (AllServers.hasOwnProperty(ip)) { + console.log("Ip: " + ip + ", hostname: " + AllServers[ip].hostname); + } + } +} + + + + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return Reviver; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return Generic_toJSON; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Generic_fromJSON; }); +/* Generic Reviver, toJSON, and fromJSON functions used for saving and loading objects */ + +// A generic "smart reviver" function. +// Looks for object values with a `ctor` property and +// a `data` property. If it finds them, and finds a matching +// constructor that has a `fromJSON` property on it, it hands +// off to that `fromJSON` fuunction, passing in the value. +function Reviver(key, value) { + var ctor; + if (value == null) { + console.log("Reviver WRONGLY called with key: " + key + ", and value: " + value); + return 0; + } + if (typeof value === "object" && + typeof value.ctor === "string" && + typeof value.data !== "undefined") { + ctor = Reviver.constructors[value.ctor] || window[value.ctor]; + if (typeof ctor === "function" && + typeof ctor.fromJSON === "function") { + + return ctor.fromJSON(value); + } + } + return value; +} +Reviver.constructors = {}; // A list of constructors the smart reviver should know about + +// A generic "toJSON" function that creates the data expected +// by Reviver. +// `ctorName` The name of the constructor to use to revive it +// `obj` The object being serialized +// `keys` (Optional) Array of the properties to serialize, +// if not given then all of the objects "own" properties +// that don't have function values will be serialized. +// (Note: If you list a property in `keys`, it will be serialized +// regardless of whether it's an "own" property.) +// Returns: The structure (which will then be turned into a string +// as part of the JSON.stringify algorithm) +function Generic_toJSON(ctorName, obj, keys) { + var data, index, key; + + if (!keys) { + keys = Object.keys(obj); // Only "own" properties are included + } + + data = {}; + for (index = 0; index < keys.length; ++index) { + key = keys[index]; + data[key] = obj[key]; + } + return {ctor: ctorName, data: data}; +} + +// A generic "fromJSON" function for use with Reviver: Just calls the +// constructor function with no arguments, then applies all of the +// key/value pairs from the raw data to the instance. Only useful for +// constructors that can be reasonably called without arguments! +// `ctor` The constructor to call +// `data` The data to apply +// Returns: The object +function Generic_fromJSON(ctor, data) { + var obj, name; + + obj = new ctor(); + for (name in data) { + obj[name] = data[name]; + } + return obj; +} + + + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/ActiveScriptsUI.js b/src/ActiveScriptsUI.js index 628258467..38a6bcdbd 100644 --- a/src/ActiveScriptsUI.js +++ b/src/ActiveScriptsUI.js @@ -1,5 +1,14 @@ -/* Active Scripts UI*/ +import {workerScripts, + addWorkerScript, + killWorkerScript} from "./NetscriptWorker.js"; +import {getServer} from "./Server.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {printArray} from "../utils/HelperFunctions.js"; +import {logBoxCreate} from "../utils/LogBox.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; + +/* Active Scripts UI*/ function setActiveScriptsClickHandlers() { //Server panel click handlers var serverPanels = document.getElementsByClassName("active-scripts-server-header"); @@ -10,7 +19,7 @@ function setActiveScriptsClickHandlers() { for (i = 0; i < serverPanels.length; ++i) { serverPanels[i].onclick = function() { this.classList.toggle("active"); - + var panel = this.nextElementSibling; if (panel.style.display === "block") { panel.style.display = "none"; @@ -19,7 +28,7 @@ function setActiveScriptsClickHandlers() { } } } - + //Script Panel click handlers var scriptPanels = document.getElementsByClassName("active-scripts-script-header"); if (scriptPanels == null) { @@ -29,13 +38,13 @@ function setActiveScriptsClickHandlers() { for (var i = 0; i < scriptPanels.length; ++i) { scriptPanels[i].onclick = function() { this.classList.toggle("active"); - + var panel = this.nextElementSibling; if (panel.style.display === "block") { panel.style.display = "none"; } else { panel.style.display = "block"; - } + } } } } @@ -54,35 +63,34 @@ function getActiveScriptsServerList(server) { function createActiveScriptsServerPanel(server) { var panelname = "active-scripts-server-panel-" + server.hostname; var activeScriptsList = document.getElementById("active-scripts-list"); - + //Div of entire Panel var panelDiv = document.createElement("div"); panelDiv.setAttribute("id", panelname); - + //Panel Header var panelHdr = document.createElement("button"); panelHdr.setAttribute("class", "active-scripts-server-header") panelHdr.setAttribute("id", panelname + "-hdr"); panelHdr.innerHTML = server.hostname; - + //Panel content var panelContentDiv = document.createElement("div"); panelContentDiv.setAttribute("class", "active-scripts-server-panel"); panelContentDiv.setAttribute("id", panelname + "-content"); - + //List of scripts var panelScriptList = document.createElement("ul"); panelScriptList.setAttribute("id", panelname + "-script-list"); - + panelContentDiv.appendChild(panelScriptList); panelDiv.appendChild(panelHdr); panelDiv.appendChild(panelContentDiv); activeScriptsList.appendChild(panelDiv); - + setActiveScriptsClickHandlers() //Reset click handlers - + return panelDiv; - //TODO Alphabetize Active Scripts list? } //Deletes the info for a particular server (Dropdown header + Panel with all info) @@ -94,7 +102,7 @@ function deleteActiveScriptsServerPanel(server) { console.log("No such panel exists: " + panelname); return; } - + //Remove the panel if it has no elements var scriptList = document.getElementById(panelname + "-script-list"); if (scriptList.childNodes.length == 0) { @@ -110,12 +118,12 @@ function addActiveScriptsItem(workerscript) { return; } var panelname = "active-scripts-server-panel-" + server.hostname; - + var panel = document.getElementById(panelname); if (panel == null) { panel = createActiveScriptsServerPanel(server); } - + //Create the element itself. Each element is an accordion collapsible var itemNameArray = ["active", "scripts", server.hostname, workerscript.name]; for (var i = 0; i < workerscript.args.length; ++i) { @@ -125,24 +133,24 @@ function addActiveScriptsItem(workerscript) { //var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var item = document.createElement("li"); item.setAttribute("id", itemName); - + var btn = document.createElement("button"); btn.setAttribute("class", "active-scripts-script-header"); btn.innerHTML = workerscript.name; - + var itemContentDiv = document.createElement("div"); itemContentDiv.setAttribute("class", "active-scripts-script-panel"); itemContentDiv.setAttribute("id", itemName + "-content"); - + item.appendChild(btn); item.appendChild(itemContentDiv); - + createActiveScriptsText(workerscript, itemContentDiv); - + //Append element to list var list = getActiveScriptsServerList(server); list.appendChild(item); - + setActiveScriptsClickHandlers() //Reset click handlers } @@ -191,47 +199,47 @@ function updateActiveScriptsItemContent(workerscript) { var itemName = itemNameArray.join("-"); //var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemContent = document.getElementById(itemName + "-content") - + //Clear the item while (itemContent.firstChild) { itemContent.removeChild(itemContent.firstChild); } - + //Add the updated text back. Returns the total online production rate return createActiveScriptsText(workerscript, itemContent); } function createActiveScriptsText(workerscript, item) { var itemText = document.createElement("p"); - + //Server ip/hostname var threads = "Threads: " + workerscript.scriptRef.threads; var args = "Args: " + printArray(workerscript.args); - + //Online var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2); var onlineTotalExpEarned = (Array(26).join(" ") + formatNumber(workerscript.scriptRef.onlineExpGained, 2) + " hacking exp").replace( / /g, " "); - + var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime; var onlineMpsText = "Online production rate: $" + formatNumber(onlineMps, 2) + "/second"; var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime; var onlineEpsText = (Array(25).join(" ") + formatNumber(onlineEps, 4) + " hacking exp/second").replace( / /g, " "); - + //Offline var offlineTotalMoneyMade = "Total offline production: $" + formatNumber(workerscript.scriptRef.offlineMoneyMade, 2); var offlineTotalExpEarned = (Array(27).join(" ") + formatNumber(workerscript.scriptRef.offlineExpGained, 2) + " hacking exp").replace( / /g, " "); - + var offlineMps = workerscript.scriptRef.offlineMoneyMade / workerscript.scriptRef.offlineRunningTime; var offlineMpsText = "Offline production rate: $" + formatNumber(offlineMps, 2) + "/second"; var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime; var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, " "); - + itemText.innerHTML = threads + "
" + args + "
" + onlineTotalMoneyMade + "
" + onlineTotalExpEarned + "
" + onlineMpsText + "
" + onlineEpsText + "
" + offlineTotalMoneyMade + "
" + offlineTotalExpEarned + "
" + offlineMpsText + "
" + offlineEpsText + "
"; - + item.appendChild(itemText); - + var logButton = document.createElement("span"); logButton.innerHTML = "Log"; var killButton = document.createElement("span"); @@ -249,7 +257,9 @@ function createActiveScriptsText(workerscript, item) { }); item.appendChild(logButton); item.appendChild(killButton); - + //Return total online production rate return onlineMps; -} \ No newline at end of file +} + +export {setActiveScriptsClickHandlers, addActiveScriptsItem, deleteActiveScriptsItem, updateActiveScriptsItems}; diff --git a/src/Alias.js b/src/Alias.js index 6e5974989..405bd984e 100644 --- a/src/Alias.js +++ b/src/Alias.js @@ -1,6 +1,23 @@ -/* Alias.js */ -Aliases = {}; -GlobalAliases = {}; +import {post} from "./Terminal.js"; + +let Aliases = {}; +let GlobalAliases = {}; + +function loadAliases(saveString) { + if (saveString === "") { + Aliases = {}; + } else { + Aliases = JSON.parse(saveString); + } +} + +function loadGlobalAliases(saveString) { + if (saveString === "") { + GlobalAliases = {}; + } else { + GlobalAliases = JSON.parse(saveString); + } +} //Print all aliases to terminal function printAliases() { @@ -91,4 +108,7 @@ function substituteAliases(origCommand) { } } return commandArray.join(" "); -} \ No newline at end of file +} + +export {Aliases, GlobalAliases, printAliases, parseAliasDeclaration, + removeAlias, substituteAliases, loadAliases, loadGlobalAliases}; diff --git a/src/Augmentations.js b/src/Augmentations.js index a4aeb0f5c..22ceefd89 100644 --- a/src/Augmentations.js +++ b/src/Augmentations.js @@ -1,3 +1,12 @@ +import {BitNodeMultipliers} from "./BitNode.js"; +import {CONSTANTS} from "./Constants.js"; +import {Player} from "./Player.js"; +import {prestigeAugmentation} from "./Prestige.js"; +import {Factions, getNextNeurofluxLevel} from "./Faction.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; + //Augmentations function Augmentation(name) { this.name = name; @@ -18,8 +27,8 @@ Augmentation.prototype.setInfo = function(inf) { } Augmentation.prototype.setRequirements = function(rep, cost) { - this.baseRepRequirement = rep * CONSTANTS.AugmentationRepMultiplier; - this.baseCost = cost * CONSTANTS.AugmentationCostMultiplier; + this.baseRepRequirement = rep * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost; + this.baseCost = cost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost; } //Takes in an array of faction names and adds this augmentation to all of those factions @@ -57,14 +66,14 @@ Augmentation.fromJSON = function(value) { Reviver.constructors.Augmentation = Augmentation; -Augmentations = {} +let Augmentations = {} -AddToAugmentations = function(aug) { +function AddToAugmentations(aug) { var name = aug.name; Augmentations[name] = aug; } -AugmentationNames = { +let AugmentationNames = { Targeting1: "Augmented Targeting I", Targeting2: "Augmented Targeting II", Targeting3: "Augmented Targeting III", @@ -153,7 +162,7 @@ AugmentationNames = { SNA: "Social Negotiation Assistant (S.N.A)" } -initAugmentations = function() { +function initAugmentations() { for (var name in Factions) { if (Factions.hasOwnProperty(name)) { Factions[name].augmentations = []; @@ -377,7 +386,7 @@ initAugmentations = function() { } AddToAugmentations(SpeechProcessor); - TITN41Injection = new Augmentation(AugmentationNames.TITN41Injection); + let TITN41Injection = new Augmentation(AugmentationNames.TITN41Injection); TITN41Injection.setRequirements(10000, 38000000); TITN41Injection.setInfo("TITN is a series of viruses that targets and alters the sequences of human DNA in genes that " + "control personality. The TITN-41 strain alters these genes so that the subject becomes more " + @@ -1403,7 +1412,7 @@ initAugmentations = function() { } } -applyAugmentation = function(aug, reapply=false) { +function applyAugmentation(aug, reapply=false) { Augmentations[aug.name].owned = true; switch(aug.name) { //Combat stat augmentations @@ -1904,7 +1913,7 @@ function PlayerOwnedAugmentation(name) { function installAugmentations() { if (Player.queuedAugmentations.length == 0) { dialogBoxCreate("You have not purchased any Augmentations to install!"); - return; + return false; } var augmentationList = ""; for (var i = 0; i < Player.queuedAugmentations.length; ++i) { @@ -1923,39 +1932,6 @@ function installAugmentations() { prestigeAugmentation(); } -PlayerObject.prototype.reapplyAllAugmentations = function(resetMultipliers=true) { - console.log("Re-applying augmentations"); - if (resetMultipliers) { - this.resetMultipliers(); - } - - for (i = 0; i < this.augmentations.length; ++i) { - //Compatibility with new version - if (typeof this.augmentations[i] === 'string' || this.augmentations[i] instanceof String) { - var newOwnedAug = new PlayerOwnedAugmentation(this.augmentations[i]); - if (this.augmentations[i] == AugmentationNames.NeuroFluxGovernor) { - newOwnedAug.level = Augmentations[AugmentationNames.NeuroFluxGovernor].level; - } - this.augmentations[i] = newOwnedAug; - } - - var augName = this.augmentations[i].name; - var aug = Augmentations[augName]; - aug.owned = true; - if (aug == null) { - console.log("WARNING: Invalid augmentation name"); - continue; - } - if (aug.name == AugmentationNames.NeuroFluxGovernor) { - for (j = 0; j < aug.level; ++j) { - applyAugmentation(this.augmentations[i], true); - } - continue; - } - applyAugmentation(this.augmentations[i], true); - } -} - function augmentationExists(name) { return Augmentations.hasOwnProperty(name); } @@ -1970,3 +1946,6 @@ function giveAllAugmentations() { } Player.reapplyAllAugmentations(); } + +export {AugmentationNames, Augmentations, PlayerOwnedAugmentation, installAugmentations, + initAugmentations, applyAugmentation, augmentationExists, Augmentation}; diff --git a/src/BitNode.js b/src/BitNode.js index 3ec373e48..b729a4fbf 100644 --- a/src/BitNode.js +++ b/src/BitNode.js @@ -1,7 +1,16 @@ -/* BitNode.js */ +import {Player} from "./Player.js"; -BitNodes = { - BitNode1: new BitNode(1, "Source Genesis", "The original BitNode", +function BitNode(n, name, desc="", info="") { + this.number = n; + this.name = name; + this.desc = desc; + this.info = info; +} + +let BitNodes = {}; +function initBitNodes() { + BitNodes = {}; + BitNodes["BitNode1"] = new BitNode(1, "Source Genesis", "The original BitNode", "The first BitNode created by the Enders to imprison the minds of humans. It became " + "the prototype and testing-grounds for all of the BitNodes that followed.

" + "This is the first BitNode that you play through. It has no special " + @@ -12,8 +21,8 @@ BitNodes = { "new BitNode, and also increases all of the player's multipliers by:

" + "Level 1: 16%
" + "Level 2: 24%
" + - "Level 3: 28%"), - BitNode2: new BitNode(2, "Rise of the Underworld", "From the shadows, they rose", //Gangs + "Level 3: 28%"); + BitNodes["BitNode2"] = new BitNode(2, "Rise of the Underworld", "From the shadows, they rose", //Gangs "From the shadows, they rose.

Organized crime groups quickly filled the void of power " + "left behind from the collapse of Western government in the 2050's. As society and civlization broke down, " + "people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " + @@ -31,52 +40,71 @@ BitNodes = { "crime money, and charisma multipliers by:

" + "Level 1: 20%
" + "Level 2: 30%
" + - "Level 3: 35%"), - BitNode3: new BitNode(3, "The Price of Civilization", "COMING SOON"), //Corporate Warfare, Run own company - BitNode4: new BitNode(4, "The Singularity", "COMING SOON"), //Everything automatable - BitNode5: new BitNode(5, "2084", "COMING SOON"), //Big Brother - BitNode6: new BitNode(6, "Hacktocracy", "COMING SOON"), //Healthy Hacknet balancing mechanic - BitNode7: new BitNode(7, "Do Androids Dream?", "COMING SOON"), //Build androids for automation - BitNode8: new BitNode(8, "Ghost of Wall Street", "COMING SOON"), //Trading only viable strategy - BitNode9: new BitNode(9, "MegaCorp", "COMING SOON"), //Single corp/server with increasing difficulty - BitNode10: new BitNode(10, "Wasteland", "COMING SOON"), //Postapocalyptic - BitNode11: new BitNode(11, "The Big Crash", "COMING SOON"), //Crashing economy - /* Okay. Sell it all. - "The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " + - "of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " + - "the USA and China. But just as the world was slowly beginning to recover from these dark times, financial catastrophe hit.

" + - "In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of this chaos and confusion hackers " + - "were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as " + - "governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.

" + - "In this BitNode:

" + - "The starting and maximum amount of money available on servers is significantly decreased
" + - "The growth rate of servers is halved
" + - "Weakening a server is twice as effective
" + - "Company wages are decreased by 25%
" + - "Hacknet Node production is significantly decreased
" + - "Augmentations are twice as expensive

" + - "Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will " + - "upgrade its level up to a maximum of 3. This Source-File increases the player's company salary multiplier by:

" + - "Level 1: 60%
" + - "Level 2: 90%
" + - "Level 3: 105%"; + "Level 3: 35%"); + BitNodes["BitNode3"] = new BitNode(3, "The Price of Civilization", "COMING SOON"); //Corporate Warfare, Run own company + BitNodes["BitNode4"] = new BitNode(4, "The Singularity", "The Man and the Machine", "The Singularity has arrived. The human race is gone, replaced " + + "by artificially superintelligent beings that are more machine than man.

" + + "In this BitNode, progressing is significantly harder. Experience gain rates " + + "for all stats are reduced. Most methods of earning money will now give significantly less.

" + + "In this BitNode you will gain access to a new set of Netscript Functions known as Singularity Functions. " + + "These functions allow you to control most aspects of the game through scripts, including working for factions/companies, " + + "purchasing/installing Augmentations, and creating programs.

" + + "Destroying this BitNode will give you Source-File 4, or if you already have this Source-File it will " + + "upgrade its level up to a maximum of 3. This Source-File lets you access and use the Singularity " + + "Functions in other BitNodes. Each level of this Source-File will open up more Singularity Functions " + + "that you can use."); + BitNodes["BitNode5"] = new BitNode(5, "Artificial Intelligence", "COMING SOON"); //Int + BitNodes["BitNode6"] = new BitNode(6, "Hacktocracy", "COMING SOON"); //Healthy Hacknet balancing mechanic + BitNodes["BitNode7"] = new BitNode(7, "Do Androids Dream?", "COMING SOON"); //Build androids for automation + BitNodes["BitNode8"] = new BitNode(8, "Ghost of Wall Street", "COMING SOON"); //Trading only viable strategy + BitNodes["BitNode9"] = new BitNode(9, "MegaCorp", "COMING SOON"); //Single corp/server with increasing difficulty + BitNodes["BitNode10"] = new BitNode(10, "Wasteland", "COMING SOON"); //Postapocalyptic + BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.", //Crashing economy + "The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " + + "of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " + + "the USA and China. But just as the world was slowly beginning to recover from these dark times, financial catastrophe hit.

" + + "In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of this chaos and confusion, hackers " + + "were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as " + + "governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.

" + + "In this BitNode:

" + + "The starting and maximum amount of money available on servers is significantly decreased
" + + "The growth rate of servers is halved
" + + "Weakening a server is twice as effective
" + + "Company wages are decreased by 50%
" + + "Hacknet Node production is significantly decreased
" + + "Augmentations are twice as expensive

" + + "Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will " + + "upgrade its level up to a maximum of 3. This Source-File increases the player's company salary and reputation gain multipliers by:

" + + "Level 1: 60%
" + + "Level 2: 90%
" + + "Level 3: 105%"); - */ - BitNode12: new BitNode(12, "Eye of the World", "COMING SOON"), //Become AI + BitNodes["BitNode12"] = new BitNode(12, "Eye of the World", "COMING SOON"); //Become AI } -function BitNode(n, name, desc="", info="") { - this.number = n; - this.name = name; - this.desc = desc; - this.info = info; -} - -BitNodeMultipliers = { +let BitNodeMultipliers = { ServerMaxMoney: 1, + ServerStartingMoney: 1, + ServerGrowthRate: 1, + ServerWeakenRate: 1, + + ManualHackMoney: 1, + ScriptHackMoney: 1, + CompanyWorkMoney: 1, CrimeMoney: 1, + HacknetNodeMoney: 1, + + CompanyWorkExpGain: 1, + ClassGymExpGain: 1, + FactionWorkExpGain: 1, + HackExpGain: 1, + CrimeExpGain: 1, + FactionWorkRepGain: 1, FactionPassiveRepGain: 1, + + AugmentationRepCost: 1, + AugmentationMoneyCost: 1, } function initBitNodeMultipliers() { @@ -93,13 +121,37 @@ function initBitNodeMultipliers() { case 1: break; case 2: //Rise of the Underworld - BitNodeMultipliers.ServerMaxMoney = 0.2; - BitNodeMultipliers.CrimeMoney = 2; - BitNodeMultipliers.FactionWorkRepGain = 0.5; - BitNodeMultipliers.FactionPassiveRepGain = 0; + BitNodeMultipliers.ServerMaxMoney = 0.2; + BitNodeMultipliers.CrimeMoney = 2; + BitNodeMultipliers.FactionWorkRepGain = 0.5; + BitNodeMultipliers.FactionPassiveRepGain = 0; + break; + case 4: //The Singularity + BitNodeMultipliers.ServerMaxMoney = 0.15; + BitNodeMultipliers.ScriptHackMoney = 0.2; + BitNodeMultipliers.CompanyWorkMoney = 0.1; + BitNodeMultipliers.CrimeMoney = 0.2; + BitNodeMultipliers.HacknetNodeMoney = 0.05; + BitNodeMultipliers.CompanyWorkExpGain = 0.5; + BitNodeMultipliers.ClassGymExpGain = 0.5; + BitNodeMultipliers.FactionWorkExpGain = 0.5; + BitNodeMultipliers.HackExpGain = 0.4; + BitNodeMultipliers.CrimeExpGain = 0.5; + BitNodeMultipliers.FactionWorkRepGain = 0.75; + break; + case 11: //The Big Crash + BitNodeMultipliers.ServerMaxMoney = 0.1; + BitNodeMultipliers.ServerStartingMoney = 0.25; + BitNodeMultipliers.ServerGrowthRate = 0.5; + BitNodeMultipliers.ServerWeakenRate = 2; + BitNodeMultipliers.CompanyWorkMoney = 0.5; + BitNodeMultipliers.HacknetNodeMoney = 0.1; + BitNodeMultipliers.AugmentationMoneyCost = 2; break; default: console.log("WARNING: Player.bitNodeN invalid"); break; } } + +export {initBitNodes, BitNode, BitNodes, BitNodeMultipliers, initBitNodeMultipliers}; diff --git a/src/Company.js b/src/Company.js index 072b5bcd2..a9a2c4954 100644 --- a/src/Company.js +++ b/src/Company.js @@ -1,3 +1,10 @@ +import {CONSTANTS} from "./Constants.js"; +import {Locations} from "./Location.js"; +import {Player} from "./Player.js"; + +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; + //Netburner Company class // Note: Company Positions can be loaded every time with init() but Company class needs // to be saved/loaded from localStorage @@ -251,7 +258,7 @@ CompanyPosition.fromJSON = function(value) { Reviver.constructors.CompanyPosition = CompanyPosition; -CompanyPositions = { +let CompanyPositions = { //Constructor: CompanyPosition(name, reqHack, reqStr, reqDef, reqDex, reqAgi, reqCha, reqRep, salary) //Software @@ -403,7 +410,7 @@ CompanyPositions = { //Returns the next highest position in the company for the relevant career/field //I.E returns what your next job would be if you qualify for a promotion -getNextCompanyPosition = function(currPos) { +function getNextCompanyPosition(currPos) { if (currPos == null) {return null;} //Software if (currPos.positionName == CompanyPositions.SoftwareIntern.positionName) { @@ -511,7 +518,7 @@ getNextCompanyPosition = function(currPos) { /* Initialize all companies. Only called when creating new game/prestiging. Otherwise companies are * usually loaded from localStorage */ -initCompanies = function() { +function initCompanies() { /* Companies that also have servers */ //Megacorporations var ECorp = new Company(Locations.AevumECorp, 3.0, 3.0, 249); @@ -1088,10 +1095,14 @@ initCompanies = function() { } //Map of all companies that exist in the game, indexed by their name -Companies = {} +let Companies = {} + +function loadCompanies(saveString) { + Companies = JSON.parse(saveString, Reviver); +} //Add a Company object onto the map of all Companies in the game -AddToCompanies = function (company) { +function AddToCompanies(company) { var name = company.companyName; Companies[name] = company; } @@ -1099,3 +1110,41 @@ AddToCompanies = function (company) { function companyExists(name) { return Companies.hasOwnProperty(name); } + +function getJobRequirementText(company, pos, tooltiptext=false) { + var reqText = ""; + var offset = company.jobStatReqOffset; + var reqHacking = pos.requiredHacking > 0 ? pos.requiredHacking+offset : 0; + var reqStrength = pos.requiredStrength > 0 ? pos.requiredStrength+offset : 0; + var reqDefense = pos.requiredDefense > 0 ? pos.requiredDefense+offset : 0; + var reqDexterity = pos.requiredDexterity > 0 ? pos.requiredDexterity+offset : 0; + var reqAgility = pos.requiredDexterity > 0 ? pos.requiredDexterity+offset : 0; + var reqCharisma = pos.requiredCharisma > 0 ? pos.requiredCharisma+offset : 0; + var reqRep = pos.requiredReputation; + if (tooltiptext) { + reqText = "Requires:
"; + reqText += (reqHacking.toString() + " hacking
"); + reqText += (reqStrength.toString() + " strength
"); + reqText += (reqDefense.toString() + " defense
"); + reqText += (reqDexterity.toString() + " dexterity
"); + reqText += (reqAgility.toString() + " agility
"); + reqText += (reqCharisma.toString() + " charisma
"); + reqText += (reqRep.toString() + " reputation"); + } else { + reqText = "(Requires "; + if (reqHacking > 0) {reqText += (reqHacking + " hacking, ");} + if (reqStrength > 0) {reqText += (reqStrength + " strength, ");} + if (reqDefense > 0) {reqText += (reqDefense + " defense, ");} + if (reqDexterity > 0) {reqText += (reqDexterity + " dexterity, ");} + if (reqAgility > 0) {reqText += (reqAgility + " agility, ");} + if (reqCharisma > 0) {reqText += (reqCharisma + " charisma, ");} + if (reqRep > 1) {reqText += (reqRep + " reputation, ");} + reqText = reqText.substring(0, reqText.length - 2); + reqText += ")"; + } + return reqText; +} + +export {CompanyPositions, initCompanies, Companies, getJobRequirementText, + getNextCompanyPosition, loadCompanies, Company, CompanyPosition, + companyExists}; diff --git a/src/CompanyJobApplication.js b/src/CompanyJobApplication.js index a1be49b8c..4723340b6 100644 --- a/src/CompanyJobApplication.js +++ b/src/CompanyJobApplication.js @@ -1,273 +1 @@ -/* Functions that handle applying for different jobs/positions in a Company */ - -//Determines the job that the Player should get (if any) at the current -//company -PlayerObject.prototype.applyForJob = function(entryPosType) { - var currCompany = ""; - if (this.companyName != "") { - currCompany = Companies[this.companyName]; - } - var currPositionName = ""; - if (this.companyPosition != "") { - currPositionName = this.companyPosition.positionName; - } - var company = Companies[this.location]; //Company being applied to - - var pos = entryPosType; - - if (!this.isQualified(company, pos)) { - var reqText = getJobRequirementText(company, pos); - dialogBoxCreate("Unforunately, you do not qualify for this position
" + reqText); - return; - } - - while (true) { - if (Engine.Debug) {console.log("Determining qualification for next Company Position");} - var newPos = getNextCompanyPosition(pos); - if (newPos == null) {break;} - - //Check if this company has this position - if (company.hasPosition(newPos)) { - if (!this.isQualified(company, newPos)) { - //If player not qualified for next job, break loop so player will be given current job - break; - } - pos = newPos; - } else { - break; - } - } - - //Check if the determined job is the same as the player's current job - if (currCompany != "") { - if (currCompany.companyName == company.companyName && - pos.positionName == currPositionName) { - var nextPos = getNextCompanyPosition(pos); - if (nextPos == null) { - dialogBoxCreate("You are already at the highest position for your field! No promotion available"); - } else if (company.hasPosition(nextPos)) { - var reqText = getJobRequirementText(company, nextPos); - dialogBoxCreate("Unfortunately, you do not qualify for a promotion
" + reqText); - } else { - dialogBoxCreate("You are already at the highest position for your field! No promotion available"); - } - return; //Same job, do nothing - } - } - - - //Lose reputation from a Company if you are leaving it for another job - var leaveCompany = false; - var oldCompanyName = ""; - if (currCompany != "") { - if (currCompany.companyName != company.companyName) { - leaveCompany = true; - oldCompanyName = currCompany.companyName; - company.playerReputation -= 1000; - if (company.playerReputation < 0) {company.playerReputation = 0;} - if (Engine.debug) { - console.log("Lost reputation for " + company.companyName + ". It is now " + company.playerReputation); - } - } - } - - this.companyName = company.companyName; - this.companyPosition = pos; - - if (leaveCompany) { - dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + - pos.positionName + "!
" + - "You lost 1000 reputation at your old company " + oldCompanyName + " because you left."); - } else { - dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.positionName + "!"); - } - - Engine.loadLocationContent(); -} - -function getJobRequirementText(company, pos, tooltiptext=false) { - var reqText = ""; - var offset = company.jobStatReqOffset; - var reqHacking = pos.requiredHacking > 0 ? pos.requiredHacking+offset : 0; - var reqStrength = pos.requiredStrength > 0 ? pos.requiredStrength+offset : 0; - var reqDefense = pos.requiredDefense > 0 ? pos.requiredDefense+offset : 0; - var reqDexterity = pos.requiredDexterity > 0 ? pos.requiredDexterity+offset : 0; - var reqAgility = pos.requiredDexterity > 0 ? pos.requiredDexterity+offset : 0; - var reqCharisma = pos.requiredCharisma > 0 ? pos.requiredCharisma+offset : 0; - var reqRep = pos.requiredReputation; - if (tooltiptext) { - reqText = "Requires:
"; - reqText += (reqHacking.toString() + " hacking
"); - reqText += (reqStrength.toString() + " strength
"); - reqText += (reqDefense.toString() + " defense
"); - reqText += (reqDexterity.toString() + " dexterity
"); - reqText += (reqAgility.toString() + " agility
"); - reqText += (reqCharisma.toString() + " charisma
"); - reqText += (reqRep.toString() + " reputation"); - } else { - reqText = "(Requires "; - if (reqHacking > 0) {reqText += (reqHacking + " hacking, ");} - if (reqStrength > 0) {reqText += (reqStrength + " strength, ");} - if (reqDefense > 0) {reqText += (reqDefense + " defense, ");} - if (reqDexterity > 0) {reqText += (reqDexterity + " dexterity, ");} - if (reqAgility > 0) {reqText += (reqAgility + " agility, ");} - if (reqCharisma > 0) {reqText += (reqCharisma + " charisma, ");} - if (reqRep > 1) {reqText += (reqRep + " reputation, ");} - reqText = reqText.substring(0, reqText.length - 2); - reqText += ")"; - } - return reqText; -} - -//Returns your next position at a company given the field (software, business, etc.) -PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType) { - var currCompany = null; - if (this.companyName != "") { - currCompany = Companies[this.companyName]; - } - - //Not employed at this company, so return the entry position - if (currCompany == null || (currCompany.companyName != company.companyName)) { - return entryPosType; - } - - //If the entry pos type and the player's current position have the same type, - //return the player's "nextCompanyPosition". Otherwise return the entryposType - //Employed at this company, so just return the next position if it exists. - if ((this.companyPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) || - (this.companyPosition.isITJob() && entryPosType.isITJob()) || - (this.companyPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) || - (this.companyPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) || - (this.companyPosition.isSecurityJob() && entryPosType.isSecurityJob()) || - (this.companyPosition.isAgentJob() && entryPosTypeisAgentJob()) || - (this.companyPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) || - (this.companyPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) || - (this.companyPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) { - return getNextCompanyPosition(this.companyPosition); - } - - - return entryPosType; -} - -PlayerObject.prototype.applyForSoftwareJob = function() { - this.applyForJob(CompanyPositions.SoftwareIntern); -} - -PlayerObject.prototype.applyForSoftwareConsultantJob = function() { - this.applyForJob(CompanyPositions.SoftwareConsultant); -} - -PlayerObject.prototype.applyForItJob = function() { - this.applyForJob(CompanyPositions.ITIntern); -} - -PlayerObject.prototype.applyForSecurityEngineerJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.SecurityEngineer)) { - this.applyForJob(CompanyPositions.SecurityEngineer); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForNetworkEngineerJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.NetworkEngineer)) { - this.applyForJob(CompanyPositions.NetworkEngineer); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForBusinessJob = function() { - this.applyForJob(CompanyPositions.BusinessIntern); -} - -PlayerObject.prototype.applyForBusinessConsultantJob = function() { - this.applyForJob(CompanyPositions.BusinessConsultant); -} - -PlayerObject.prototype.applyForSecurityJob = function() { - //TODO If case for POlice departments - this.applyForJob(CompanyPositions.SecurityGuard); -} - -PlayerObject.prototype.applyForAgentJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.FieldAgent)) { - this.applyForJob(CompanyPositions.FieldAgent); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForEmployeeJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.Employee)) { - this.companyName = company.companyName; - this.companyPosition = CompanyPositions.Employee; - dialogBoxCreate("Congratulations, you are now employed at " + this.companyName); - Engine.loadLocationContent(); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForPartTimeEmployeeJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.PartTimeEmployee)) { - this.companyName = company.companyName; - this.companyPosition = CompanyPositions.PartTimeEmployee; - dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName); - Engine.loadLocationContent(); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForWaiterJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.Waiter)) { - this.companyName = company.companyName; - this.companyPosition = CompanyPositions.Waiter; - dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName); - Engine.loadLocationContent(); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForPartTimeWaiterJob = function() { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions.PartTimeWaiter)) { - this.companyName = company.companyName; - this.companyPosition = CompanyPositions.PartTimeWaiter; - dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName); - Engine.loadLocationContent(); - } else { - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -//Checks if the Player is qualified for a certain position -PlayerObject.prototype.isQualified = function(company, position) { - var offset = company.jobStatReqOffset; - var reqHacking = position.requiredHacking > 0 ? position.requiredHacking+offset : 0; - var reqStrength = position.requiredStrength > 0 ? position.requiredStrength+offset : 0; - var reqDefense = position.requiredDefense > 0 ? position.requiredDefense+offset : 0; - var reqDexterity = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; - var reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; - var reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma+offset : 0; - - if (this.hacking_skill >= reqHacking && - this.strength >= reqStrength && - this.defense >= reqDefense && - this.dexterity >= reqDexterity && - this.agility >= reqAgility && - this.charisma >= reqCharisma && - company.playerReputation >= position.requiredReputation) { - return true; - } - return false; -} +//TODO probably just move this to whatever file needs it then delete this diff --git a/src/Constants.js b/src/Constants.js index 6d881145c..d78348273 100644 --- a/src/Constants.js +++ b/src/Constants.js @@ -1,5 +1,5 @@ -CONSTANTS = { - Version: "0.27.3", +let CONSTANTS = { + Version: "0.28.1", //Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then @@ -75,8 +75,12 @@ CONSTANTS = { ScriptRoundRamCost: 0.05, ScriptReadWriteRamCost: 1.0, ScriptArbScriptRamCost: 1.0, //Functions that apply to all scripts regardless of args - ScriptGetScriptCost: 0.1, - ScriptGetHackTimeCost: 0.05, + ScriptGetScriptRamCost: 0.1, + ScriptGetHackTimeRamCost: 0.05, + + ScriptSingularityFn1RamCost: 1, + ScriptSingularityFn2RamCost: 2, + ScriptSingularityFn3RamCost: 3, MultithreadingRAMCost: 1, @@ -320,6 +324,9 @@ CONSTANTS = { "numeric - Integers and floats (eg. 6, 10.4999)
" + "string - Encapsulated by single or double quotes (eg. 'this is a string')
" + "boolean - true or false

" + + "Strings are fully functional Javascript strings, " + + "which means that all of the member functions of Javascript strings such as toLowerCase() and includes() are also " + + "available in Netscript!

" + "To create a variable, use the assign (=) operator. The language is not strongly typed. Examples:
" + "i = 5;
" + "s = 'this game is awesome!';

" + @@ -388,7 +395,8 @@ CONSTANTS = { "any server, regardless of where the script is running. This command requires root access to the target server, but " + "there is no required hacking level to run the command. Returns " + "0.1. Works offline at a slower rate
Example: weaken('foodnstuff');

" + - "print(x)
Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command ).

" + + "print(x)
Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command ).

" + + "tprint(x)
Prints a value or a variable to the Terminal

" + "clearLog()
Clears the script's logs.

" + "scan(hostname/ip)
Returns an array containing the hostnames of all servers that are one node away from the specified server. " + "The argument must be a string containing the IP or hostname of the target server. The hostnames in the returned array are strings.

" + @@ -618,6 +626,140 @@ CONSTANTS = { "The code above will use the getServerMoneyAvailable() function to check how much money there is on the 'foodnstuff' server. " + "If there is more than $200,000, then it will try to hack that server. If there is $200,000 or less on the server, " + "then the code will call grow('foodnstuff') instead and add more money to the server.

", + TutorialSingularityFunctionsText: "

Singularity Functions


" + + "The Singularity Functions are a special set of Netscript functions that are unlocked in BitNode-4. " + + "These functions allow you to control many additional aspects of the game through scripts, such as " + + "working for factions/companies, purchasing/installing Augmentations, and creating programs.

" + + "If you are in BitNode-4, then you will automatically have access to all of these functions. " + + "You can use the Singularity Functions in other BitNodes if and only if you have the Source-File " + + "for BitNode-4 (aka Source-File 4). Each level of Source-File 4 will open up additional Singularity " + + "Functions that you can use in other BitNodes. If your Source-File 4 is upgraded all the way to level 3, " + + "then you will be able to access all of the Singularity Functions.

" + + "Note that Singularity Functions require a lot of RAM outside of BitNode-4 (their RAM costs are multiplied by " + + "10 if you are not in BitNode-4).

" + + "universityCourse(universityName, courseName)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start taking a course at a university. If you are already " + + "in the middle of some 'working' action (such as working at a company, for a faction, or on a program), " + + "then running this function will automatically cancel that action and give you your earnings.

" + + "The first argument must be a string with the name of the university. The names are NOT case-sensitive. " + + "Note that you must be in the correct city for whatever university you specify. The three universities are:

" + + "Summit University
Rothman University
ZB Institute of Technology

" + + "The second argument must be a string with the name of the course you are taking. These names are NOT case-sensitive. " + + "The available courses are:

" + + "Study Computer Science
Data Structures
Networks
Algorithms
Management
Leadership

" + + "The cost and experience gains for all of these universities and classes are the same as if you were to manually " + + "visit and take these classes.

" + + "This function will return true if you successfully start taking the course, and false otherwise.

" + + "gymWorkout(gymName, stat)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working out at a gym to train a particular stat. If you are " + + "already in the middle of some 'working' action (such as working at a company, for a faction, or on a program), then " + + "running this function will automatically cancel that action and give you your earnings.

" + + "The first argument must be a string with the name of the gym. The names are NOT case-sensitive. Note that you must " + + "be in the correct city for whatever gym you specify. The available gyms are:

" + + "Crush Fitness Gym
Snap Fitness Gym
Iron Gym
Powerhouse Gym
Millenium Fitness Gym

" + + "The second argument must be a string with the stat you want to work out. These are NOT case-sensitive. " + + "The valid stats are:

strength OR str
defense OR def
dexterity OR dex
agility OR agi

" + + "The cost and experience gains for all of these gyms are the same as if you were to manually visit these gyms and train " + + "This function will return true if you successfully start working out at the gym, and false otherwise.

" + + "travelToCity(cityname)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function allows the player to travel to any city. The cost for using this function is the same as the cost for traveling through the Travel Agency.

" + + "The argument passed into this must be a string with the name of the city to travel to. Note that this argument IS CASE SENSITIVE. The valid cities are:

" + + "Aevum
Chongqing
Sector-12
New Tokyo
Ishima
Volhaven

" + + "This function will return true if you successfully travel to the specified city and false otherwise.

" + + "purchaseTor()
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function allows you to automatically purchase a TOR router. The cost for purchasing a TOR router using this " + + "function is the same as if you were to manually purchase one.

" + + "This function will return true if it successfully purchase a TOR router and false otherwise.

" + + "purchaseProgram(programName)
" + + "If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.

" + + "This function allows you to automatically purchase programs. You MUST have a TOR router in order to use this function.

" + + "The argument passed in must be a string with the name of the program (including the '.exe' extension). This argument is " + + "NOT case-sensitive.

Example: " + + "purchaseProgram('brutessh.exe');

" + + "The cost of purchasing programs using this function is the same as if you were purchasing them through the Dark Web (using " + + "the buy Terminal command).

" + + "This function will return true if the specified program is purchased, and false otherwise.

" + + "upgradeHomeRam()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will upgrade amount of RAM on the player's home computer. The cost is the same as if you were to do it manually.

" + + "This function will return true if the player's home computer RAM is successfully upgraded, and false otherwise.

" + + "getUpgradeHomeRamCost()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "Returns the cost of upgrading the player's home computer RAM.

" + + "workForCompany()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working at the company at which you are employed. If you are already " + + "in the middle of some 'working' action (such as working for a faction, training at a gym, or creating a program), then " + + "running this function will automatically cancel that action and give you your earnings.

" + + "This function will return true if the player starts working, and false otherwise.

" + + "applyToCompany(companyName, field)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically try to apply to the specified company for a position in the specified field. This " + + "function can also be used to apply for promotions by specifying the company and field you are already employed at.

" + + "The first argument must be a string with the name of the company. This argument IS CASE-SENSITIVE. The second argument must " + + "be a string representing the 'field' to which you want to apply. This second argument is NOT case-sensitive. Valid values for " + + "the second argument are:

" + + "software
software consultant
it
security engineer
network engineer
business
business consultant
" + + "security
agent
employee
part-time employee
waiter
part-time waiter

" + + "This function will return true if you successfully get a job/promotion, and false otherwise. Note " + + "that if you are trying to use this function to apply for a promotion and you don't get one, it will return false.

" + + "getCompanyRep(companyName)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will return the amount of reputation you have at the specified company. If the company passed in as " + + "an argument is invalid, -1 will be returned.

" + + "The argument passed in must be a string with the name of the company. This argument IS CASE-SENSITIVE.

" + + "checkFactionInvitations()
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "Returns an array with the name of all Factions you currently have oustanding invitations from.

" + + "joinFaction(name)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically accept an invitation from a faction and join it.

" + + "The argument must be a string with the name of the faction. This name IS CASE-SENSITIVE.

" + + "workForFaction(factionName, workType)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working for the specified Faction. Obviously, you " + + "must be a member of the Faction or else this function will fail. If you are already in the middle of " + + "some 'working' action (such as working for a company, training at a gym, or creating a program), then running " + + "this function will automatically cancel that action and give you your earnings.

" + + "The first argument must be a string with the name of the faction. This argument IS CASE-SENSITIVE. The second argument " + + "must be a string with the type of work you want to perform for the faction. The valid values for this argument are:

" + + "
hacking/hacking contracts/hackingcontracts
field/fieldwork/field work
security/securitywork/security work

" + + "This function will return true if you successfully start working for the specified faction, and false otherwise.

" + + "getFactionRep(factionName)
" + + "If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.

" + + "This function returns the amount of reputation you have for the specified Faction. The argument must be a " + + "string with the name of the Faction. The argument IS CASE-SENSITIVE.

" + + "createProgram(programName)
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function will automatically set you to start working on creating the specified program. If you are already in " + + "the middle of some 'working' action (such as working for a company, training at a gym, or taking a course), then " + + "running this function will automatically cancel that action and give you your earnings.

" + + "The argument passed in must be a string designating the name of the program. This argument is NOT case-sensitive.

" + + "Example:

createProgram('relaysmtp.exe');

" + + "Note that creating a program using this function has the same hacking level requirements as it normally would. These level requirements are:

" + + "BruteSSH.exe: 50
FTPCrack.exe: 100
relaySMTP.exe: 250
HTTPWorm.exe: 500
SQLInject.exe: 750
" + + "DeepscanV1.exe: 75
DeepscanV2.exe: 400
ServerProfiler.exe: 75
AutoLink.exe: 25

" + + "This function returns true if you successfully start working on the specified program, and false otherwise.

" + + "getAugmentationCost(augName)
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function returns an array with two elements that gives the cost for the specified Augmentation" + + ". The first element in the returned array is the reputation requirement of the Augmentation, and the second element " + + "is the money cost.

" + + "The argument passed in must be a string with the name of the Augmentation. This argument IS CASE-SENSITIVE. " + + "If an invalid Augmentation name is passed in, this function will return the array [-1, -1].

" + + "purchaseAugmentation(factionName, augName)
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function will try to purchase the specified Augmentation through the given Faction.

" + + "The two arguments must be strings specifying the name of the Faction and Augmentation, respectively. These arguments are both CASE-SENSITIVE.

" + + "This function will return true if the Augmentation is successfully purchased, and false otherwise.

" + + "installAugmentations()
" + + "If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

" + + "This function will automatically install your Augmentations, resetting the game as usual.

" + + "It will return true if successful, and false otherwise.", TutorialTravelingText:"There are six major cities in the world that you are able to travel to:

" + " Aevum
" + @@ -717,38 +859,14 @@ CONSTANTS = { "World Stock Exchange account and TIX API Access
", LatestUpdate: - "v0.27.3
" + - "-You can now purchase upgrades for Gang Members (BitNode 2 only)
" + - "-Decreased Gang respect gains and slightly increased wanted gains (BitNode 2 only)
" + - "-Other gangs will increase in power faster (BitNode 2 only)
" + - "-Added getHackTime(), getGrowTime(), and getWeakenTime() Netscript functions

" + - "v0.27.2
" + - "-Added getServerGrowth() Netscript function
" + - "-Added getNextHacknetNodeCost() Netscript function
" + - "-Added new 'literature' files (.lit extension) that are used to build lore for the game. " + - "These .lit files can be found in certain servers throughout the game. They can be viewed with the 'cat' Terminal " + - "command and copied over to other servers using the 'scp' command. These .lit files won't be found until you reset " + - "by installing Augmentations
" + - "Fixed some bugs with Gang Territory(BitNode 2 only)

" + - "v0.27.1
" + - "-Changed the way Gang power was calculated to make it scale better late game (BitNode 2 only)
" + - "-Lowered the respect gain rate in Gangs (Bitnode 2 only)
" + - "-Added '| grep pattern' option for ls Terminal command. This allows you to only list files that contain a certain pattern
" + - "-Added break statement in Netscript
" + - "-Display for some numerical values is now done in shorthand (e.g 1.000m instead of 1,000,000)

" + - "v0.27.0
" + - "-Added secondary 'prestige' system - featuring Source Files and BitNodes
" + - "-MILD SPOILERS HERE: Installing 'The Red Pill' Augmentation from Daedalus will unlock a special server called " + - "w0r1d_d43m0n. Finding and manually hacking this server through Terminal will destroy the Player's current BitNode, and allow the player " + - "to enter a new one. When destroying a BitNode, the player loses everything except the scripts on his/her " + - "home computer. The player will then gain a powerful second-tier persistent upgrade called a Source File. The player can then " + - "enter a new BitNode to start the game over. Each BitNode has different characteristics, and many will have new content/mechanics " + - "as well. Right now there are only 2 BitNodes. Each BitNode grants its own unique Source File. Restarting and destroying a BitNode you already " + - "have a Source File for will upgrade your Source File up to a maximum level of 3.

" + - "-Reputation gain with factions and companies is no longer a linear conversion, but an exponential one. It " + - "will be much easier to gain faction favor at first, but much harder later on.
" + - "-Significantly increased Infiltration exp gains
" + - "-Fixed a bug with company job requirement tooltips
" + - "-Added scriptRunning(), scriptKill(), and getScriptRam() Netscript functions. See documentation for details
" + - "-Fixed a bug with deleteServer() Netscript function

" + "v0.28.1
" + + "-The script editor now uses the open-source Ace editor, which provides a much better experience when coding!
" + + "-Added tprint() Netscript function

" + + "v0.28.0
" + + "-Added BitNode-4: The Singularity
" + + "-Added BitNode-11: The Big Crash
" + + "-Migrated the codebase to use webpack (doesn't affect any in game content, except maybe some slight " + + "performance improvements and there may be bugs that result from dependency errors)" } + +export {CONSTANTS}; diff --git a/src/CreateProgram.js b/src/CreateProgram.js index be8ca9e18..a1523ed08 100644 --- a/src/CreateProgram.js +++ b/src/CreateProgram.js @@ -1,17 +1,20 @@ +import {CONSTANTS} from "./Constants.js"; +import {Player} from "./Player.js"; + /* Create programs */ -Programs = { - NukeProgram: "NUKE.exe", - BruteSSHProgram: "BruteSSH.exe", - FTPCrackProgram: "FTPCrack.exe", - RelaySMTPProgram: "relaySMTP.exe", - HTTPWormProgram: "HTTPWorm.exe", - SQLInjectProgram: "SQLInject.exe", - DeepscanV1: "DeepscanV1.exe", - DeepscanV2: "DeepscanV2.exe", - ServerProfiler: "ServerProfiler.exe", - AutoLink: "AutoLink.exe", - Flight: "fl1ght.exe", -} +let Programs = { + NukeProgram: "NUKE.exe", + BruteSSHProgram: "BruteSSH.exe", + FTPCrackProgram: "FTPCrack.exe", + RelaySMTPProgram: "relaySMTP.exe", + HTTPWormProgram: "HTTPWorm.exe", + SQLInjectProgram: "SQLInject.exe", + DeepscanV1: "DeepscanV1.exe", + DeepscanV2: "DeepscanV2.exe", + ServerProfiler: "ServerProfiler.exe", + AutoLink: "AutoLink.exe", + Flight: "fl1ght.exe", +}; //TODO Right now the times needed to complete work are hard-coded... //maybe later make this dependent on hacking level or something @@ -26,9 +29,9 @@ function displayCreateProgramContent() { var deepscanv2ALink = document.getElementById("create-program-deepscanv2"); var servProfilerALink = document.getElementById("create-program-serverprofiler"); var autolinkALink = document.getElementById("create-program-autolink"); - + nukeALink.style.display = "none"; - bruteSshALink.style.display = "none"; + bruteSshALink.style.display = "none"; ftpCrackALink.style.display = "none"; relaySmtpALink.style.display = "none"; httpWormALink.style.display = "none"; @@ -37,15 +40,15 @@ function displayCreateProgramContent() { deepscanv2ALink.style.display = "none"; servProfilerALink.style.display = "none"; autolinkALink.style.display = "none"; - + //NUKE.exe (in case you delete it lol) - if (Player.getHomeComputer().programs.indexOf(Programs.NukeProgram) == -1) { + if (Player.getHomeComputer().programs.indexOf(Programs.NukeProgram) == -1) { nukeALink.style.display = "inline-block"; } //BruteSSH if (Player.getHomeComputer().programs.indexOf(Programs.BruteSSHProgram) == -1 && Player.hacking_skill >= 50) { - bruteSshALink.style.display = "inline-block"; + bruteSshALink.style.display = "inline-block"; } //FTPCrack if (Player.getHomeComputer().programs.indexOf(Programs.FTPCrackProgram) == -1 && @@ -88,7 +91,7 @@ function displayCreateProgramContent() { function getNumAvailableCreateProgram() { var count = 0; //PortHack.exe (in case you delete it lol) - if (Player.getHomeComputer().programs.indexOf(Programs.NukeProgram) == -1) { + if (Player.getHomeComputer().programs.indexOf(Programs.NukeProgram) == -1) { ++count; } //BruteSSH @@ -131,6 +134,7 @@ function getNumAvailableCreateProgram() { if (!Player.hasProgram(Programs.AutoLink) && Player.hacking_skill >= 25) { ++count; } + if (count > 0) {Player.firstProgramAvailable = true;} return count; } @@ -145,7 +149,7 @@ function initCreateProgramButtons() { var deepscanv2ALink = document.getElementById("create-program-deepscanv2"); var servProfilerALink = document.getElementById("create-program-serverprofiler"); var autolinkALink = document.getElementById("create-program-autolink"); - + nukeALink.addEventListener("click", function() { Player.startCreateProgramWork(Programs.NukeProgram, CONSTANTS.MillisecondsPerFiveMinutes, 1); return false; @@ -185,5 +189,8 @@ function initCreateProgramButtons() { autolinkALink.addEventListener("click", function() { Player.startCreateProgramWork(Programs.AutoLink, CONSTANTS.MillisecondsPerQuarterHour, 25); return false; - }); -} \ No newline at end of file + }); +} + +export {Programs, displayCreateProgramContent, getNumAvailableCreateProgram, + initCreateProgramButtons}; diff --git a/src/Crimes.js b/src/Crimes.js index 78a4faf7e..77c0b3f8b 100644 --- a/src/Crimes.js +++ b/src/Crimes.js @@ -1,3 +1,7 @@ +import {CONSTANTS} from "./Constants.js"; +import {Player} from "./Player.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; + /* Crimes.js */ function commitShopliftCrime() { Player.crimeType = CONSTANTS.CrimeShoplift; @@ -202,3 +206,14 @@ function determineCrimeChanceHeist() { chance *= Player.crime_success_mult; return Math.min(chance, 1); } + +export {commitShopliftCrime, commitRobStoreCrime, commitMugCrime, + commitLarcenyCrime, commitDealDrugsCrime, commitTraffickArmsCrime, + commitHomicideCrime, commitGrandTheftAutoCrime, commitKidnapCrime, + commitAssassinationCrime, commitHeistCrime, determineCrimeSuccess, + determineCrimeChanceShoplift, determineCrimeChanceRobStore, + determineCrimeChanceMug, determineCrimeChanceLarceny, + determineCrimeChanceDealDrugs, determineCrimeChanceTraffickArms, + determineCrimeChanceHomicide, determineCrimeChanceGrandTheftAuto, + determineCrimeChanceKidnap, determineCrimeChanceAssassination, + determineCrimeChanceHeist}; diff --git a/src/DarkWeb.js b/src/DarkWeb.js index 09403e071..197088f9b 100644 --- a/src/DarkWeb.js +++ b/src/DarkWeb.js @@ -1,6 +1,14 @@ +import {Programs} from "./CreateProgram.js"; +import {Player} from "./Player.js"; +import {SpecialServerIps} from "./SpecialServerIps.js"; +import {post} from "./Terminal.js"; + +import {formatNumber} from "../utils/StringHelperFunctions.js"; + + /* DarkWeb.js */ //Posts a "help" message if connected to DarkWeb -checkIfConnectedToDarkweb = function() { +function checkIfConnectedToDarkweb() { if (SpecialServerIps.hasOwnProperty("Darkweb Server")) { var darkwebIp = SpecialServerIps["Darkweb Server"]; if (!isValidIPAddress(darkwebIp)) {return;} @@ -16,7 +24,7 @@ checkIfConnectedToDarkweb = function() { //Handler for dark web commands. The terminal's executeCommand() function will pass //dark web-specific commands into this. It will pass in the raw split command array //rather than the command string -executeDarkwebTerminalCommand = function(commandArray) { +function executeDarkwebTerminalCommand(commandArray) { if (commandArray.length == 0) {return;} switch (commandArray[0]) { case "buy": @@ -24,6 +32,7 @@ executeDarkwebTerminalCommand = function(commandArray) { post("Incorrect number of arguments. Usage: "); post("buy -l"); post("buy [item name]"); + return; } var arg = commandArray[1]; if (arg == "-l") { @@ -38,7 +47,7 @@ executeDarkwebTerminalCommand = function(commandArray) { } } -listAllDarkwebItems = function() { +function listAllDarkwebItems() { for (var item in DarkWebItems) { if (DarkWebItems.hasOwnProperty(item)) { var item = DarkWebItems[item]; @@ -76,7 +85,7 @@ listAllDarkwebItems = function() { else {return price;} } -buyDarkwebItem = function(itemName) { +function buyDarkwebItem(itemName) { if (itemName.toLowerCase() == Programs.BruteSSHProgram.toLowerCase()) { var price = parseDarkwebItemPrice(DarkWebItems.BruteSSHProgram); if (price > 0 && Player.money.gt(price)) { @@ -152,7 +161,7 @@ buyDarkwebItem = function(itemName) { } } -parseDarkwebItemPrice = function(itemDesc) { +function parseDarkwebItemPrice(itemDesc) { var split = itemDesc.split(" - "); if (split.length == 3) { var priceString = split[1]; @@ -173,12 +182,16 @@ parseDarkwebItemPrice = function(itemDesc) { } } -DarkWebItems = { - BruteSSHProgram: Programs.BruteSSHProgram + " - $500,000 - Opens up SSH Ports", - FTPCrackProgram: Programs.FTPCrackProgram + " - $1,500,000 - Opens up FTP Ports", - RelaySMTPProgram: Programs.RelaySMTPProgram + " - $5,000,000 - Opens up SMTP Ports", - HTTPWormProgram: Programs.HTTPWormProgram + " - $30,000,000 - Opens up HTTP Ports", - SQLInjectProgram: Programs.SQLInjectProgram + " - $250,000,000 - Opens up SQL Ports", - DeepScanV1Program: Programs.DeepscanV1 + " - $500,000 - Enables 'scan-analyze' with a depth up to 5", - DeepScanV2Program: Programs.DeepscanV2 + " - $25,000,000 - Enables 'scan-analyze' with a depth up to 10", +let DarkWebItems = { + BruteSSHProgram: "BruteSSH.exe - $500,000 - Opens up SSH Ports", + FTPCrackProgram: "FTPCrack.exe - $1,500,000 - Opens up FTP Ports", + RelaySMTPProgram: "relaySMTP.exe - $5,000,000 - Opens up SMTP Ports", + HTTPWormProgram: "HTTPWorm.exe - $30,000,000 - Opens up HTTP Ports", + SQLInjectProgram: "SQLInject.exe - $250,000,000 - Opens up SQL Ports", + DeepScanV1Program: "DeepscanV1.exe - $500,000 - Enables 'scan-analyze' with a depth up to 5", + DeepScanV2Program: "DeepscanV2.exe - $25,000,000 - Enables 'scan-analyze' with a depth up to 10", } + +export {checkIfConnectedToDarkweb, executeDarkwebTerminalCommand, + listAllDarkwebItems, buyDarkwebItem, parseDarkwebItemPrice, + DarkWebItems}; diff --git a/src/Faction.js b/src/Faction.js index dcc60ed43..3708b31b4 100644 --- a/src/Faction.js +++ b/src/Faction.js @@ -1,3 +1,23 @@ +import {Augmentations, AugmentationNames, + PlayerOwnedAugmentation} from "./Augmentations.js"; +import {BitNodeMultipliers} from "./BitNode.js"; +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {FactionInfo} from "./FactionInfo.js"; +import {Locations} from "./Location.js"; +import {Player} from "./Player.js"; +import {Settings} from "./Settings.js"; + +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {factionInvitationBoxCreate} from "../utils/FactionInvitationBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {formatNumber, isPositiveNumber} from "../utils/StringHelperFunctions.js"; +import {yesNoBoxCreate, yesNoBoxGetYesButton, + yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js"; + + //Netburner Faction class function factionInit() { $('#faction-donate-input').on('input', function() { @@ -97,9 +117,13 @@ Faction.fromJSON = function(value) { Reviver.constructors.Faction = Faction; //Map of factions indexed by faction name -Factions = {} +let Factions = {} -AddToFactions = function(faction) { +function loadFactions(saveString) { + Factions = JSON.parse(saveString, Reviver); +} + +function AddToFactions(faction) { var name = faction.name; Factions[name] = faction; } @@ -110,7 +134,7 @@ function factionExists(name) { //TODO Augmentation price and rep requirement mult are 1 for everything right now, // This might change in the future for balance -initFactions = function() { +function initFactions() { //Endgame var Illuminati = new Faction("Illuminati"); Illuminati.setInfo(FactionInfo.IlluminatiInfo); @@ -368,304 +392,7 @@ initFactions = function() { AddToFactions(CyberSec); } -//This function sets the requirements to join a Faction. It checks whether the Player meets -//those requirements and will return an array of all factions that the Player should -//receive an invitation to -PlayerObject.prototype.checkForFactionInvitations = function() { - invitedFactions = []; //Array which will hold all Factions th eplayer should be invited to - - var numAugmentations = this.augmentations.length; - - var company = Companies[this.companyName]; - var companyRep = 0; - if (company != null) { - companyRep = company.playerReputation; - } - - //Illuminati - var illuminatiFac = Factions["Illuminati"]; - if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited && - numAugmentations >= 30 && - this.money.gte(150000000000) && - this.hacking_skill >= 1500 && - this.strength >= 1200 && this.defense >= 1200 && - this.dexterity >= 1200 && this.agility >= 1200) { - invitedFactions.push(illuminatiFac); - } - - //Daedalus - var daedalusFac = Factions["Daedalus"]; - if (!daedalusFac.isBanned && !daedalusFac.isMember && !daedalusFac.alreadyInvited && - numAugmentations >= 30 && - this.money.gte(100000000000) && - (this.hacking_skill >= 2500 || - (this.strength >= 1500 && this.defense >= 1500 && - this.dexterity >= 1500 && this.agility >= 1500))) { - invitedFactions.push(daedalusFac); - } - - //The Covenant - var covenantFac = Factions["The Covenant"]; - if (!covenantFac.isBanned && !covenantFac.isMember && !covenantFac.alreadyInvited && - numAugmentations >= 30 && - this.money.gte(75000000000) && - this.hacking_skill >= 850 && - this.strength >= 850 && - this.defense >= 850 && - this.dexterity >= 850 && - this.agility >= 850) { - invitedFactions.push(covenantFac); - } - - //ECorp - var ecorpFac = Factions["ECorp"]; - if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited && - this.companyName == Locations.AevumECorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(ecorpFac); - } - - //MegaCorp - var megacorpFac = Factions["MegaCorp"]; - if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited && - this.companyName == Locations.Sector12MegaCorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(megacorpFac); - } - - //Bachman & Associates - var bachmanandassociatesFac = Factions["Bachman & Associates"]; - if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember && - !bachmanandassociatesFac.alreadyInvited && - this.companyName == Locations.AevumBachmanAndAssociates && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(bachmanandassociatesFac); - } - - //Blade Industries - var bladeindustriesFac = Factions["Blade Industries"]; - if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited && - this.companyName == Locations.Sector12BladeIndustries && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(bladeindustriesFac); - } - - //NWO - var nwoFac = Factions["NWO"]; - if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && - this.companyName == Locations.VolhavenNWO && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(nwoFac); - } - - //Clarke Incorporated - var clarkeincorporatedFac = Factions["Clarke Incorporated"]; - if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited && - this.companyName == Locations.AevumClarkeIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(clarkeincorporatedFac); - } - - //OmniTek Incorporated - var omnitekincorporatedFac = Factions["OmniTek Incorporated"]; - if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited && - this.companyName == Locations.VolhavenOmniTekIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(omnitekincorporatedFac); - } - - //Four Sigma - var foursigmaFac = Factions["Four Sigma"]; - if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited && - this.companyName == Locations.Sector12FourSigma && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(foursigmaFac); - } - - //KuaiGong International - var kuaigonginternationalFac = Factions["KuaiGong International"]; - if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember && - !kuaigonginternationalFac.alreadyInvited && - this.companyName == Locations.ChongqingKuaiGongInternational && companyRep >= CONSTANTS.CorpFactionRepRequirement) { - invitedFactions.push(kuaigonginternationalFac); - } - - //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company - var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"]; - var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]]; - if (fulcrumSecretServer == null) { - console.log("ERROR: Could not find Fulcrum Secret Technologies Server"); - } else { - if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && - !fulcrumsecrettechonologiesFac.alreadyInvited && - fulcrumSecretServer.manuallyHacked && - this.companyName == Locations.AevumFulcrumTechnologies && companyRep >= 250000) { - invitedFactions.push(fulcrumsecrettechonologiesFac); - } - } - - //BitRunners - var bitrunnersFac = Factions["BitRunners"]; - var homeComp = this.getHomeComputer(); - var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]]; - if (bitrunnersServer == null) { - console.log("ERROR: Could not find BitRunners Server"); - } else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked && - !bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) { - invitedFactions.push(bitrunnersFac); - } - - //The Black Hand - var theblackhandFac = Factions["The Black Hand"]; - var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]]; - if (blackhandServer == null) { - console.log("ERROR: Could not find The Black Hand Server"); - } else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked && - !theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) { - invitedFactions.push(theblackhandFac); - } - - //NiteSec - var nitesecFac = Factions["NiteSec"]; - var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]]; - if (nitesecServer == null) { - console.log("ERROR: Could not find NiteSec Server"); - } else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked && - !nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) { - invitedFactions.push(nitesecFac); - } - - //Chongqing - var chongqingFac = Factions["Chongqing"]; - if (!chongqingFac.isBanned && !chongqingFac.isMember && !chongqingFac.alreadyInvited && - this.money.gte(20000000) && this.city == Locations.Chongqing) { - invitedFactions.push(chongqingFac); - } - - //Sector-12 - var sector12Fac = Factions["Sector-12"]; - if (!sector12Fac.isBanned && !sector12Fac.isMember && !sector12Fac.alreadyInvited && - this.money.gte(15000000) && this.city == Locations.Sector12) { - invitedFactions.push(sector12Fac); - } - - //New Tokyo - var newtokyoFac = Factions["New Tokyo"]; - if (!newtokyoFac.isBanned && !newtokyoFac.isMember && !newtokyoFac.alreadyInvited && - this.money.gte(20000000) && this.city == Locations.NewTokyo) { - invitedFactions.push(newtokyoFac); - } - - //Aevum - var aevumFac = Factions["Aevum"]; - if (!aevumFac.isBanned && !aevumFac.isMember && !aevumFac.alreadyInvited && - this.money.gte(40000000) && this.city == Locations.Aevum) { - invitedFactions.push(aevumFac); - } - - //Ishima - var ishimaFac = Factions["Ishima"]; - if (!ishimaFac.isBanned && !ishimaFac.isMember && !ishimaFac.alreadyInvited && - this.money.gte(30000000) && this.city == Locations.Ishima) { - invitedFactions.push(ishimaFac); - } - - //Volhaven - var volhavenFac = Factions["Volhaven"]; - if (!volhavenFac.isBanned && !volhavenFac.isMember && !volhavenFac.alreadyInvited && - this.money.gte(50000000) && this.city == Locations.Volhaven) { - invitedFactions.push(volhavenFac); - } - - //Speakers for the Dead - var speakersforthedeadFac = Factions["Speakers for the Dead"]; - if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited && - this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 && - this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 && - this.karma <= -45 && this.companyName != Locations.Sector12CIA && - this.companyName != Locations.Sector12NSA) { - invitedFactions.push(speakersforthedeadFac); - } - - //The Dark Army - var thedarkarmyFac = Factions["The Dark Army"]; - if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited && - this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 && - this.dexterity >= 300 && this.agility >= 300 && this.city == Locations.Chongqing && - this.numPeopleKilled >= 5 && this.karma <= -45 && this.companyName != Locations.Sector12CIA && - this.companyName != Locations.Sector12NSA) { - invitedFactions.push(thedarkarmyFac); - } - - //The Syndicate - var thesyndicateFac = Factions["The Syndicate"]; - if (!thesyndicateFac.isBanned && !thesyndicateFac.isMember && !thesyndicateFac.alreadyInvited && - this.hacking_skill >= 200 && this.strength >= 200 && this.defense >= 200 && - this.dexterity >= 200 && this.agility >= 200 && - (this.city == Locations.Aevum || this.city == Locations.Sector12) && - this.money.gte(10000000) && this.karma <= -90 && - this.companyName != Locations.Sector12CIA && this.companyName != Locations.Sector12NSA) { - invitedFactions.push(thesyndicateFac); - } - - //Silhouette - var silhouetteFac = Factions["Silhouette"]; - if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited && - (this.companyPosition.positionName == CompanyPositions.CTO.positionName || - this.companyPosition.positionName == CompanyPositions.CFO.positionName || - this.companyPosition.positionName == CompanyPositions.CEO.positionName) && - this.money.gte(15000000) && this.karma <= -22) { - invitedFactions.push(silhouetteFac); - } - - //Tetrads - var tetradsFac = Factions["Tetrads"]; - if (!tetradsFac.isBanned && !tetradsFac.isMember && !tetradsFac.alreadyInvited && - (this.city == Locations.Chongqing || this.city == Locations.NewTokyo || - this.city == Locations.Ishima) && this.strength >= 75 && this.defense >= 75 && - this.dexterity >= 75 && this.agility >= 75 && this.karma <= -18) { - invitedFactions.push(tetradsFac); - } - - //SlumSnakes - var slumsnakesFac = Factions["Slum Snakes"]; - if (!slumsnakesFac.isBanned && !slumsnakesFac.isMember && !slumsnakesFac.alreadyInvited && - this.strength >= 30 && this.defense >= 30 && this.dexterity >= 30 && - this.agility >= 30 && this.karma <= -9 && this.money.gte(1000000)) { - invitedFactions.push(slumsnakesFac); - } - - //Netburners - var netburnersFac = Factions["Netburners"]; - var totalHacknetRam = 0; - var totalHacknetCores = 0; - var totalHacknetLevels = 0; - for (var i = 0; i < Player.hacknetNodes.length; ++i) { - totalHacknetLevels += Player.hacknetNodes[i].level; - totalHacknetRam += Player.hacknetNodes[i].ram; - totalHacknetCores += Player.hacknetNodes[i].cores; - } - if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited && - this.hacking_skill >= 80 && totalHacknetRam >= 8 && - totalHacknetCores >= 4 && totalHacknetLevels >= 100) { - invitedFactions.push(netburnersFac); - } - - //Tian Di Hui - var tiandihuiFac = Factions["Tian Di Hui"]; - if (!tiandihuiFac.isBanned && !tiandihuiFac.isMember && !tiandihuiFac.alreadyInvited && - this.money.gte(1000000) && this.hacking_skill >= 50 && - (this.city == Locations.Chongqing || this.city == Locations.NewTokyo || - this.city == Locations.Ishima)) { - invitedFactions.push(tiandihuiFac); - } - - //CyberSec - var cybersecFac = Factions["CyberSec"]; - var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]]; - if (cybersecServer == null) { - console.log("ERROR: Could not find CyberSec Server"); - } else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked && - !cybersecFac.alreadyInvited && this.hacking_skill >= 50) { - invitedFactions.push(cybersecFac); - } - - return invitedFactions; -} - -inviteToFaction = function(faction) { +function inviteToFaction(faction) { if (Settings.SuppressFactionInvites) { faction.alreadyInvited = true; Player.factionInvitations.push(faction.name); @@ -674,7 +401,7 @@ inviteToFaction = function(faction) { } } -joinFaction = function(faction) { +function joinFaction(faction) { faction.isMember = true; Player.factions.push(faction.name); @@ -710,47 +437,8 @@ joinFaction = function(faction) { } } -leaveFaction = function(faction) { - faction.isMember = false; - var i = Player.factions.indexOf(faction.name); - if (i > -1) { - Player.factions.splice(i, 1); - } - - //Unban from faction - if (faction.name == "Chongqing") { - Factions["Sector-12"].isBanned = false; - Factions["Aevum"].isBanned = false; - Factions["Volhaven"].isBanned = false; - } else if (faction.name == "Sector-12") { - Factions["Chongqing"].isBanned = false; - Factions["New Tokyo"].isBanned = false; - Factions["Ishima"].isBanned = false; - Factions["Volhaven"].isBanned = false; - } else if (faction.name == "New Tokyo") { - Factions["Sector-12"].isBanned = false; - Factions["Aevum"].isBanned = false; - Factions["Volhaven"].isBanned = false; - } else if (faction.name == "Aevum") { - Factions["Chongqing"].isBanned = false; - Factions["New Tokyo"].isBanned = false; - Factions["Ishima"].isBanned = false; - Factions["Volhaven"].isBanned = false; - } else if (faction.name == "Ishima") { - Factions["Sector-12"].isBanned = false; - Factions["Aevum"].isBanned = false; - Factions["Volhaven"].isBanned = false; - } else if (faction.name == "Volhaven") { - Factions["Chongqing"].isBanned = false; - Factions["Sector-12"].isBanned = false; - Factions["New Tokyo"].isBanned = false; - Factions["Aevum"].isBanned = false; - Factions["Ishima"].isBanned = false; - } -} - //Displays the HTML content for a specific faction -displayFactionContent = function(factionName) { +function displayFactionContent(factionName) { var faction = Factions[factionName]; document.getElementById("faction-name").innerHTML = factionName; document.getElementById("faction-info").innerHTML = "" + faction.info + ""; @@ -882,8 +570,8 @@ displayFactionContent = function(factionName) { noBtn.innerHTML = "Cancel"; yesBtn.addEventListener("click", () => { var hacking = false; - if (factionName == "NiteSec" || factionName == "The Black Hand") {hacking = true;} - Player.gang = new Gang(factionName, hacking); + if (factionName === "NiteSec" || factionName === "The Black Hand") {hacking = true;} + Player.startGang(factionName, hacking); Engine.loadGangContent(); yesNoBoxClose(); }); @@ -1077,7 +765,7 @@ displayFactionContent = function(factionName) { } } -displayFactionAugmentations = function(factionName) { +function displayFactionAugmentations(factionName) { document.getElementById("faction-augmentations-page-desc").innerHTML = "Lists all augmentations that are available to purchase from " + factionName; var faction = Factions[factionName]; @@ -1150,87 +838,12 @@ displayFactionAugmentations = function(factionName) { } } -purchaseAugmentationBoxCreate = function(aug, fac) { +function purchaseAugmentationBoxCreate(aug, fac) { var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel"; yesBtn.addEventListener("click", function() { - //TODO Requirements for specific augmentations (e.g Embedded Netburner Module b4 its upgrades) - if (aug.name == AugmentationNames.Targeting2 && - Augmentations[AugmentationNames.Targeting1].owned == false) { - dialogBoxCreate("You must first install Augmented Targeting I before you can upgrade it to Augmented Targeting II"); - } else if (aug.name == AugmentationNames.Targeting3 && - Augmentations[AugmentationNames.Targeting2].owned == false) { - dialogBoxCreate("You must first install Augmented Targeting II before you can upgrade it to Augmented Targeting III"); - } else if (aug.name == AugmentationNames.CombatRib2 && - Augmentations[AugmentationNames.CombatRib1].owned == false) { - dialogBoxCreate("You must first install Combat Rib I before you can upgrade it to Combat Rib II"); - } else if (aug.name == AugmentationNames.CombatRib3 && - Augmentations[AugmentationNames.CombatRib2].owned == false) { - dialogBoxCreate("You must first install Combat Rib II before you can upgrade it to Combat Rib III"); - } else if (aug.name == AugmentationNames.GrapheneBionicSpine && - Augmentations[AugmentationNames.BionicSpine].owned == false) { - dialogBoxCreate("You must first install a Bionic Spine before you can upgrade it to a Graphene Bionic Spine"); - } else if (aug.name == AugmentationNames.GrapheneBionicLegs && - Augmentations[AugmentationNames.BionicLegs].owned == false) { - dialogBoxCreate("You must first install Bionic Legs before you can upgrade it to Graphene Bionic Legs"); - } else if (aug.name == AugmentationNames.ENMCoreV2 && - Augmentations[AugmentationNames.ENMCore].owned == false) { - dialogBoxCreate("You must first install Embedded Netburner Module Core Implant before you can upgrade it to V2"); - } else if (aug.name == AugmentationNames.ENMCoreV3 && - Augmentations[AugmentationNames.ENMCoreV2].owned == false) { - dialogBoxCreate("You must first install Embedded Netburner Module Core V2 Upgrade before you can upgrade it to V3"); - } else if ((aug.name == AugmentationNames.ENMCore || - aug.name == AugmentationNames.ENMAnalyzeEngine || - aug.name == AugmentationNames.ENMDMA) && - Augmentations[AugmentationNames.ENM].owned == false) { - dialogBoxCreate("You must first install the Embedded Netburner Module before installing any upgrades to it"); - } else if ((aug.name == AugmentationNames.PCDNIOptimizer || - aug.name == AugmentationNames.PCDNINeuralNetwork) && - Augmentations[AugmentationNames.PCDNI].owned == false) { - dialogBoxCreate("You must first install the Pc Direct-Neural Interface before installing this upgrade"); - } else if (aug.name == AugmentationNames.GrapheneBrachiBlades && - Augmentations[AugmentationNames.BrachiBlades].owned == false) { - dialogBoxCreate("You must first install the Brachi Blades augmentation before installing this upgrade"); - } else if (aug.name == AugmentationNames.GrapheneBionicArms && - Augmentations[AugmentationNames.BionicArms].owned == false) { - dialogBoxCreate("You must first install the Bionic Arms augmentation before installing this upgrade"); - } else if (Player.money.gte(aug.baseCost * fac.augmentationPriceMult)) { - var queuedAugmentation = new PlayerOwnedAugmentation(aug.name); - if (aug.name == AugmentationNames.NeuroFluxGovernor) { - queuedAugmentation.level = getNextNeurofluxLevel(); - } - Player.queuedAugmentations.push(queuedAugmentation); - - Player.loseMoney((aug.baseCost * fac.augmentationPriceMult)); - dialogBoxCreate("You purchased " + aug.name + ". It's enhancements will not take " + - "effect until they are installed. To install your augmentations, go to the " + - "'Augmentations' tab on the left-hand navigation menu. Purchasing additional " + - "augmentations will now be more expensive."); - - //If you just purchased Neuroflux Governor, recalculate the cost - if (aug.name == AugmentationNames.NeuroFluxGovernor) { - var nextLevel = getNextNeurofluxLevel(); - --nextLevel; - var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel); - aug.setRequirements(500 * mult, 750000 * mult); - - for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) { - aug.baseCost *= CONSTANTS.MultipleAugMultiplier; - } - } - - for (var name in Augmentations) { - if (Augmentations.hasOwnProperty(name)) { - Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier; - } - } - - displayFactionAugmentations(fac.name); - } else { - dialogBoxCreate("You don't have enough money to purchase this Augmentation!"); - } - yesNoBoxClose(); + purchaseAugmentation(aug, fac); }); noBtn.addEventListener("click", function() { yesNoBoxClose(); @@ -1242,6 +855,107 @@ purchaseAugmentationBoxCreate = function(aug, fac) { formatNumber(aug.baseCost * fac.augmentationPriceMult, 2) + "?"); } +function purchaseAugmentation(aug, fac, sing=false) { + if (aug.name == AugmentationNames.Targeting2 && + Augmentations[AugmentationNames.Targeting1].owned == false) { + var txt = "You must first install Augmented Targeting I before you can upgrade it to Augmented Targeting II"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.Targeting3 && + Augmentations[AugmentationNames.Targeting2].owned == false) { + var txt = "You must first install Augmented Targeting II before you can upgrade it to Augmented Targeting III"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.CombatRib2 && + Augmentations[AugmentationNames.CombatRib1].owned == false) { + var txt = "You must first install Combat Rib I before you can upgrade it to Combat Rib II"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.CombatRib3 && + Augmentations[AugmentationNames.CombatRib2].owned == false) { + var txt = "You must first install Combat Rib II before you can upgrade it to Combat Rib III"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.GrapheneBionicSpine && + Augmentations[AugmentationNames.BionicSpine].owned == false) { + var txt = "You must first install a Bionic Spine before you can upgrade it to a Graphene Bionic Spine"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.GrapheneBionicLegs && + Augmentations[AugmentationNames.BionicLegs].owned == false) { + var txt = "You must first install Bionic Legs before you can upgrade it to Graphene Bionic Legs"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.ENMCoreV2 && + Augmentations[AugmentationNames.ENMCore].owned == false) { + var txt = "You must first install Embedded Netburner Module Core Implant before you can upgrade it to V2"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.ENMCoreV3 && + Augmentations[AugmentationNames.ENMCoreV2].owned == false) { + var txt = "You must first install Embedded Netburner Module Core V2 Upgrade before you can upgrade it to V3"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if ((aug.name == AugmentationNames.ENMCore || + aug.name == AugmentationNames.ENMAnalyzeEngine || + aug.name == AugmentationNames.ENMDMA) && + Augmentations[AugmentationNames.ENM].owned == false) { + var txt = "You must first install the Embedded Netburner Module before installing any upgrades to it"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if ((aug.name == AugmentationNames.PCDNIOptimizer || + aug.name == AugmentationNames.PCDNINeuralNetwork) && + Augmentations[AugmentationNames.PCDNI].owned == false) { + var txt = "You must first install the Pc Direct-Neural Interface before installing this upgrade"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.GrapheneBrachiBlades && + Augmentations[AugmentationNames.BrachiBlades].owned == false) { + var txt = "You must first install the Brachi Blades augmentation before installing this upgrade"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (aug.name == AugmentationNames.GrapheneBionicArms && + Augmentations[AugmentationNames.BionicArms].owned == false) { + var txt = "You must first install the Bionic Arms augmentation before installing this upgrade"; + if (sing) {return txt;} else {dialogBoxCreate(txt);} + } else if (Player.money.gte(aug.baseCost * fac.augmentationPriceMult)) { + Player.firstAugPurchased = true; + + var queuedAugmentation = new PlayerOwnedAugmentation(aug.name); + if (aug.name == AugmentationNames.NeuroFluxGovernor) { + queuedAugmentation.level = getNextNeurofluxLevel(); + } + Player.queuedAugmentations.push(queuedAugmentation); + + Player.loseMoney((aug.baseCost * fac.augmentationPriceMult)); + + //If you just purchased Neuroflux Governor, recalculate the cost + if (aug.name == AugmentationNames.NeuroFluxGovernor) { + var nextLevel = getNextNeurofluxLevel(); + --nextLevel; + var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel); + aug.setRequirements(500 * mult, 750000 * mult); + + for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) { + aug.baseCost *= CONSTANTS.MultipleAugMultiplier; + } + } + + for (var name in Augmentations) { + if (Augmentations.hasOwnProperty(name)) { + Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier; + } + } + + if (sing) { + return "You purchased " + aug.name; + } else { + dialogBoxCreate("You purchased " + aug.name + ". It's enhancements will not take " + + "effect until they are installed. To install your augmentations, go to the " + + "'Augmentations' tab on the left-hand navigation menu. Purchasing additional " + + "augmentations will now be more expensive."); + } + + displayFactionAugmentations(fac.name); + } else { + if (sing) { + return "You don't have enough money to purchase " + aug.name; + } else { + dialogBoxCreate("You don't have enough money to purchase this Augmentation!"); + } + } + yesNoBoxClose(); +} + function getNextNeurofluxLevel() { var aug = Augmentations[AugmentationNames.NeuroFluxGovernor]; if (aug == null) { @@ -1277,3 +991,7 @@ function processPassiveFactionRepGain(numCycles) { } } } + +export {getNextNeurofluxLevel, Factions, initFactions, inviteToFaction, + joinFaction, displayFactionContent, processPassiveFactionRepGain, + loadFactions, Faction, purchaseAugmentation, factionExists}; diff --git a/src/FactionInfo.js b/src/FactionInfo.js index 7fcdd921d..fd8b55413 100644 --- a/src/FactionInfo.js +++ b/src/FactionInfo.js @@ -1,45 +1,45 @@ //Contains the "information" property for all the Factions, which is just a description //of each faction -FactionInfo = { +let FactionInfo = { //Endgame - IlluminatiInfo: "Humanity never changes. No matter how civilized society becomes, it will eventually fall back " + + IlluminatiInfo: "Humanity never changes. No matter how civilized society becomes, it will eventually fall back " + "into chaos. And from this chaos, we are the Invisible hand that guides them to order. ", - + DaedalusInfo: "Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.", - + CovenantInfo: "Surrender yourself. Give up your empty individuality to become part of something great, something eternal. " + - "Become a slave. Submit your mind, body, and soul. Only then can you set yourself free.

" + + "Become a slave. Submit your mind, body, and soul. Only then can you set yourself free.

" + "Only then can you discover immortality.", - + //Megacorporations, each forms its own faction - ECorpInfo: "ECorp's mission is simple: to connect the world of today with the technology of tomorrow. " + - "With our wide range of Internet-related software and commercial hardware, ECorp makes the world's " + + ECorpInfo: "ECorp's mission is simple: to connect the world of today with the technology of tomorrow. " + + "With our wide range of Internet-related software and commercial hardware, ECorp makes the world's " + "information universally accessible.", - + MegaCorpInfo: "MegaCorp does things that others don't. We imagine. We create. We invent. We build things that " + "others have never even dreamed of. Our work fills the world's needs for food, water, power, and " + - "transporation on an unprecendented scale, in ways that no other company can.

" + + "transporation on an unprecendented scale, in ways that no other company can.

" + "In our labs and factories and on the ground with customers, MegaCorp is ushering in a new era for the world.", - - BachmanAndAssociatesInfo: "Where Law and Business meet - thats where we are.

" + + + BachmanAndAssociatesInfo: "Where Law and Business meet - thats where we are.

" + "Legal Insight - Business Instinct - Experience Innovation", - + BladeIndustriesInfo: "Augmentation is salvation", - + NWOInfo: "The human being created civilization not because of willingness but of a need to be assimilated into higher orders of structure and meaning.", - + ClarkeIncorporatedInfo: "Unlocking the power of the genome", - + OmniTekIncorporatedInfo: "Simply put, our mission is to design and build robots that make a difference", - - FourSigmaInfo: "The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by " + + + FourSigmaInfo: "The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by " + "deep learning and innovative ideas. And improved by iteration. That's Four Sigma.", - + KuaiGongInternationalInfo: "Dream big. Work hard. Make history.", - + //Other Corporations FulcrumSecretTechnologiesInfo: "TODO", - + //Hacker groups BitRunnersInfo: "Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. "+ "It's all transformed into bits, stored in bits, communicated through bits. It’s impossible for any person " + @@ -47,14 +47,14 @@ FactionInfo = { "And when a person moves, lives, and operates, they leave behind their bits, mere traces of seemingly " + "meaningless fragments of information. But these bits can be reconstructed. Transformed. Used.

" + "Those who run the bits, run the world", - - - BlackHandInfo: "The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power. " + - "Technological power. " + + + + BlackHandInfo: "The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power. " + + "Technological power. " + "And those at the top rule with an invisible hand. They built a society where the rich get richer, " + "and everyone else suffers.

" + - "So much pain. So many lives. Their darkness must end.", - + "So much pain. So many lives. Their darkness must end.", + NiteSecInfo: " __..__
" + " _.nITESECNIt.
" + @@ -91,7 +91,7 @@ FactionInfo = { " d .dNITESEC $ |
" + " :bp.__.gNITESEC$$ :$ ;
" + " NITESECNITESECNIT $$b :
", - + //City factions, essentially governments ChongqingInfo: "Serve the people", Sector12Info: "The City of the Future", @@ -99,32 +99,34 @@ FactionInfo = { AevumInfo: "The Silicon City", IshimaInfo: "The East Asian Order of the Future", VolhavenInfo: "Benefit, Honour, and Glory", - + //Criminal Organizations/Gangs SpeakersForTheDeadInfo: "It is better to reign in hell than to serve in heaven.", - + DarkArmyInfo: "The World doesn't care about right or wrong. It's all about power.", - + TheSyndicateInfo: "Honor holds you back", - - SilhouetteInfo: "Corporations have filled the void of power left behind by the collapse of Western government. The issue is they've become so big " + + + SilhouetteInfo: "Corporations have filled the void of power left behind by the collapse of Western government. The issue is they've become so big " + "that you don't know who they're working for. And if you're employed at one of these corporations, you don't even know who you're working " + - "for.

" + + "for.

" + "That's terror. Terror, fear, and corruption. All born into the system, all propagated by the system.", - + TetradsInfo: "Following the Mandate of Heaven and Carrying out the Way", - + SlumSnakesInfo: "Slum Snakes rule!", - + //Earlygame factions - factions the player will prestige with early on that don't //belong in other categories NetburnersInfo: "~~//*>H4CK|\|3T 8URN3R5**>?>\\~~", - + TianDiHuiInfo: "Obey Heaven and Work Righteousness", - + CyberSecInfo: "The Internet is the first thing that humanity has built that humanity doesn’t understand, " + - "the largest experiment in anarchy that we have ever had. And as the world becomes increasingly " + + "the largest experiment in anarchy that we have ever had. And as the world becomes increasingly " + "dominated by the internet, society approaches the brink of total chaos. " + "We serve only to protect society, to protect humanity, to protect the world from its imminent collapse.", - -} \ No newline at end of file + +} + +export {FactionInfo}; diff --git a/src/Gang.js b/src/Gang.js index 60d72956a..eb6ea0916 100644 --- a/src/Gang.js +++ b/src/Gang.js @@ -1,3 +1,20 @@ +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {Faction, Factions} from "./Faction.js"; +import {Locations} from "./Location.js"; +import {Player} from "./Player.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {getRandomInt} from "../utils/HelperFunctions.js"; +import numeral from "../utils/numeral.min.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; +import {yesNoBoxCreate, yesNoTxtInpBoxCreate, + yesNoBoxGetYesButton, yesNoBoxGetNoButton, + yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton, + yesNoTxtInpBoxGetInput, yesNoBoxClose, + yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox.js"; + /* Gang.js */ //Switch between territory and management screen with 1 and 2 $(document).keydown(function(event) { @@ -29,11 +46,11 @@ $(document).mousedown(function(event) { } }); -GangNames = ["Slum Snakes", "Tetrads", "The Syndicate", "The Dark Army", "Speakers for the Dead", +let GangNames = ["Slum Snakes", "Tetrads", "The Syndicate", "The Dark Army", "Speakers for the Dead", "NiteSec", "The Black Hand"]; -GangLocations = [Locations.Aevum, Locations.Chongqing, Locations.Sector12, Locations.NewTokyo, - Locations.Ishima, Locations.Volhaven]; -AllGangs = { +let GangLocations = [Locations.Aevum, Locations.Chongqing, Locations.Sector12, Locations.NewTokyo, + Locations.Ishima, Locations.Volhaven]; +let AllGangs = { "Slum Snakes" : { power: 1, territory: 1/7, @@ -64,8 +81,12 @@ AllGangs = { }, } +function loadAllGangs(saveString) { + AllGangs = JSON.parse(saveString, Reviver); +} + //Power is an estimate of a gang's ability to gain/defend territory -gangStoredPowerCycles = 0; +let gangStoredPowerCycles = 0; function processAllGangPowerGains(numCycles=1) { if (!Player.inGang()) {return;} gangStoredPowerCycles += numCycles; @@ -85,7 +106,7 @@ function processAllGangPowerGains(numCycles=1) { gangStoredPowerCycles -= 150; } -gangStoredTerritoryCycles = 0; +let gangStoredTerritoryCycles = 0; function processAllGangTerritory(numCycles=1) { if (!Player.inGang()) {return;} gangStoredTerritoryCycles += numCycles; @@ -118,12 +139,6 @@ function processAllGangTerritory(numCycles=1) { gangStoredTerritoryCycles -= CONSTANTS.GangTerritoryUpdateTimer; } -//Returns true if Player is in a gang and false otherwise -PlayerObject.prototype.inGang = function() { - if (this.gang == null || this.gang == undefined) {return false;} - return (this.gang instanceof Gang); -} - /* faction - Name of corresponding faction hacking - Boolean indicating whether its a hacking gang or not */ @@ -230,7 +245,6 @@ Gang.fromJSON = function(value) { Reviver.constructors.Gang = Gang; - /*** Gang Member object ***/ function GangMember(name) { this.name = name; @@ -405,7 +419,7 @@ GangMemberTask.fromJSON = function(value) { Reviver.constructors.GangMemberTask = GangMemberTask; //TODO Human trafficking and an equivalent hacking crime -GangMemberTasks = { +let GangMemberTasks = { "Ransomware" : new GangMemberTask( "Ransomware", "Assign this gang member to create and distribute ransomware

" + @@ -674,7 +688,7 @@ GangMemberUpgrade.fromJSON = function(value) { Reviver.constructors.GangMemberUpgrade = GangMemberUpgrade; -GangMemberUpgrades = { +let GangMemberUpgrades = { "Baseball Bat" : new GangMemberUpgrade("Baseball Bat", "Increases strength and defense by 10%", 1000000, "w"), "Katana" : new GangMemberUpgrade("Katana", @@ -716,7 +730,7 @@ GangMemberUpgrades = { } //Create a pop-up box that lets player purchase upgrades -var gangMemberUpgradeBoxOpened = false; +let gangMemberUpgradeBoxOpened = false; function createGangMemberUpgradeBox(memberObj) { console.log("Creating gang member upgrade box for " + memberObj.name); var container = document.getElementById("gang-purchase-upgrade-container"); @@ -838,7 +852,7 @@ function createGangMemberUpgradeButtons(memberObj, upgNames, memberUpgrade, cont } } -var gangContentCreated = false; +let gangContentCreated = false; function displayGangContent() { if (!gangContentCreated) { gangContentCreated = true; @@ -1084,7 +1098,7 @@ function setGangMemberClickHandlers() { console.log("ERROR: Could not find Active Scripts server panels"); return; } - for (i = 0; i < gangMemberHdrs.length; ++i) { + for (let i = 0; i < gangMemberHdrs.length; ++i) { gangMemberHdrs[i].onclick = function() { this.classList.toggle("active"); @@ -1168,7 +1182,7 @@ function createGangMemberDisplayElement(memberObj) { if (memberObj.task instanceof GangMemberTask) { var taskName = memberObj.task.name; var taskIndex = 0; - for (i = 0; i < tasks.length; ++i) { + for (let i = 0; i < tasks.length; ++i) { if (taskName == tasks[i]) { taskIndex = i; break; @@ -1247,3 +1261,5 @@ function setGangMemberTaskDescription(memberObj, taskName) { taskDesc.innerHTML = desc; } } + +export {Gang, displayGangContent, updateGangContent, loadAllGangs, AllGangs}; diff --git a/src/HacknetNode.js b/src/HacknetNode.js index e5d28825d..dd8e68ec8 100644 --- a/src/HacknetNode.js +++ b/src/HacknetNode.js @@ -1,3 +1,15 @@ +import {BitNodeMultipliers} from "./BitNode.js"; +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {iTutorialSteps, iTutorialNextStep, + iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js"; +import {Player} from "./Player.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; + /* HacknetNode.js */ function hacknetNodesInit() { var mult1x = document.getElementById("hacknet-nodes-1x-multiplier"); @@ -50,7 +62,9 @@ HacknetNode.prototype.updateMoneyGainRate = function() { this.moneyGainRatePerSecond = (this.level * gainPerLevel) * Math.pow(1.035, this.ram-1) * - ((this.cores + 5) / 6) * Player.hacknet_node_money_mult; + ((this.cores + 5) / 6) * + Player.hacknet_node_money_mult * + BitNodeMultipliers.HacknetNodeMoney; if (isNaN(this.moneyGainRatePerSecond)) { this.moneyGainRatePerSecond = 0; dialogBoxCreate("Error in calculating Hacknet Node production. Please report to game developer"); @@ -165,7 +179,7 @@ HacknetNode.fromJSON = function(value) { Reviver.constructors.HacknetNode = HacknetNode; -purchaseHacknet = function() { +function purchaseHacknet() { /* INTERACTIVE TUTORIAL */ if (iTutorialIsRunning) { if (currITutorialStep == iTutorialSteps.HacknetNodesIntroduction) { @@ -199,7 +213,7 @@ purchaseHacknet = function() { } //Calculates the total production from all HacknetNodes -updateTotalHacknetProduction = function() { +function updateTotalHacknetProduction() { var total = 0; for (var i = 0; i < Player.hacknetNodes.length; ++i) { total += Player.hacknetNodes[i].moneyGainRatePerSecond; @@ -207,7 +221,7 @@ updateTotalHacknetProduction = function() { Player.totalHacknetNodeProduction = total; } -getCostOfNextHacknetNode = function() { +function getCostOfNextHacknetNode() { //Cost increases exponentially based on how many you own var numOwned = Player.hacknetNodes.length; var mult = CONSTANTS.HacknetNodePurchaseNextMult; @@ -215,7 +229,7 @@ getCostOfNextHacknetNode = function() { } var hacknetNodePurchaseMultiplier = 1; -updateHacknetNodesMultiplierButtons = function() { +function updateHacknetNodesMultiplierButtons() { var mult1x = document.getElementById("hacknet-nodes-1x-multiplier"); var mult5x = document.getElementById("hacknet-nodes-5x-multiplier"); var mult10x = document.getElementById("hacknet-nodes-10x-multiplier"); @@ -242,7 +256,7 @@ updateHacknetNodesMultiplierButtons = function() { //Calculate the maximum number of times the Player can afford to upgrade //a Hacknet Node's level" -getMaxNumberLevelUpgrades = function(nodeObj) { +function getMaxNumberLevelUpgrades(nodeObj) { if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1))) {return 0;} var min = 1; var max = CONSTANTS.HacknetNodeMaxLevel-1; @@ -268,7 +282,7 @@ getMaxNumberLevelUpgrades = function(nodeObj) { } //Creates Hacknet Node DOM elements when the page is opened -displayHacknetNodesContent = function() { +function displayHacknetNodesContent() { //Update Hacknet Nodes button var newPurchaseButton = clearEventListeners("hacknet-nodes-purchase-button"); @@ -294,7 +308,7 @@ displayHacknetNodesContent = function() { } //Update information on all Hacknet Node DOM elements -updateHacknetNodesContent = function() { +function updateHacknetNodesContent() { //Set purchase button to inactive if not enough money, and update its price display var cost = getCostOfNextHacknetNode(); var purchaseButton = document.getElementById("hacknet-nodes-purchase-button"); @@ -317,7 +331,7 @@ updateHacknetNodesContent = function() { } //Creates a single Hacknet Node DOM element -createHacknetNodeDomElement = function(nodeObj) { +function createHacknetNodeDomElement(nodeObj) { var nodeName = nodeObj.name; var listItem = document.createElement("li"); @@ -383,7 +397,7 @@ createHacknetNodeDomElement = function(nodeObj) { } //Updates information on a single hacknet node DOM element -updateHacknetNodeDomElement = function(nodeObj) { +function updateHacknetNodeDomElement(nodeObj) { var nodeName = nodeObj.name; var txt = document.getElementById("hacknet-node-text-" + nodeName); if (txt == null) {throw new Error("Cannot find text element");} @@ -453,7 +467,7 @@ updateHacknetNodeDomElement = function(nodeObj) { } } -processAllHacknetNodeEarnings = function(numCycles) { +function processAllHacknetNodeEarnings(numCycles) { var total = 0; for (var i = 0; i < Player.hacknetNodes.length; ++i) { total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]); @@ -461,7 +475,7 @@ processAllHacknetNodeEarnings = function(numCycles) { return total; } -processSingleHacknetNodeEarnings = function(numCycles, nodeObj) { +function processSingleHacknetNodeEarnings(numCycles, nodeObj) { var cyclesPerSecond = 1000 / Engine._idleSpeed; var earningPerCycle = nodeObj.moneyGainRatePerSecond / cyclesPerSecond; if (isNaN(earningPerCycle)) {throw new Error("Calculated Earnings is not a number");} @@ -472,7 +486,7 @@ processSingleHacknetNodeEarnings = function(numCycles, nodeObj) { return totalEarnings; } -getHacknetNode = function(name) { +function getHacknetNode(name) { for (var i = 0; i < Player.hacknetNodes.length; ++i) { if (Player.hacknetNodes[i].name == name) { return Player.hacknetNodes[i]; @@ -480,3 +494,8 @@ getHacknetNode = function(name) { } return null; } + +export {hacknetNodesInit, HacknetNode, purchaseHacknet, updateTotalHacknetProduction, + getCostOfNextHacknetNode, updateHacknetNodesMultiplierButtons, getMaxNumberLevelUpgrades, + displayHacknetNodesContent, updateHacknetNodesContent, processAllHacknetNodeEarnings, + getHacknetNode}; diff --git a/src/HelpText.js b/src/HelpText.js index 2a7aa126f..d74e13f8f 100644 --- a/src/HelpText.js +++ b/src/HelpText.js @@ -1,8 +1,9 @@ /* HelpText.js */ -TerminalHelpText = +let TerminalHelpText = "Type 'help name' to learn more about the command 'name'

" + 'alias [-g] [name="value"] Create or display Terminal aliases
' + "analyze Get information about the current machine
" + + "buy [-l/program] Purchase a program through the Dark Web
" + "cat [file] Display a .msg or .lit file
" + "check [script] [args...] Print a script's logs to Terminal
" + "clear Clear all text on the terminal
" + @@ -31,7 +32,7 @@ TerminalHelpText = "top Displays all running scripts and their RAM usage
" + 'unalias "[alias name]" Deletes the specified alias
'; -HelpTexts = { +let HelpTexts = { alias: 'alias [-g] [name="value"]
' + "Create or display aliases. An alias enables a replacement of a word with another string. " + "It can be used to abbreviate a commonly used command, or commonly used parts of a command. The NAME " + @@ -56,6 +57,11 @@ HelpTexts = { "server details such as the hostname, whether the player has root access, what ports are opened/closed, and also " + "hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is " + "available on the server, etc.", + buy: "buy [-l / program]
" + + "Purchase a program through the Dark Web. Requires a TOR router to use.

" + + "If this command is ran with the '-l' flag, it will display a list of all programs that can be bought through the " + + "dark web to the Terminal, as well as their costs.

" + + "Otherwise, the name of the program must be passed in as a parameter. This is name is NOT case-sensitive.", cat: "cat [file]
" + "Display message files, which are files ending with the '.msg' extension, or a literature file, which " + "are files ending with the '.lit' extension. Examples:

" + @@ -159,7 +165,7 @@ HelpTexts = { "it has", scp: "scp [filename] [target server]
" + "Copies the specified file from the current server to the target server. " + - "This command only works for script files (.script extension) and literature files (.lit extension). " + + "This command only works for script files (.script extension) and literature files (.lit extension). " + "The second argument passed in must be the hostname or IP of the target server.", sudov: "sudov
" + "Prints whether or not you have root access to the current machine", @@ -193,3 +199,5 @@ HelpTexts = { "It is not necessary to differentiate between global and non-global aliases when using 'unalias'", } + +export {TerminalHelpText, HelpTexts}; diff --git a/src/Infiltration.js b/src/Infiltration.js index ae67deeea..238dee3d6 100644 --- a/src/Infiltration.js +++ b/src/Infiltration.js @@ -1,3 +1,11 @@ +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {Player} from "./Player.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners, getRandomInt} from "../utils/HelperFunctions.js"; +import {infiltrationBoxCreate} from "../utils/InfiltrationBox.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; + /* Infiltration.js * * Kill @@ -16,7 +24,7 @@ * Escape */ -InfiltrationScenarios = { +let InfiltrationScenarios = { Guards: "You see an armed security guard patrolling the area.", TechOnly: "The area is equipped with a state-of-the-art security system: cameras, laser tripwires, and sentry turrets.", TechOrLockedDoor: "The area is equipped with a state-of-the-art security system. There is a locked door on the side of the " + @@ -71,8 +79,6 @@ InfiltrationInstance.prototype.gainCharismaExp = function(amt) { this.chaExpGained += amt; } - - function beginInfiltration(companyName, startLevel, val, maxClearance, diff) { var inst = new InfiltrationInstance(companyName, startLevel, val, maxClearance, diff); clearInfiltrationStatusText(); @@ -796,3 +802,5 @@ function getInfiltrationEscapeChance(inst) { (2 * Player.agility + Player.dexterity) / lvl); } + +export {beginInfiltration}; diff --git a/src/InteractiveTutorial.js b/src/InteractiveTutorial.js index 20348e394..665f560d6 100644 --- a/src/InteractiveTutorial.js +++ b/src/InteractiveTutorial.js @@ -1,5 +1,9 @@ +import {Engine} from "./engine.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; + /* InteractiveTutorial.js */ -iTutorialSteps = { +let iTutorialSteps = { Start: "Start", GoToCharacterPage: "Click on the Character page menu link", CharacterPage: "Introduction to Character page", @@ -652,3 +656,6 @@ function iTutorialSetText(txt) { textBox.innerHTML = txt; textBox.parentElement.scrollTop = 0; // this resets scroll position } + +export {iTutorialSteps, iTutorialEnd, iTutorialStart, iTutorialNextStep, currITutorialStep, + iTutorialIsRunning}; diff --git a/src/Literature.js b/src/Literature.js index 7b41cb655..78d12f445 100644 --- a/src/Literature.js +++ b/src/Literature.js @@ -1,3 +1,5 @@ +import {dialogBoxCreate} from "../utils/DialogBox.js"; + /* Literature.js * Lore / world building literature that can be found on servers */ @@ -15,7 +17,7 @@ function showLiterature(fn) { dialogBoxCreate(txt); } -Literatures = {} +let Literatures = {} function initLiterature() { var title, fn, txt; @@ -125,7 +127,7 @@ function initLiterature() { "Soon the cries rose everywhere, with revolt and riot
Until one day, finally, all was quiet
" + "From the ashes rose a new order, corporatocracy was its name
" + "Rome, Mongol, Byzantine, all of history is just the same
" + - "For man will never change in a fundamental way
" + "For man will never change in a fundamental way
" + "And now democracy is dead, in the USA"; Literatures[fn] = new Literature(title, fn, txt); @@ -265,7 +267,7 @@ function initLiterature() { title = "The Hidden World"; fn = "the-hidden-world.lit"; - txt = "WAKE UP SHEEPLE

" + txt = "WAKE UP SHEEPLE

" + "THE GOVERNMENT DOES NOT EXIST. CORPORATIONS DO NOT RUN SOCIETY

" + "THE ILLUMINATI ARE THE SECRET RULERS OF THE WORLD!

" + "Yes, the Illuminati of legends. The ancient secret society that controls the entire " + @@ -317,3 +319,5 @@ function initLiterature() { txt = "" Literatures[fn] = new Literature(title, fn, txt); } + +export {Literatures, initLiterature, showLiterature}; diff --git a/src/Location.js b/src/Location.js index aa5b1b575..6153b8a3d 100644 --- a/src/Location.js +++ b/src/Location.js @@ -1,7 +1,36 @@ +import {CompanyPositions, initCompanies, + Companies, getJobRequirementText} from "./Company.js"; +import {CONSTANTS} from "./Constants.js"; +import {commitShopliftCrime, commitRobStoreCrime, commitMugCrime, + commitLarcenyCrime, commitDealDrugsCrime, commitTraffickArmsCrime, + commitHomicideCrime, commitGrandTheftAutoCrime, commitKidnapCrime, + commitAssassinationCrime, commitHeistCrime, determineCrimeSuccess, + determineCrimeChanceShoplift, determineCrimeChanceRobStore, + determineCrimeChanceMug, determineCrimeChanceLarceny, + determineCrimeChanceDealDrugs, determineCrimeChanceTraffickArms, + determineCrimeChanceHomicide, determineCrimeChanceGrandTheftAuto, + determineCrimeChanceKidnap, determineCrimeChanceAssassination, + determineCrimeChanceHeist} from "./Crimes.js"; +import {Engine} from "./engine.js"; +import {beginInfiltration} from "./Infiltration.js"; +import {Player} from "./Player.js"; +import {Server, AllServers, AddToAllServers} from "./Server.js"; +import {purchaseServer, + purchaseRamForHomeComputer} from "./ServerPurchases.js"; +import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps.js"; + +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {createRandomIp} from "../utils/IPAddress.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; +import {yesNoBoxCreate, yesNoTxtInpBoxCreate, + yesNoBoxGetYesButton, yesNoBoxGetNoButton, + yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton, + yesNoTxtInpBoxGetInput, yesNoBoxClose, + yesNoTxtInpBoxClose} from "../utils/YesNoBox.js"; + /* Display Location Content when visiting somewhere in the World*/ - - -Locations = { +let Locations = { //Cities Aevum: "Aevum", //AevumDesc: "" @@ -86,7 +115,7 @@ Locations = { WorldStockExchange: "World Stock Exchange", } -displayLocationContent = function() { +function displayLocationContent() { if (Engine.debug) { console.log("displayLocationContent() called with location " + Player.location) } @@ -1058,458 +1087,457 @@ displayLocationContent = function() { } } -initLocationButtons = function() { +function initLocationButtons() { //Buttons to travel to different locations in World - aevumTravelAgency = document.getElementById("aevum-travelagency"); + let aevumTravelAgency = document.getElementById("aevum-travelagency"); aevumTravelAgency.addEventListener("click", function() { Player.location = Locations.AevumTravelAgency; Engine.loadLocationContent(); return false; }); - aevumHospital = document.getElementById("aevum-hospital"); + let aevumHospital = document.getElementById("aevum-hospital"); aevumHospital.addEventListener("click", function() { Player.location = Locations.Hospital; Engine.loadLocationContent(); return false; }); - aevumSummitUniversity = document.getElementById("aevum-summituniversity"); + let aevumSummitUniversity = document.getElementById("aevum-summituniversity"); aevumSummitUniversity.addEventListener("click", function() { Player.location = Locations.AevumSummitUniversity; Engine.loadLocationContent(); return false; }); - aevumECorp = document.getElementById("aevum-ecorp"); + let aevumECorp = document.getElementById("aevum-ecorp"); aevumECorp.addEventListener("click", function() { Player.location = Locations.AevumECorp; Engine.loadLocationContent(); return false; }); - aevumBachmanAndAssociates = document.getElementById("aevum-bachmanandassociates"); + let aevumBachmanAndAssociates = document.getElementById("aevum-bachmanandassociates"); aevumBachmanAndAssociates.addEventListener("click", function() { Player.location = Locations.AevumBachmanAndAssociates; Engine.loadLocationContent(); return false; }); - aevumClarkeIncorporated = document.getElementById("aevum-clarkeincorporated"); + let aevumClarkeIncorporated = document.getElementById("aevum-clarkeincorporated"); aevumClarkeIncorporated.addEventListener("click", function() { Player.location = Locations.AevumClarkeIncorporated; Engine.loadLocationContent(); return false; }); - aevumFulcrumTechnologies = document.getElementById("aevum-fulcrumtechnologies"); + let aevumFulcrumTechnologies = document.getElementById("aevum-fulcrumtechnologies"); aevumFulcrumTechnologies.addEventListener("click", function() { Player.location = Locations.AevumFulcrumTechnologies; Engine.loadLocationContent(); return false; }); - aevumAeroCorp = document.getElementById("aevum-aerocorp"); + let aevumAeroCorp = document.getElementById("aevum-aerocorp"); aevumAeroCorp.addEventListener("click", function() { Player.location = Locations.AevumAeroCorp; Engine.loadLocationContent(); return false; }); - aevumGalacticCybersystems = document.getElementById("aevum-galacticcybersystems"); + let aevumGalacticCybersystems = document.getElementById("aevum-galacticcybersystems"); aevumGalacticCybersystems.addEventListener("click", function() { Player.location = Locations.AevumGalacticCybersystems; Engine.loadLocationContent(); return false; }); - aevumWatchdogSecurity = document.getElementById("aevum-watchdogsecurity"); + let aevumWatchdogSecurity = document.getElementById("aevum-watchdogsecurity"); aevumWatchdogSecurity.addEventListener("click", function() { Player.location = Locations.AevumWatchdogSecurity; Engine.loadLocationContent(); return false; }); - aevumRhoConstruction = document.getElementById("aevum-rhoconstruction"); + let aevumRhoConstruction = document.getElementById("aevum-rhoconstruction"); aevumRhoConstruction.addEventListener("click", function() { Player.location = Locations.AevumRhoConstruction; Engine.loadLocationContent(); return false; }); - aevumPolice = document.getElementById("aevum-aevumpolice"); + let aevumPolice = document.getElementById("aevum-aevumpolice"); aevumPolice.addEventListener("click", function() { Player.location = Locations.AevumPolice; Engine.loadLocationContent(); return false; }); - aevumNetLinkTechnologies = document.getElementById("aevum-netlinktechnologies"); + let aevumNetLinkTechnologies = document.getElementById("aevum-netlinktechnologies"); aevumNetLinkTechnologies.addEventListener("click", function() { Player.location = Locations.AevumNetLinkTechnologies; Engine.loadLocationContent(); return false; }); - aevumCrushFitnessGym = document.getElementById("aevum-crushfitnessgym"); + let aevumCrushFitnessGym = document.getElementById("aevum-crushfitnessgym"); aevumCrushFitnessGym.addEventListener("click", function() { Player.location = Locations.AevumCrushFitnessGym; Engine.loadLocationContent(); return false; }); - aevumSnapFitnessGym = document.getElementById("aevum-snapfitnessgym"); + let aevumSnapFitnessGym = document.getElementById("aevum-snapfitnessgym"); aevumSnapFitnessGym.addEventListener("click", function() { Player.location = Locations.AevumSnapFitnessGym; Engine.loadLocationContent(); return false; }); - aevumSlums = document.getElementById("aevum-slums"); + let aevumSlums = document.getElementById("aevum-slums"); aevumSlums.addEventListener("click", function() { Player.location = Locations.AevumSlums; Engine.loadLocationContent(); return false; }); - chongqingTravelAgency = document.getElementById("chongqing-travelagency"); + let chongqingTravelAgency = document.getElementById("chongqing-travelagency"); chongqingTravelAgency.addEventListener("click", function() { Player.location = Locations.ChongqingTravelAgency; Engine.loadLocationContent(); return false; }); - chongqingHospital = document.getElementById("chongqing-hospital"); + let chongqingHospital = document.getElementById("chongqing-hospital"); chongqingHospital.addEventListener("click", function() { Player.location = Locations.Hospital; Engine.loadLocationContent(); return false; }); - chongqingKuaiGongInternational = document.getElementById("chongqing-kuaigonginternational"); + let chongqingKuaiGongInternational = document.getElementById("chongqing-kuaigonginternational"); chongqingKuaiGongInternational.addEventListener("click", function() { Player.location = Locations.ChongqingKuaiGongInternational; Engine.loadLocationContent(); return false; }); - chongqingSolarisSpaceSystems = document.getElementById("chongqing-solarisspacesystems"); + let chongqingSolarisSpaceSystems = document.getElementById("chongqing-solarisspacesystems"); chongqingSolarisSpaceSystems.addEventListener("click", function() { Player.location = Locations.ChongqingSolarisSpaceSystems; Engine.loadLocationContent(); return false; }); - chongqingSlums = document.getElementById("chongqing-slums"); + let chongqingSlums = document.getElementById("chongqing-slums"); chongqingSlums.addEventListener("click", function() { Player.location = Locations.ChongqingSlums; Engine.loadLocationContent(); return false; }); - - sector12TravelAgency = document.getElementById("sector12-travelagency"); + let sector12TravelAgency = document.getElementById("sector12-travelagency"); sector12TravelAgency.addEventListener("click", function() { Player.location = Locations.Sector12TravelAgency; Engine.loadLocationContent(); return false; }); - sector12Hospital = document.getElementById("sector12-hospital"); + let sector12Hospital = document.getElementById("sector12-hospital"); sector12Hospital.addEventListener("click", function() { Player.location = Locations.Hospital; Engine.loadLocationContent(); return false; }); - sector12RothmanUniversity = document.getElementById("sector12-rothmanuniversity"); + let sector12RothmanUniversity = document.getElementById("sector12-rothmanuniversity"); sector12RothmanUniversity.addEventListener("click", function() { Player.location = Locations.Sector12RothmanUniversity; Engine.loadLocationContent(); return false; }); - sector12MegaCorp = document.getElementById("sector12-megacorp"); + let sector12MegaCorp = document.getElementById("sector12-megacorp"); sector12MegaCorp.addEventListener("click", function() { Player.location = Locations.Sector12MegaCorp; Engine.loadLocationContent(); return false; }); - sector12BladeIndustries = document.getElementById("sector12-bladeindustries"); + let sector12BladeIndustries = document.getElementById("sector12-bladeindustries"); sector12BladeIndustries.addEventListener("click", function() { Player.location = Locations.Sector12BladeIndustries; Engine.loadLocationContent(); return false; }); - sector12FourSigma = document.getElementById("sector12-foursigma"); + let sector12FourSigma = document.getElementById("sector12-foursigma"); sector12FourSigma.addEventListener("click", function() { Player.location = Locations.Sector12FourSigma; Engine.loadLocationContent(); return false; }); - sector12IcarusMicrosystems = document.getElementById("sector12-icarusmicrosystems"); + let sector12IcarusMicrosystems = document.getElementById("sector12-icarusmicrosystems"); sector12IcarusMicrosystems.addEventListener("click", function() { Player.location = Locations.Sector12IcarusMicrosystems; Engine.loadLocationContent(); return false; }); - sector12UniversalEnergy = document.getElementById("sector12-universalenergy"); + let sector12UniversalEnergy = document.getElementById("sector12-universalenergy"); sector12UniversalEnergy.addEventListener("click", function() { Player.location = Locations.Sector12UniversalEnergy; Engine.loadLocationContent(); return false; }); - sector12DeltaOne = document.getElementById("sector12-deltaone"); + let sector12DeltaOne = document.getElementById("sector12-deltaone"); sector12DeltaOne.addEventListener("click", function() { Player.location = Locations.Sector12DeltaOne; Engine.loadLocationContent(); return false; }); - sector12CIA = document.getElementById("sector12-cia"); + let sector12CIA = document.getElementById("sector12-cia"); sector12CIA.addEventListener("click", function() { Player.location = Locations.Sector12CIA; Engine.loadLocationContent(); return false; }); - sector12NSA = document.getElementById("sector12-nsa"); + let sector12NSA = document.getElementById("sector12-nsa"); sector12NSA.addEventListener("click", function() { Player.location = Locations.Sector12NSA; Engine.loadLocationContent(); return false; }); - sector12AlphaEnterprises = document.getElementById("sector12-alphaenterprises"); + let sector12AlphaEnterprises = document.getElementById("sector12-alphaenterprises"); sector12AlphaEnterprises.addEventListener("click", function() { Player.location = Locations.Sector12AlphaEnterprises; Engine.loadLocationContent(); return false; }); - sector12CarmichaelSecurity = document.getElementById("sector12-carmichaelsecurity"); + let sector12CarmichaelSecurity = document.getElementById("sector12-carmichaelsecurity"); sector12CarmichaelSecurity.addEventListener("click", function() { Player.location = Locations.Sector12CarmichaelSecurity; Engine.loadLocationContent(); return false; }); - sector12FoodNStuff = document.getElementById("sector12-foodnstuff"); + let sector12FoodNStuff = document.getElementById("sector12-foodnstuff"); sector12FoodNStuff.addEventListener("click", function() { Player.location = Locations.Sector12FoodNStuff; Engine.loadLocationContent(); return false; }); - sector12JoesGuns = document.getElementById("sector12-joesguns"); + let sector12JoesGuns = document.getElementById("sector12-joesguns"); sector12JoesGuns.addEventListener("click", function() { Player.location = Locations.Sector12JoesGuns; Engine.loadLocationContent(); return false; }); - sector12IronGym = document.getElementById("sector12-irongym"); + let sector12IronGym = document.getElementById("sector12-irongym"); sector12IronGym.addEventListener("click", function() { Player.location = Locations.Sector12IronGym; Engine.loadLocationContent(); return false; }); - sector12PowerhouseGym = document.getElementById("sector12-powerhousegym"); + let sector12PowerhouseGym = document.getElementById("sector12-powerhousegym"); sector12PowerhouseGym.addEventListener("click", function() { Player.location = Locations.Sector12PowerhouseGym; Engine.loadLocationContent(); return false; }); - sector12Slums = document.getElementById("sector12-slums"); + let sector12Slums = document.getElementById("sector12-slums"); sector12Slums.addEventListener("click", function() { Player.location = Locations.Sector12Slums; Engine.loadLocationContent(); return false; }); - newTokyoTravelAgency = document.getElementById("newtokyo-travelagency"); + let newTokyoTravelAgency = document.getElementById("newtokyo-travelagency"); newTokyoTravelAgency.addEventListener("click", function() { Player.location = Locations.NewTokyoTravelAgency; Engine.loadLocationContent(); return false; }); - newTokyoHospital = document.getElementById("newtokyo-hospital"); + let newTokyoHospital = document.getElementById("newtokyo-hospital"); newTokyoHospital.addEventListener("click", function() { Player.location = Locations.Hospital; Engine.loadLocationContent(); return false; }); - newTokyoDefComm = document.getElementById("newtokyo-defcomm"); + let newTokyoDefComm = document.getElementById("newtokyo-defcomm"); newTokyoDefComm.addEventListener("click", function() { Player.location = Locations.NewTokyoDefComm; Engine.loadLocationContent(); return false; }); - newTokyoVitaLife = document.getElementById("newtokyo-vitalife"); + let newTokyoVitaLife = document.getElementById("newtokyo-vitalife"); newTokyoVitaLife.addEventListener("click", function() { Player.location = Locations.NewTokyoVitaLife; Engine.loadLocationContent(); return false; }); - newTokyoGlobalPharmaceuticals = document.getElementById("newtokyo-globalpharmaceuticals"); + let newTokyoGlobalPharmaceuticals = document.getElementById("newtokyo-globalpharmaceuticals"); newTokyoGlobalPharmaceuticals.addEventListener("click", function() { Player.location = Locations.NewTokyoGlobalPharmaceuticals; Engine.loadLocationContent(); return false; }); - newTokyoNoodleBar = document.getElementById("newtokyo-noodlebar"); + let newTokyoNoodleBar = document.getElementById("newtokyo-noodlebar"); newTokyoNoodleBar.addEventListener("click", function() { Player.location = Locations.NewTokyoNoodleBar; Engine.loadLocationContent(); return false; }); - newTokyoSlums = document.getElementById("newtokyo-slums"); + let newTokyoSlums = document.getElementById("newtokyo-slums"); newTokyoSlums.addEventListener("click", function() { Player.location = Locations.NewTokyoSlums; Engine.loadLocationContent(); return false; }); - ishimaTravelAgency = document.getElementById("ishima-travelagency"); + let ishimaTravelAgency = document.getElementById("ishima-travelagency"); ishimaTravelAgency.addEventListener("click", function() { Player.location = Locations.IshimaTravelAgency; Engine.loadLocationContent(); return false; }); - ishimaHospital = document.getElementById("ishima-hospital"); + let ishimaHospital = document.getElementById("ishima-hospital"); ishimaHospital.addEventListener("click", function() { Player.location = Locations.Hospital; Engine.loadLocationContent(); return false; }); - ishimaStormTechnologies = document.getElementById("ishima-stormtechnologies"); + let ishimaStormTechnologies = document.getElementById("ishima-stormtechnologies"); ishimaStormTechnologies.addEventListener("click", function() { Player.location = Locations.IshimaStormTechnologies; Engine.loadLocationContent(); return false; }); - ishimaNovaMedical = document.getElementById("ishima-novamedical"); + let ishimaNovaMedical = document.getElementById("ishima-novamedical"); ishimaNovaMedical.addEventListener("click", function() { Player.location = Locations.IshimaNovaMedical; Engine.loadLocationContent(); return false; }); - ishimaOmegaSoftware = document.getElementById("ishima-omegasoftware"); + let ishimaOmegaSoftware = document.getElementById("ishima-omegasoftware"); ishimaOmegaSoftware.addEventListener("click", function() { Player.location = Locations.IshimaOmegaSoftware; Engine.loadLocationContent(); return false; }); - ishimaSlums = document.getElementById("ishima-slums"); + let ishimaSlums = document.getElementById("ishima-slums"); ishimaSlums.addEventListener("click", function() { Player.location = Locations.IshimaSlums; Engine.loadLocationContent(); return false; }); - volhavenTravelAgency = document.getElementById("volhaven-travelagency"); + let volhavenTravelAgency = document.getElementById("volhaven-travelagency"); volhavenTravelAgency.addEventListener("click", function() { Player.location = Locations.VolhavenTravelAgency; Engine.loadLocationContent(); return false; }); - volhavenHospital = document.getElementById("volhaven-hospital"); + let volhavenHospital = document.getElementById("volhaven-hospital"); volhavenHospital.addEventListener("click", function() { Player.location = Locations.Hospital; Engine.loadLocationContent(); return false; }); - volhavenZBInstituteOfTechnology = document.getElementById("volhaven-zbinstituteoftechnology"); + let volhavenZBInstituteOfTechnology = document.getElementById("volhaven-zbinstituteoftechnology"); volhavenZBInstituteOfTechnology.addEventListener("click", function() { Player.location = Locations.VolhavenZBInstituteOfTechnology; Engine.loadLocationContent(); return false; }); - volhavenOmniTekIncorporated = document.getElementById("volhaven-omnitekincorporated"); + let volhavenOmniTekIncorporated = document.getElementById("volhaven-omnitekincorporated"); volhavenOmniTekIncorporated.addEventListener("click", function() { Player.location = Locations.VolhavenOmniTekIncorporated; Engine.loadLocationContent(); return false; }); - volhavenNWO = document.getElementById("volhaven-nwo"); + let volhavenNWO = document.getElementById("volhaven-nwo"); volhavenNWO.addEventListener("click", function() { Player.location = Locations.VolhavenNWO; Engine.loadLocationContent(); return false; }); - volhavenHeliosLabs = document.getElementById("volhaven-helioslabs"); + let volhavenHeliosLabs = document.getElementById("volhaven-helioslabs"); volhavenHeliosLabs.addEventListener("click", function() { Player.location = Locations.VolhavenHeliosLabs; Engine.loadLocationContent(); return false; }); - volhavenOmniaCybersystems = document.getElementById("volhaven-omniacybersystems"); + let volhavenOmniaCybersystems = document.getElementById("volhaven-omniacybersystems"); volhavenOmniaCybersystems.addEventListener("click", function() { Player.location = Locations.VolhavenOmniaCybersystems; Engine.loadLocationContent(); return false; }); - volhavenLexoCorp = document.getElementById("volhaven-lexocorp"); + let volhavenLexoCorp = document.getElementById("volhaven-lexocorp"); volhavenLexoCorp.addEventListener("click", function() { Player.location = Locations.VolhavenLexoCorp; Engine.loadLocationContent(); return false; }); - volhavenSysCoreSecurities = document.getElementById("volhaven-syscoresecurities"); + let volhavenSysCoreSecurities = document.getElementById("volhaven-syscoresecurities"); volhavenSysCoreSecurities.addEventListener("click", function() { Player.location = Locations.VolhavenSysCoreSecurities; Engine.loadLocationContent(); return false; }); - volhavenCompuTek = document.getElementById("volhaven-computek"); + let volhavenCompuTek = document.getElementById("volhaven-computek"); volhavenCompuTek.addEventListener("click", function() { Player.location = Locations.VolhavenCompuTek; Engine.loadLocationContent(); return false; }); - volhavenMilleniumFitnessGym = document.getElementById("volhaven-milleniumfitnessgym"); + let volhavenMilleniumFitnessGym = document.getElementById("volhaven-milleniumfitnessgym"); volhavenMilleniumFitnessGym.addEventListener("click", function() { Player.location = Locations.VolhavenMilleniumFitnessGym; Engine.loadLocationContent(); return false; }); - volhavenSlums = document.getElementById("volhaven-slums"); + let volhavenSlums = document.getElementById("volhaven-slums"); volhavenSlums.addEventListener("click", function() { Player.location = Locations.VolhavenSlums; Engine.loadLocationContent(); return false; }); - worldStockExchange = document.getElementById("generic-location-wse"); + let worldStockExchange = document.getElementById("generic-location-wse"); worldStockExchange.addEventListener("click", function() { Player.location = Locations.WorldStockExchange; Engine.loadStockMarketContent(); @@ -1811,7 +1839,8 @@ initLocationButtons = function() { }); } -travelToCity = function(destCityName, cost) { +function travelToCity(destCityName, cost) { + Player.firstTimeTraveled = true; if (Player.money.lt(cost)) { dialogBoxCreate("You cannot afford to travel to " + destCityName); return; @@ -1823,7 +1852,7 @@ travelToCity = function(destCityName, cost) { Engine.loadWorldContent(); } -purchaseTorRouter = function() { +function purchaseTorRouter() { if (Player.money.lt(CONSTANTS.TorRouterCost)) { dialogBoxCreate("You cannot afford to purchase the Tor router"); return; @@ -1841,7 +1870,7 @@ purchaseTorRouter = function() { dialogBoxCreate("You have purchased a Tor router!
You now have access to the dark web from your home computer
Use the scan/netstat commands to search for the dark web connection."); } -displayUniversityLocationContent = function(costMult) { +function displayUniversityLocationContent(costMult) { var studyComputerScienceButton = document.getElementById("location-study-computer-science"); var classDataStructuresButton = document.getElementById("location-data-structures-class"); var classNetworksButton = document.getElementById("location-networks-class"); @@ -1870,7 +1899,7 @@ displayUniversityLocationContent = function(costMult) { classLeadershipButton.innerHTML = "Take Leadership course ($" + leadershipCost + " / sec)"; } -setUniversityLocationButtons = function(costMult, expMult) { +function setUniversityLocationButtons(costMult, expMult) { var newStudyCS = clearEventListeners("location-study-computer-science"); newStudyCS.addEventListener("click", function() { Player.startClass(costMult, expMult, CONSTANTS.ClassStudyComputerScience); @@ -1908,7 +1937,7 @@ setUniversityLocationButtons = function(costMult, expMult) { }); } -displayGymLocationContent = function(costMult) { +function displayGymLocationContent(costMult) { var gymStrButton = document.getElementById("location-gym-train-str"); var gymDefButton = document.getElementById("location-gym-train-def"); var gymDexButton = document.getElementById("location-gym-train-dex"); @@ -1928,7 +1957,7 @@ displayGymLocationContent = function(costMult) { gymAgiButton.innerHTML = "Train Agility ($" + cost + " / sec)"; } -setGymLocationButtons = function(costMult, expMult) { +function setGymLocationButtons(costMult, expMult) { var gymStr = clearEventListeners("location-gym-train-str"); gymStr.addEventListener("click", function() { Player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength); @@ -1954,7 +1983,7 @@ setGymLocationButtons = function(costMult, expMult) { }); } -setInfiltrateButton = function(btn, companyName, startLevel, val, maxClearance, difficulty) { +function setInfiltrateButton(btn, companyName, startLevel, val, maxClearance, difficulty) { btn.style.display = "block"; btn.addEventListener("click", function() { Engine.loadInfiltrationContent(); @@ -2008,3 +2037,5 @@ function purchaseServerBoxCreate(ram, cost) { "GB of RAM for $" + formatNumber(cost, 2) + "?

" + "Please enter the server hostname below:
"); } + +export {Locations, displayLocationContent, initLocationButtons}; diff --git a/src/Message.js b/src/Message.js index 80f92b747..6404e6e3a 100644 --- a/src/Message.js +++ b/src/Message.js @@ -1,3 +1,13 @@ +import {Augmentations, Augmentation, + AugmentationNames} from "./Augmentations.js"; +import {Programs} from "./CreateProgram.js"; +import {Player} from "./Player.js"; +import {GetServerByHostname} from "./Server.js"; +import {Settings} from "./Settings.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; + /* Message.js */ function Message(filename="", msg="") { this.filename = filename; @@ -56,6 +66,11 @@ function checkForMessagesToSend() { var bitrunnersTest = Messages[MessageFilenames.BitRunnersTest]; var redpill = Messages[MessageFilenames.RedPill]; + var redpillOwned = false; + if (Augmentations[AugmentationNames.TheRedPill].owned) { + redpillOwned = true; + } + if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) { sendMessage(jumper0); } else if (jumper1 && !jumper1.recvd && Player.hacking_skill >= 40) { @@ -75,7 +90,7 @@ function checkForMessagesToSend() { } else if (jumper5 && !jumper5.recvd && Player.hacking_skill >= 1000) { sendMessage(jumper5); Player.getHomeComputer().programs.push(Programs.Flight); - } else if (redpill && !redpill.recvd && Player.hacking_skill >= 2000) { + } else if (redpill && !redpill.recvd && Player.hacking_skill >= 2000 && redpillOwned) { sendMessage(redpill); } } @@ -84,9 +99,13 @@ function AddToAllMessages(msg) { Messages[msg.filename] = msg; } -Messages = {} +let Messages = {} -MessageFilenames = { +function loadMessages(saveString) { + Messages = JSON.parse(saveString, Reviver); +} + +let MessageFilenames = { Jumper0: "j0.msg", Jumper1: "j1.msg", Jumper2: "j2.msg", @@ -160,3 +179,6 @@ function initMessages() { "@_#(%_@#M(BDSPOMB__THE-CAVE_#)$(*@#$)@#BNBEGB
" + "DFLSMFVMV)#@($*)@#*$MV)@#(*$V)M#(*$)M@(#*VM$)")); } + +export {Messages, checkForMessagesToSend, sendMessage, showMessage, loadMessages, + initMessages, Message}; diff --git a/src/NetscriptEnvironment.js b/src/NetscriptEnvironment.js index e51a828a1..7a358ac66 100644 --- a/src/NetscriptEnvironment.js +++ b/src/NetscriptEnvironment.js @@ -1,5 +1,6 @@ +import {NetscriptFunctions} from "./NetscriptFunctions.js"; /* Environment - * NetScript program environment + * NetScript program environment */ function Environment(workerScript,parent) { if (parent){ @@ -16,7 +17,7 @@ Environment.prototype = { extend: function() { return new Environment(this); }, - + //Finds the scope where the variable with the given name is defined lookup: function(name) { var scope = this; @@ -26,7 +27,7 @@ Environment.prototype = { scope = scope.parent; } }, - + //Get the current value of a variable get: function(name) { if (name in this.vars) { @@ -34,7 +35,7 @@ Environment.prototype = { } throw new Error("Undefined variable " + name); }, - + //Sets the value of a variable in any scope set: function(name, value) { var scope = this.lookup(name); @@ -48,7 +49,7 @@ Environment.prototype = { } return (scope || this).vars[name] = value; }, - + setArrayElement: function(name, idx, value) { var scope = this.lookup(name); if (!scope && this.parent) { @@ -61,9 +62,11 @@ Environment.prototype = { } return (scope || this).vars[name][idx] = value; }, - + //Creates (or overwrites) a variable in the current scope def: function(name, value) { return this.vars[name] = value; - } -}; \ No newline at end of file + } +}; + +export {Environment}; diff --git a/src/NetscriptEvaluator.js b/src/NetscriptEvaluator.js index c125b4d59..c681dc087 100644 --- a/src/NetscriptEvaluator.js +++ b/src/NetscriptEvaluator.js @@ -1,3 +1,17 @@ +import {BitNodeMultipliers} from "./BitNode.js"; +import {CONSTANTS} from "./Constants.js"; +import {Player} from "./Player.js"; +import {Environment} from "./NetscriptEnvironment.js"; +import {WorkerScript, addWorkerScript} from "./NetscriptWorker.js"; +import {Server} from "./Server.js"; +import {Settings} from "./Settings.js"; +import {Script, findRunningScript, + RunningScript} from "./Script.js"; + +import {printArray} from "../utils/HelperFunctions.js"; +import {isValidIPAddress} from "../utils/IPAddress.js"; +import {isString} from "../utils/StringHelperFunctions.js"; + /* Evaluator * Evaluates the Abstract Syntax Tree for Netscript * generated by the Parser class @@ -20,7 +34,7 @@ function evaluate(exp, workerScript) { evaluateProgPromise.then(function(w) { resolve(workerScript); }, function(e) { - if (typeof e === 'string' || e instanceof String) { + if (isString(e)) { workerScript.errorMessage = e; reject(workerScript); } else if (e instanceof WorkerScript) { @@ -35,7 +49,7 @@ function evaluate(exp, workerScript) { break; case "Identifier": if (!(exp.name in env.vars)){ - reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not definied")); + reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not defined")); } resolve(env.get(exp.name)) break; @@ -172,7 +186,7 @@ function evaluate(exp, workerScript) { } resolve(env.get(exp.argument.name)) } else { - reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not definied")); + reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not defined")); } } else { reject(makeRuntimeRejectMsg(workerScript, "argument must be an identifier")); @@ -336,7 +350,7 @@ function evalAssignment(exp, workerScript) { } if (exp.operator !== "=" && !(exp.left.name in env.vars)){ - return reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not definied")); + return reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not defined")); } var expRightPromise = evaluate(exp.right, workerScript); @@ -347,7 +361,7 @@ function evalAssignment(exp, workerScript) { //Index designated by exp.left.property var name = exp.left.object.name; if (!(name in env.vars)){ - reject(makeRuntimeRejectMsg(workerScript, "variable " + name + " not definied")); + reject(makeRuntimeRejectMsg(workerScript, "variable " + name + " not defined")); } var arr = env.get(name); if (arr.constructor === Array || arr instanceof Array) { @@ -631,7 +645,8 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1) } function isScriptErrorMessage(msg) { - splitMsg = msg.split("|"); + if (!isString(msg)) {return false;} + let splitMsg = msg.split("|"); if (splitMsg.length != 4){ return false; } @@ -666,7 +681,7 @@ function scriptCalculateExpGain(server) { if (server.baseDifficulty == null) { server.baseDifficulty = server.hackDifficulty; } - return (server.baseDifficulty * Player.hacking_exp_mult * 0.3 + 3); + return (server.baseDifficulty * Player.hacking_exp_mult * 0.3 + 3) * BitNodeMultipliers.HackExpGain; } //The same as Player's calculatePercentMoneyHacked() function but takes in the server as an argument @@ -676,7 +691,7 @@ function scriptCalculatePercentMoneyHacked(server) { var percentMoneyHacked = difficultyMult * skillMult * Player.hacking_money_mult / 240; if (percentMoneyHacked < 0) {return 0;} if (percentMoneyHacked > 1) {return 1;} - return percentMoneyHacked; + return percentMoneyHacked * BitNodeMultipliers.ScriptHackMoney; } //Amount of time to execute grow() in milliseconds @@ -694,3 +709,9 @@ function scriptCalculateWeakenTime(server) { var weakenTime = 20 * skillFactor / Player.hacking_speed_mult; //This is in seconds return weakenTime * 1000; } + +export {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript, + scriptCalculateHackingChance, scriptCalculateHackingTime, + scriptCalculateExpGain, scriptCalculatePercentMoneyHacked, + scriptCalculateGrowTime, scriptCalculateWeakenTime, evaluate, + isScriptErrorMessage}; diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index 10d654a92..24066a1d0 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -1,3 +1,55 @@ +import {Augmentations, Augmentation, + augmentationExists, installAugmentations} from "./Augmentations.js"; +import {Companies, Company, CompanyPosition, + CompanyPositions, companyExists} from "./Company.js"; +import {CONSTANTS} from "./Constants.js"; +import {Programs} from "./CreateProgram.js"; +import {parseDarkwebItemPrice, DarkWebItems} from "./DarkWeb.js"; +import {Engine} from "./engine.js"; +import {Factions, Faction, joinFaction, + factionExists, purchaseAugmentation} from "./Faction.js"; +import {getCostOfNextHacknetNode, + purchaseHacknet} from "./HacknetNode.js"; +import {Locations} from "./Location.js"; +import {Player} from "./Player.js"; +import {Script, findRunningScript, RunningScript} from "./Script.js"; +import {Server, getServer, AddToAllServers, + AllServers, processSingleServerGrowth, + GetServerByHostname} from "./Server.js"; +import {Settings} from "./Settings.js"; +import {SpecialServerIps} from "./SpecialServerIps.js"; +import {StockMarket, StockSymbols, SymbolToStockMap, initStockSymbols, + initStockMarket, initSymbolToStockMap, stockMarketCycle, buyStock, + sellStock, updateStockPrices, displayStockMarketContent, + updateStockTicker, updateStockPlayerPosition, + Stock} from "./StockMarket.js"; +import {post} from "./Terminal.js"; + +import {WorkerScript, workerScripts, + killWorkerScript, NetscriptPorts} from "./NetscriptWorker.js"; +import {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript, + scriptCalculateHackingChance, scriptCalculateHackingTime, + scriptCalculateExpGain, scriptCalculatePercentMoneyHacked, + scriptCalculateGrowTime, scriptCalculateWeakenTime} from "./NetscriptEvaluator.js"; +import {Environment} from "./NetscriptEnvironment.js"; + +import Decimal from '../utils/decimal.js'; +import {printArray, powerOfTwo} from "../utils/HelperFunctions.js"; +import {createRandomIp} from "../utils/IPAddress.js"; +import {formatNumber, isString} from "../utils/StringHelperFunctions.js"; + +var hasSingularitySF = false; +var singularitySFLvl = 1; + +function initSingularitySFFlags() { + for (var i = 0; i < Player.sourceFiles.length; ++i) { + if (Player.sourceFiles[i].n === 4) { + hasSingularitySF = true; + singularitySFLvl = Player.sourceFiles[i].lvl; + } + } +} + function NetscriptFunctions(workerScript) { return { hacknetnodes : Player.hacknetNodes, @@ -172,6 +224,12 @@ function NetscriptFunctions(workerScript) { } workerScript.scriptRef.log(args.toString()); }, + tprint : function(args) { + if (args === undefined || args === null) { + throw makeRuntimeRejectMsg(workerScript, "tprint() call has incorrect number of arguments. Takes 1 argument"); + } + post(workerScript.scriptRef.filename + ": " + args.toString()); + }, clearLog : function() { workerScript.scriptRef.clearLog(); }, @@ -208,6 +266,7 @@ function NetscriptFunctions(workerScript) { throw makeRuntimeRejectMsg(workerScript, "Cannot call brutessh(). Invalid IP or hostname passed in: " + ip); } if (!Player.hasProgram(Programs.BruteSSHProgram)) { + workerScript.scriptRef.log("You do not have the BruteSSH.exe program!"); throw makeRuntimeRejectMsg(workerScript, "You do not have the BruteSSH.exe program!"); } if (!server.sshPortOpen) { @@ -864,7 +923,784 @@ function NetscriptFunctions(workerScript) { throw makeRuntimeRejectMsg(workerScript, "getWeakenTime() failed. Invalid IP or hostname passed in: " + ip); } return scriptCalculateWeakenTime(server) / 1000; //Returns seconds - } + }, + /* Singularity Functions */ + universityCourse(universityName, className) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 1)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run universityCourse(). It is a Singularity Function and requires SourceFile-4 (level 1) to run."); + return false; + } + } + if (Player.isWorking) { + var txt = Player.singularityStopWork(); + workerScript.scriptRef.log(txt); + } + + var costMult, expMult; + switch(universityName.toLowerCase()) { + case Locations.AevumSummitUniversity.toLowerCase(): + if (Player.city != Locations.Aevum) { + workerScript.scriptRef.log("ERROR: You cannot study at Summit University because you are not in Aevum. universityCourse() failed"); + return false; + } + costMult = 4; + expMult = 3; + break; + case Locations.Sector12RothmanUniversity.toLowerCase(): + if (Player.city != Locations.Sector12) { + workerScript.scriptRef.log("ERROR: You cannot study at Rothman University because you are not in Sector-12. universityCourse() failed"); + return false; + } + costMult = 3; + expMult = 2; + break; + case Locations.VolhavenZBInstituteOfTechnology.toLowerCase(): + if (Player.city != Locations.Volhaven) { + workerScript.scriptRef.log("ERROR: You cannot study at ZB Institute of Technology because you are not in Volhaven. universityCourse() failed"); + return false; + } + costMult = 5; + expMult = 4; + break; + default: + workerScript.scriptRef.log("Invalid university name: " + universityName + ". universityCourse() failed"); + return false; + } + + var task; + switch(className.toLowerCase()) { + case "Study Computer Science".toLowerCase(): + task = CONSTANTS.ClassStudyComputerScience; + break; + case "Data Structures".toLowerCase(): + task = CONSTANTS.ClassDataStructures; + break; + case "Networks".toLowerCase(): + task = CONSTANTS.ClassNetworks; + break; + case "Algorithms".toLowerCase(): + task = CONSTANTS.ClassAlgorithms; + break; + case "Management".toLowerCase(): + task = CONSTANTS.ClassManagement; + break; + case "Leadership".toLowerCase(): + task = CONSTANTS.ClassLeadership; + break; + default: + workerScript.scriptRef.log("Invalid class name: " + className + ". universityCourse() failed"); + return false; + } + Player.startClass(costMult, expMult, task); + workerScript.scriptRef.log("Started " + task + " at " + universityName); + return true; + }, + + gymWorkout(gymName, stat) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 1)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run gymWorkout(). It is a Singularity Function and requires SourceFile-4 (level 1) to run."); + return false; + } + } + if (Player.isWorking) { + var txt = Player.singularityStopWork(); + workerScript.scriptRef.log(txt); + } + var costMult, expMult; + switch(gymName.toLowerCase()) { + case Locations.AevumCrushFitnessGym.toLowerCase(): + if (Player.city != Locations.Aevum) { + workerScript.scriptRef.log("ERROR: You cannot workout at Crush Fitness because you are not in Aevum. gymWorkout() failed"); + return false; + } + costMult = 2; + expMult = 1.5; + break; + case Locations.AevumSnapFitnessGym.toLowerCase(): + if (Player.city != Locations.Aevum) { + workerScript.scriptRef.log("ERROR: You cannot workout at Snap Fitness because you are not in Aevum. gymWorkout() failed"); + return false; + } + costMult = 6; + expMult = 4; + break; + case Locations.Sector12IronGym.toLowerCase(): + if (Player.city != Locations.Sector12) { + workerScript.scriptRef.log("ERROR: You cannot workout at Iron Gym because you are not in Sector-12. gymWorkout() failed"); + return false; + } + costMult = 1; + expMult = 1; + break; + case Locations.Sector12PowerhouseGym.toLowerCase(): + if (Player.city != Locations.Sector12) { + workerScript.scriptRef.log("ERROR: You cannot workout at Powerhouse Gym because you are not in Sector-12. gymWorkout() failed"); + return false; + } + costMult = 10; + expMult = 7.5; + break; + case Locations.VolhavenMilleniumFitnessGym: + if (Player.city != Locations.Volhaven) { + workerScript.scriptRef.log("ERROR: You cannot workout at Millenium Fitness Gym because you are not in Volhaven. gymWorkout() failed"); + return false; + } + costMult = 3; + expMult = 2.5; + break; + default: + workerScript.scriptRef.log("Invalid gym name: " + gymName + ". gymWorkout() failed"); + return false; + } + + switch(stat.toLowerCase()) { + case "strength".toLowerCase(): + case "str".toLowerCase(): + Player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength); + break; + case "defense".toLowerCase(): + case "def".toLowerCase(): + Player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense); + break; + case "dexterity".toLowerCase(): + case "dex".toLowerCase(): + Player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity); + break; + case "agility".toLowerCase(): + case "agi".toLowerCase(): + Player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility); + break; + default: + workerScript.scriptRef.log("Invalid stat: " + stat + ". gymWorkout() failed"); + return false; + } + workerScript.scriptRef.log("Started training " + stat + " at " + gymName); + return true; + }, + + travelToCity(cityname) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 1)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run travelToCity(). It is a Singularity Function and requires SourceFile-4 (level 1) to run."); + return false; + } + } + + switch(cityname) { + case Locations.Aevum: + case Locations.Chongqing: + case Locations.Sector12: + case Locations.NewTokyo: + case Locations.Ishima: + case Locations.Volhaven: + Player.loseMoney(200000); + Player.city = cityname; + workerScript.scriptRef.log("Traveled to " + cityname); + return true; + default: + workerScript.scriptRef.log("ERROR: Invalid city name passed into travelToCity()."); + return false; + } + }, + + purchaseTor() { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 1)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run purchaseTor(). It is a Singularity Function and requires SourceFile-4 (level 1) to run."); + return false; + } + } + + if (SpecialServerIps["Darkweb Server"] != null) { + workerScript.scriptRef.log("You already have a TOR router! purchaseTor() failed"); + return false; + } + + if (Player.money.lt(CONSTANTS.TorRouterCost)) { + workerScript.scriptRef.log("ERROR: You cannot afford to purchase a Tor router. purchaseTor() failed"); + return false; + } + Player.loseMoney(CONSTANTS.TorRouterCost); + + var darkweb = new Server(createRandomIp(), "darkweb", "", false, false, false, 1); + AddToAllServers(darkweb); + SpecialServerIps.addIp("Darkweb Server", darkweb.ip); + + document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button-inactive"); + + Player.getHomeComputer().serversOnNetwork.push(darkweb.ip); + darkweb.serversOnNetwork.push(Player.getHomeComputer().ip); + workerScript.scriptRef.log("You have purchased a Tor router!"); + return true; + }, + purchaseProgram(programName) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 1)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run purchaseProgram(). It is a Singularity Function and requires SourceFile-4 (level 1) to run."); + return false; + } + } + + if (SpecialServerIps["Darkweb Server"] == null) { + workerScript.scriptRef.log("ERROR: You do not have TOR router. purchaseProgram() failed."); + return false; + } + + switch(programName.toLowerCase()) { + case Programs.BruteSSHProgram.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.BruteSSHProgram); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.BruteSSHProgram); + workerScript.scriptRef.log("You have purchased the BruteSSH.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + programName); + } + return true; + case Programs.FTPCrackProgram.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.FTPCrackProgram); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.FTPCrackProgram); + workerScript.scriptRef.log("You have purchased the FTPCrack.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + itemName); + } + return true; + case Programs.RelaySMTPProgram.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.RelaySMTPProgram); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.RelaySMTPProgram); + workerScript.scriptRef.log("You have purchased the relaySMTP.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + itemName); + } + return true; + case Programs.HTTPWormProgram.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.HTTPWormProgram); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.HTTPWormProgram); + workerScript.scriptRef.log("You have purchased the HTTPWorm.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + itemName); + } + return true; + case Programs.SQLInjectProgram.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.SQLInjectProgram); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.SQLInjectProgram); + workerScript.scriptRef.log("You have purchased the SQLInject.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + itemName); + } + return true; + case Programs.DeepscanV1.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.DeepScanV1Program); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.DeepscanV1); + workerScript.scriptRef.log("You have purchased the DeepscanV1.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + itemName); + } + return true; + case Programs.DeepscanV2.toLowerCase(): + var price = parseDarkwebItemPrice(DarkWebItems.DeepScanV2Program); + if (price > 0 && Player.money.gt(price)) { + Player.loseMoney(price); + Player.getHomeComputer().programs.push(Programs.DeepscanV2); + workerScript.scriptRef.log("You have purchased the DeepscanV2.exe program. The new program " + + "can be found on your home computer."); + } else { + workerScript.scriptRef.log("Not enough money to purchase " + itemName); + } + return true; + default: + workerScript.scriptRef.log("ERROR: Invalid program passed into purchaseProgram()."); + return false; + } + return true; + }, + upgradeHomeRam() { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run upgradeHomeRam(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + //Calculate how many times ram has been upgraded (doubled) + var currentRam = Player.getHomeComputer().maxRam; + var numUpgrades = Math.log2(currentRam); + + //Calculate cost + //Have cost increase by some percentage each time RAM has been upgraded + var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome; + var mult = Math.pow(1.55, numUpgrades); + cost = cost * mult; + + if (Player.money.lt(cost)) { + workerScript.scriptRef.log("ERROR: upgradeHomeRam() failed because you don't have enough money"); + return false; + } + + var homeComputer = Player.getHomeComputer(); + homeComputer.maxRam *= 2; + + Player.loseMoney(cost); + + workerScript.scriptRef.log("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM."); + return true; + }, + getUpgradeHomeRamCost() { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run getUpgradeHomeRamCost(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + //Calculate how many times ram has been upgraded (doubled) + var currentRam = Player.getHomeComputer().maxRam; + var numUpgrades = Math.log2(currentRam); + + //Calculate cost + //Have cost increase by some percentage each time RAM has been upgraded + var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome; + var mult = Math.pow(1.55, numUpgrades); + return cost * mult; + }, + workForCompany() { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run workForCompany(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + if (Player.companyPosition == "" || !(Player.companyPosition instanceof CompanyPosition)) { + workerScript.scriptRef.log("ERROR: workForCompany() failed because you do not have a job"); + return false; + } + + if (Player.isWorking) { + var txt = Player.singularityStopWork(); + workerScript.scriptRef.log(txt); + } + + if (Player.companyPosition.isPartTimeJob()) { + Player.startWorkPartTime(); + } else { + Player.startWork(); + } + workerScript.scriptRef.log("Began working at " + Player.companyName + " as a " + Player.companyPosition.positionName); + return true; + }, + applyToCompany(companyName, field) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run applyToCompany(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + if (!companyExists(companyName)) { + workerScript.scriptRef.log("ERROR: applyToCompany() failed because specified company " + companyName + " does not exist."); + return false; + } + + Player.location = companyName; + var res; + switch (field.toLowerCase()) { + case "software": + res = Player.applyForSoftwareJob(true); + break; + case "software consultant": + res = Player.applyForSoftwareConsultantJob(true); + break; + case "it": + res = Player.applyForItJob(true); + break; + case "security engineer": + res = Player.applyForSecurityEngineerJob(true); + break; + case "network engineer": + res = Player.applyForNetworkEngineerJob(true); + break; + case "business": + res = Player.applyForBusinessJob(true); + break; + case "business consultant": + res = Player.applyForBusinessConsultantJob(true); + break; + case "security": + res = Player.applyForSecurityJob(true); + break; + case "agent": + res = Player.applyForAgentJob(true); + break; + case "employee": + res = Player.applyForEmployeeJob(true); + break; + case "part-time employee": + res = Player.applyForPartTimeEmployeeJob(true); + break; + case "waiter": + res = Player.applyForWaiterJob(true); + break; + case "part-time waiter": + res = Player.applyForPartTimeWaiterJob(true); + break; + default: + workerScript.scriptRef.log("ERROR: Invalid job passed into applyToCompany: " + field + ". applyToCompany() failed"); + return false; + } + //The Player object's applyForJob function can return string with special error messages + if (isString(res)) { + workerScript.scriptRef.log(res); + return false; + } + if (res) { + workerScript.scriptRef.log("You were offered a new job at " + companyName + " as a " + Player.companyPosition.positionName); + } else { + workerScript.scriptRef.log("You failed to get a new job/promotion at " + companyName + " in the " + field + " field."); + } + return res; + }, + getCompanyRep(companyName) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run getCompanyRep(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + var company = Companies[companyName]; + if (company === null || !(company instanceof Company)) { + workerScript.scriptRef.log("ERROR: Invalid companyName passed into getCompanyRep(): " + companyName); + return -1; + } + return company.playerReputation; + }, + checkFactionInvitations() { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run checkFactionInvitations(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + //Make a copy of Player.factionInvitations + return Player.factionInvitations.slice(); + }, + joinFaction(name) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run joinFaction(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + if (!factionExists(name)) { + workerScript.scriptRef.log("ERROR: Faction specified in joinFaction() does not exist."); + return false; + } + + if (!Player.factionInvitations.includes(name)) { + workerScript.scriptRef.log("ERROR: Cannot join " + name + " Faction because you have not been invited. joinFaction() failed"); + return false; + } + + var index = Player.factionInvitations.indexOf(name); + if (index === -1) { + //Redundant and should never happen... + workerScript.scriptRef.log("ERROR: Cannot join " + name + " Faction because you have not been invited. joinFaction() failed"); + return false; + } + Player.factionInvitations.splice(index, 1); + var fac = Factions[name]; + joinFaction(fac); + workerScript.scriptRef.log("Joined the " + name + " faction."); + return true; + }, + workForFaction(name, type) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run workForFaction(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return false; + } + } + + if (!factionExists(name)) { + workerScript.scriptRef.log("ERROR: Faction specified in workForFaction() does not exist."); + return false; + } + + if (!Player.factions.includes(name)) { + workerScript.scriptRef.log("ERROR: workForFaction() failed because you are not a member of " + name); + return false; + } + + if (Player.isWorking) { + var txt = Player.singularityStopWork(); + workerScript.scriptRef.log(txt); + } + + var fac = Factions[name]; + //Arrays listing factions that allow each time of work + var hackAvailable = ["Illuminati", "Daedalus", "The Covenant", "ECorp", "MegaCorp", + "Bachman & Associates", "Blade Industries", "NWO", "Clarke Incorporated", + "OmniTek Incorporated", "Four Sigma", "KuaiGong International", + "Fulcrum Secret Technologies", "BitRunners", "The Black Hand", + "NiteSec", "Chongqing", "Sector-12", "New Tokyo", "Aevum", + "Ishima", "Volhaven", "Speakers for the Dead", "The Dark Army", + "The Syndicate", "Silhouette", "Netburners", "Tian Di Hui", "CyberSec"]; + var fdWkAvailable = ["Illuminati", "Daedalus", "The Covenant", "ECorp", "MegaCorp", + "Bachman & Associates", "Blade Industries", "NWO", "Clarke Incorporated", + "OmniTek Incorporated", "Four Sigma", "KuaiGong International", + "The Black Hand", "Chongqing", "Sector-12", "New Tokyo", "Aevum", + "Ishima", "Volhaven", "Speakers for the Dead", "The Dark Army", + "The Syndicate", "Silhouette", "Tetrads", "Slum Snakes"]; + var scWkAvailable = ["ECorp", "MegaCorp", + "Bachman & Associates", "Blade Industries", "NWO", "Clarke Incorporated", + "OmniTek Incorporated", "Four Sigma", "KuaiGong International", + "Fulcrum Secret Technologies", "Chongqing", "Sector-12", "New Tokyo", "Aevum", + "Ishima", "Volhaven", "Speakers for the Dead", + "The Syndicate", "Tetrads", "Slum Snakes", "Tian Di Hui"]; + + switch (type.toLowerCase()) { + case "hacking": + case "hacking contracts": + case "hackingcontracts": + if (!hackAvailable.includes(fac.name)) { + workerScript.scriptRef.log("ERROR: Cannot carry out hacking contracts for " + fac.name + ". workForFaction() failed"); + return false; + } + Player.startFactionHackWork(fac); + workerScript.scriptRef.log("Started carrying out hacking contracts for " + fac.name); + return true; + case "field": + case "fieldwork": + case "field work": + if (!fdWkAvailable.includes(fac.name)) { + workerScript.scriptRef.log("ERROR: Cannot carry out field missions for " + fac.name + ". workForFaction() failed"); + return false; + } + Player.startFactionFieldWork(fac); + workerScript.scriptRef.log("Started carrying out field missions for " + fac.name); + return true; + case "security": + case "securitywork": + case "security work": + if (!scWkAvailable.includes(fac.name)) { + workerScript.scriptRef.log("ERROR: Cannot serve as security detail for " + fac.name + ". workForFaction() failed"); + return false; + } + Player.startFactionSecurityWork(fac); + workerScript.scriptRef.log("Started serving as security details for " + fac.name); + return true; + default: + workerScript.scriptRef.log("ERROR: Invalid work type passed into workForFaction(): " + type); + } + return true; + }, + getFactionRep(name) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 2)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run getFactionRep(). It is a Singularity Function and requires SourceFile-4 (level 2) to run."); + return -1; + } + } + + if (!factionExists(name)) { + workerScript.scriptRef.log("ERROR: Faction specified in getFactionRep() does not exist."); + return -1; + } + + return Factions[name].playerReputation; + }, + createProgram(name) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 3)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run createProgram(). It is a Singularity Function and requires SourceFile-4 (level 3) to run."); + return false; + } + } + + if (Player.isWorking) { + var txt = Player.singularityStopWork(); + workerScript.scriptRef.log(txt); + } + + switch(name.toLowerCase()) { + case Programs.NukeProgram.toLowerCase(): + Player.startCreateProgramWork(Programs.NukeProgram, CONSTANTS.MillisecondsPerFiveMinutes, 1); + break; + case Programs.BruteSSHProgram.toLowerCase(): + if (Player.hacking_skill < 50) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create BruteSSH (level 50 req)"); + return false; + } + Player.startCreateProgramWork(Programs.BruteSSHProgram, CONSTANTS.MillisecondsPerFiveMinutes * 2, 50); + break; + case Programs.FTPCrackProgram.toLowerCase(): + if (Player.hacking_skill < 100) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create FTPCrack (level 100 req)"); + return false; + } + Player.startCreateProgramWork(Programs.FTPCrackProgram, CONSTANTS.MillisecondsPerHalfHour, 100); + break; + case Programs.RelaySMTPProgram.toLowerCase(): + if (Player.hacking_skill < 250) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create relaySMTP (level 250 req)"); + return false; + } + Player.startCreateProgramWork(Programs.RelaySMTPProgram, CONSTANTS.MillisecondsPer2Hours, 250); + break; + case Programs.HTTPWormProgram.toLowerCase(): + if (Player.hacking_skill < 500) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create HTTPWorm (level 500 req)"); + return false; + } + Player.startCreateProgramWork(Programs.HTTPWormProgram, CONSTANTS.MillisecondsPer4Hours, 500); + break; + case Programs.SQLInjectProgram.toLowerCase(): + if (Player.hacking_skill < 750) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create SQLInject (level 750 req)"); + return false; + } + Player.startCreateProgramWork(Programs.SQLInjectProgram, CONSTANTS.MillisecondsPer8Hours, 750); + break; + case Programs.DeepscanV1.toLowerCase(): + if (Player.hacking_skill < 75) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create DeepscanV1 (level 75 req)"); + return false; + } + Player.startCreateProgramWork(Programs.DeepscanV1, CONSTANTS.MillisecondsPerQuarterHour, 75); + break; + case Programs.DeepscanV2.toLowerCase(): + if (Player.hacking_skill < 400) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create DeepscanV2 (level 400 req)"); + return false; + } + Player.startCreateProgramWork(Programs.DeepscanV2, CONSTANTS.MillisecondsPer2Hours, 400); + break; + case Programs.ServerProfiler.toLowerCase(): + if (Player.hacking_skill < 75) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create ServerProfiler (level 75 req)"); + return false; + } + Player.startCreateProgramWork(Programs.ServerProfiler, CONSTANTS.MillisecondsPerHalfHour, 75); + break; + case Programs.AutoLink.toLowerCase(): + if (Player.hacking_skill < 25) { + workerScript.scriptRef.log("ERROR: createProgram() failed because hacking level is too low to create AutoLink (level 25 req)"); + return false; + } + Player.startCreateProgramWork(Programs.AutoLink, CONSTANTS.MillisecondsPerQuarterHour, 25); + break; + default: + workerScript.scriptRef.log("ERROR: createProgram() failed because the specified program does not exist: " + name); + return false; + } + workerScript.scriptRef.log("Began creating program: " + name); + return true; + }, + getAugmentationCost(name) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 3)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run getAugmentationCost(). It is a Singularity Function and requires SourceFile-4 (level 3) to run."); + return false; + } + } + + if (!augmentationExists(name)) { + workerScript.scriptRef.log("ERROR: getAugmentationCost() failed. Invalid Augmentation name passed in (note: this is case-sensitive): " + name); + return [-1, -1]; + } + + var aug = Augmentations[name]; + return [aug.baseRepRequirement, aug.baseCost]; + }, + purchaseAugmentation(faction, name) { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 3)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run purchaseAugmentation(). It is a Singularity Function and requires SourceFile-4 (level 3) to run."); + return false; + } + } + + var fac = Factions[faction]; + if (fac === null || !(fac instanceof Faction)) { + workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because of invalid faction name: " + faction); + return false; + } + + if (!fac.augmentations.includes(name)) { + workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because the faction " + faction + " does not contain the " + name + " augmentation"); + return false; + } + + var aug = Augmentations[name]; + if (aug === null || !(aug instanceof Augmentation)) { + workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because of invalid augmentation name: " + name); + return false; + } + + for (var j = 0; j < Player.queuedAugmentations.length; ++j) { + if (Player.queuedAugmentations[j].name === aug.name) { + workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name); + return false; + } + } + for (var j = 0; j < Player.augmentations.length; ++j) { + if (Player.augmentations[j].name === aug.name) { + workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name); + return false; + } + } + + if (fac.playerReputation < aug.baseRepRequirement) { + workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you do not have enough reputation with " + fac.name); + return false; + } + + var res = purchaseAugmentation(aug, fac, true); + workerScript.scriptRef.log(res); + if (isString(res) && res.startsWith("You purchased")) { + return true; + } else { + return false; + } + }, + installAugmentations() { + if (Player.bitNodeN != 4) { + if (!(hasSingularitySF && singularitySFLvl >= 3)) { + throw makeRuntimeRejectMsg(workerScript, "Cannot run installAugmentations(). It is a Singularity Function and requires SourceFile-4 (level 3) to run."); + return false; + } + } + + if (Player.queuedAugmentations.length === 0) { + workerScript.scriptRef.log("ERROR: installAugmentations() failed because you do not have any Augmentations to be installed"); + return false; + } + workerScript.scriptRef.log("Installing Augmentations. This will cause this script to be killed"); + installAugmentations(); + return true; + } } } + +export {NetscriptFunctions, initSingularitySFFlags, hasSingularitySF}; diff --git a/src/NetscriptWorker.js b/src/NetscriptWorker.js index 9746760a2..b91cf34d2 100644 --- a/src/NetscriptWorker.js +++ b/src/NetscriptWorker.js @@ -1,8 +1,18 @@ -/* Worker code, contains Netscript scripts that are actually running */ +import {addActiveScriptsItem, + deleteActiveScriptsItem, + updateActiveScriptsItems} from "./ActiveScriptsUI.js"; +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {Environment} from "./NetscriptEnvironment.js"; +import {evaluate, isScriptErrorMessage} from "./NetscriptEvaluator.js"; +import {AllServers} from "./Server.js"; +import {Settings} from "./Settings.js"; + +import {parse} from "../utils/acorn.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {compareArrays, printArray} from "../utils/HelperFunctions.js"; -//TODO Tested For and while and generic call statements. Have not tested if statements -/* Actual Worker Code */ function WorkerScript(runningScriptObj) { this.name = runningScriptObj.filename; this.running = false; @@ -23,9 +33,9 @@ WorkerScript.prototype.getServer = function() { } //Array containing all scripts that are running across all servers, to easily run them all -var workerScripts = []; +let workerScripts = []; -var NetscriptPorts = { +let NetscriptPorts = { Port1: [], Port2: [], Port3: [], @@ -38,6 +48,14 @@ var NetscriptPorts = { Port10: [], } +function prestigeWorkerScripts() { + for (var i = 0; i < workerScripts.length; ++i) { + deleteActiveScriptsItem(workerScripts[i]); + workerScripts[i].env.stopFlag = true; + } + workerScripts.length = 0; +} + //Loop through workerScripts and run every script that is not currently running function runScriptsLoop() { //Run any scripts that haven't been started @@ -45,7 +63,7 @@ function runScriptsLoop() { //If it isn't running, start the script if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == false) { try { - var ast = acorn.parse(workerScripts[i].code); + var ast = parse(workerScripts[i].code); //console.log(ast); } catch (e) { console.log("Error parsing script: " + workerScripts[i].name); @@ -64,9 +82,10 @@ function runScriptsLoop() { w.env.stopFlag = true; w.scriptRef.log("Script finished running"); }, function(w) { + //console.log(w); if (w instanceof Error) { dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); - console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN"); + console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + w.toString()); return; } else if (w instanceof WorkerScript) { if (isScriptErrorMessage(w.errorMessage)) { @@ -92,7 +111,7 @@ function runScriptsLoop() { } else if (isScriptErrorMessage(w)) { dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); - console.log("ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN"); + console.log("ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN: " + w.toString()); return; } else { dialogBoxCreate("An unknown script died for an unknown reason. This is a bug please contact game dev"); @@ -182,4 +201,6 @@ function updateOnlineScriptTimes(numCycles = 1) { } } -runScriptsLoop(); +export {WorkerScript, workerScripts, NetscriptPorts, runScriptsLoop, + killWorkerScript, addWorkerScript, updateOnlineScriptTimes, + prestigeWorkerScripts}; diff --git a/src/Player.js b/src/Player.js index 6e1d1b4e8..8293d7d28 100644 --- a/src/Player.js +++ b/src/Player.js @@ -1,4 +1,29 @@ -//Netburner Player class +import {Augmentations, applyAugmentation, + AugmentationNames} from "./Augmentations.js"; +import {BitNodes, BitNode, BitNodeMultipliers} from "./BitNode.js"; +import {Company, Companies, getNextCompanyPosition, + getJobRequirementText, CompanyPosition, + CompanyPositions} from "./Company.js"; +import {CONSTANTS} from "./Constants.js"; +import {Programs} from "./CreateProgram.js"; +import {determineCrimeSuccess} from "./Crimes.js"; +import {Engine} from "./engine.js"; +import {Factions, Faction} from "./Faction.js"; +import {Gang} from "./Gang.js"; +import {Locations} from "./Location.js"; +import {AllServers, Server, AddToAllServers} from "./Server.js"; +import {SpecialServerIps, SpecialServerNames} from "./SpecialServerIps.js"; +import {SourceFiles, applySourceFile} from "./SourceFile.js"; + +import Decimal from '../utils/decimal.js'; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {createRandomIp} from "../utils/IPAddress.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {formatNumber, + convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js"; + function PlayerObject() { //Skills and stats this.hacking_skill = 1; @@ -80,15 +105,8 @@ function PlayerObject() { this.sourceFiles = []; //Crime statistics + this.numPeopleKilled = 0; this.karma = 0; - this.numTimesShoplifted = 0; - this.numPeopleMugged = 0; - this.numTimesDealtDrugs = 0; - this.numTimesTraffickArms = 0; - this.numPeopleKilled = 0; - this.numTimesGrandTheftAuto = 0; - this.numTimesKidnapped = 0; - this.numTimesHeist = 0; this.crime_money_mult = 1; this.crime_success_mult = 1; @@ -147,11 +165,18 @@ function PlayerObject() { this.hasTixApiAccess = false; //Gang - this.gang = null; + this.gang = 0; //bitnode this.bitNodeN = 1; + //Flags for determining whether certain "thresholds" have been achieved + this.firstFacInvRecvd = false; + this.firstAugPurchased = false; + this.firstJobRecvd = false; + this.firstTimeTraveled = false; + this.firstProgramAvailable = false; + //Used to store the last update time. this.lastUpdate = 0; this.totalPlaytime = 0; @@ -168,6 +193,181 @@ PlayerObject.prototype.init = function() { this.getHomeComputer().programs.push(Programs.NukeProgram); } +PlayerObject.prototype.increaseMultiplier = function(name, val) { + let mult = this[name]; + if (mult === null || mult === undefined) { + console.log("ERROR: Could not find this multiplier " + name); + return; + } + mult *= val; +} + +PlayerObject.prototype.prestigeAugmentation = function() { + var homeComp = this.getHomeComputer(); + this.currentServer = homeComp.ip; + this.homeComputer = homeComp.ip; + + this.numPeopleKilled = 0; + this.karma = 0; + + //Reset stats + this.hacking_skill = 1; + + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + this.charisma = 1; + + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.money = new Decimal(1000); + + this.city = Locations.Sector12; + this.location = ""; + + this.companyName = ""; + this.companyPosition = ""; + + this.discoveredServers = []; + this.purchasedServers = []; + + this.factions = []; + this.factionInvitations = []; + + this.queuedAugmentations = []; + + this.startAction = false; + this.actionTime = 0; + + this.isWorking = false; + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + this.crimeType = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.lastUpdate = new Date().getTime(); + + this.playtimeSinceLastAug = 0; + + this.hacknetNodes.length = 0; + this.totalHacknetNodeProduction = 0; +} + +PlayerObject.prototype.prestigeSourceFile = function() { + var homeComp = this.getHomeComputer(); + this.currentServer = homeComp.ip; + this.homeComputer = homeComp.ip; + + this.numPeopleKilled = 0; + this.karma = 0; + + //Reset stats + this.hacking_skill = 1; + + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + this.charisma = 1; + + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.money = new Decimal(1000); + + this.city = Locations.Sector12; + this.location = ""; + + this.companyName = ""; + this.companyPosition = ""; + + this.discoveredServers = []; + this.purchasedServers = []; + + this.factions = []; + this.factionInvitations = []; + + this.queuedAugmentations = []; + this.augmentations = []; + + this.startAction = false; + this.actionTime = 0; + + this.isWorking = false; + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + this.crimeType = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.lastUpdate = new Date().getTime(); + + this.hacknetNodes.length = 0; + this.totalHacknetNodeProduction = 0; + + //Gang + this.gang = null; + + //Reset Stock market + this.hasWseAccount = false; + this.hasTixApiAccess = false; + + this.playtimeSinceLastAug = 0; +} + PlayerObject.prototype.getCurrentServer = function() { return AllServers[this.currentServer]; } @@ -269,7 +469,7 @@ PlayerObject.prototype.calculatePercentMoneyHacked = function() { console.log("Percent money hacked calculated to be: " + percentMoneyHacked); if (percentMoneyHacked < 0) {return 0;} if (percentMoneyHacked > 1) {return 1;} - return percentMoneyHacked; + return percentMoneyHacked * BitNodeMultipliers.ManualHackMoney; } //Returns how much EXP the player gains on a successful hack @@ -280,7 +480,7 @@ PlayerObject.prototype.calculateExpGain = function() { if (s.baseDifficulty == null) { s.baseDifficulty = s.hackDifficulty; } - return (s.baseDifficulty * this.hacking_exp_mult * 0.3 + 3); + return (s.baseDifficulty * this.hacking_exp_mult * 0.3 + 3) * BitNodeMultipliers.HackExpGain; } //Hack/Analyze a server. Return the amount of time the hack will take. This lets the Terminal object know how long to disable itself for @@ -305,6 +505,13 @@ PlayerObject.prototype.hasProgram = function(programName) { return false; } +PlayerObject.prototype.setMoney = function(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.setMoney()"); return; + } + this.money = money; +} + PlayerObject.prototype.gainMoney = function(money) { if (isNaN(money)) { console.log("ERR: NaN passed into Player.gainMoney()"); return; @@ -403,7 +610,7 @@ PlayerObject.prototype.gainWorkExp = function() { } /* Working for Company */ -PlayerObject.prototype.finishWork = function(cancelled) { +PlayerObject.prototype.finishWork = function(cancelled, sing=false) { //Since the work was cancelled early, player only gains half of what they've earned so far if (cancelled) { this.workRepGained /= 2; @@ -435,12 +642,24 @@ PlayerObject.prototype.finishWork = function(cancelled) { txt = "You worked a full shift of 8 hours!

" + "You earned a total of:
" + txt; } - dialogBoxCreate(txt); + if (!sing) {dialogBoxCreate(txt);} var mainMenu = document.getElementById("mainmenu-container"); mainMenu.style.visibility = "visible"; this.isWorking = false; Engine.loadTerminalContent(); + + if (sing) { + return "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + + "earned $" + formatNumber(this.workMoneyGained, 2) + ", " + + formatNumber(this.workRepGained, 4) + " reputation, " + + formatNumber(this.workHackExpGained, 4) + " hacking exp, " + + formatNumber(this.workStrExpGained, 4) + " strength exp, " + + formatNumber(this.workDefExpGained, 4) + " defense exp, " + + formatNumber(this.workDexExpGained, 4) + " dexterity exp, " + + formatNumber(this.workAgiExpGained, 4) + " agility exp, and " + + formatNumber(this.workChaExpGained, 4) + " charisma exp."; + } } PlayerObject.prototype.startWork = function() { @@ -596,7 +815,7 @@ PlayerObject.prototype.workPartTime = function(numCycles) { } -PlayerObject.prototype.finishWorkPartTime = function() { +PlayerObject.prototype.finishWorkPartTime = function(sing=false) { this.gainWorkExp(); var company = Companies[this.companyName]; @@ -616,16 +835,28 @@ PlayerObject.prototype.finishWorkPartTime = function() { formatNumber(this.workAgiExpGained, 4) + " agility exp
" + formatNumber(this.workChaExpGained, 4) + " charisma exp
"; txt = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

" + txt; - dialogBoxCreate(txt); + if (!sing) {dialogBoxCreate(txt);} var mainMenu = document.getElementById("mainmenu-container"); mainMenu.style.visibility = "visible"; this.isWorking = false; Engine.loadTerminalContent(); + if (sing) { + return "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + + "earned a total of " + + "$" + formatNumber(this.workMoneyGained, 2) + ", " + + formatNumber(this.workRepGained, 4) + " reputation, " + + formatNumber(this.workHackExpGained, 4) + " hacking exp, " + + formatNumber(this.workStrExpGained, 4) + " strength exp, " + + formatNumber(this.workDefExpGained, 4) + " defense exp, " + + formatNumber(this.workDexExpGained, 4) + " dexterity exp, " + + formatNumber(this.workAgiExpGained, 4) + " agility exp, and " + + formatNumber(this.workChaExpGained, 4) + " charisma exp"; + } } /* Working for Faction */ -PlayerObject.prototype.finishFactionWork = function(cancelled, faction) { +PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) { this.gainWorkExp(); var faction = Factions[this.currentWorkFactionName]; @@ -645,7 +876,7 @@ PlayerObject.prototype.finishFactionWork = function(cancelled, faction) { formatNumber(this.workDexExpGained, 4) + " dexterity exp
" + formatNumber(this.workAgiExpGained, 4) + " agility exp
" + formatNumber(this.workChaExpGained, 4) + " charisma exp
"; - dialogBoxCreate(txt); + if (!sing) {dialogBoxCreate(txt);} var mainMenu = document.getElementById("mainmenu-container"); mainMenu.style.visibility = "visible"; @@ -653,6 +884,17 @@ PlayerObject.prototype.finishFactionWork = function(cancelled, faction) { this.isWorking = false; Engine.loadTerminalContent(); + if (sing) { + return "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " + + "You earned " + + formatNumber(this.workRepGained, 4) + " rep, " + + formatNumber(this.workHackExpGained, 4) + " hacking exp, " + + formatNumber(this.workStrExpGained, 4) + " str exp, " + + formatNumber(this.workDefExpGained, 4) + " def exp, " + + formatNumber(this.workDexExpGained, 4) + " dex exp, " + + formatNumber(this.workAgiExpGained, 4) + " agi exp, and " + + formatNumber(this.workChaExpGained, 4) + " cha exp."; + } } PlayerObject.prototype.startFactionWork = function(faction) { @@ -671,7 +913,7 @@ PlayerObject.prototype.startFactionWork = function(faction) { var cancelButton = clearEventListeners("work-in-progress-cancel-button"); cancelButton.innerHTML = "Stop Faction Work"; cancelButton.addEventListener("click", function() { - Player.finishFactionWork(true, faction); + Player.finishFactionWork(true); return false; }); @@ -682,8 +924,8 @@ PlayerObject.prototype.startFactionWork = function(faction) { PlayerObject.prototype.startFactionHackWork = function(faction) { this.resetWorkStatus(); - this.workHackExpGainRate = .15 * this.hacking_exp_mult; - this.workRepGainRate = 0.9 * this.hacking_skill / CONSTANTS.MaxSkillLevel * this.faction_rep_mult; + this.workHackExpGainRate = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workRepGainRate = this.hacking_skill / CONSTANTS.MaxSkillLevel * this.faction_rep_mult; this.factionWorkType = CONSTANTS.FactionWorkHacking; this.currentWorkFactionDescription = "carrying out hacking contracts"; @@ -694,12 +936,12 @@ PlayerObject.prototype.startFactionHackWork = function(faction) { PlayerObject.prototype.startFactionFieldWork = function(faction) { this.resetWorkStatus(); - this.workHackExpGainRate = .1 * this.hacking_exp_mult; - this.workStrExpGainRate = .1 * this.strength_exp_mult; - this.workDefExpGainRate = .1 * this.defense_exp_mult; - this.workDexExpGainRate = .1 * this.dexterity_exp_mult; - this.workAgiExpGainRate = .1 * this.agility_exp_mult; - this.workChaExpGainRate = .1 * this.charisma_exp_mult; + this.workHackExpGainRate = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workStrExpGainRate = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDefExpGainRate = .1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workRepGainRate = this.getFactionFieldWorkRepGain(); this.factionWorkType = CONSTANTS.FactionWorkField; @@ -711,12 +953,12 @@ PlayerObject.prototype.startFactionFieldWork = function(faction) { PlayerObject.prototype.startFactionSecurityWork = function(faction) { this.resetWorkStatus(); - this.workHackExpGainRate = 0.05 * this.hacking_exp_mult; - this.workStrExpGainRate = 0.15 * this.strength_exp_mult; - this.workDefExpGainRate = 0.15 * this.defense_exp_mult; - this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult; - this.workAgiExpGainRate = 0.15 * this.agility_exp_mult; - this.workChaExpGainRate = 0.00 * this.charisma_exp_mult; + this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDefExpGainRate = 0.15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workRepGainRate = this.getFactionSecurityWorkRepGain(); this.factionWorkType = CONSTANTS.FactionWorkSecurity; @@ -773,7 +1015,7 @@ PlayerObject.prototype.workForFaction = function(numCycles) { this.workChaExpGained = this.workChaExpGainRate * maxCycles; this.workRepGained = this.workRepGainRate * maxCycles; this.workMoneyGained = this.workMoneyGainRate * maxCycles; - this.finishFactionWork(false, faction); + this.finishFactionWork(false); } var txt = document.getElementById("work-in-progress-text"); @@ -797,43 +1039,50 @@ PlayerObject.prototype.workForFaction = function(numCycles) { //Money gained per game cycle PlayerObject.prototype.getWorkMoneyGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.baseSalary * company.salaryMultiplier * this.work_money_mult; + return this.companyPosition.baseSalary * company.salaryMultiplier * + this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney; } //Hack exp gained per game cycle PlayerObject.prototype.getWorkHackExpGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.hackingExpGain * company.expMultiplier * this.hacking_exp_mult; + return this.companyPosition.hackingExpGain * company.expMultiplier * + this.hacking_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; } //Str exp gained per game cycle PlayerObject.prototype.getWorkStrExpGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.strengthExpGain * company.expMultiplier * this.strength_exp_mult; + return this.companyPosition.strengthExpGain * company.expMultiplier * + this.strength_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; } //Def exp gained per game cycle PlayerObject.prototype.getWorkDefExpGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.defenseExpGain * company.expMultiplier * this.defense_exp_mult; + return this.companyPosition.defenseExpGain * company.expMultiplier * + this.defense_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; } //Dex exp gained per game cycle PlayerObject.prototype.getWorkDexExpGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.dexterityExpGain * company.expMultiplier * this.dexterity_exp_mult; + return this.companyPosition.dexterityExpGain * company.expMultiplier * + this.dexterity_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; } //Agi exp gained per game cycle PlayerObject.prototype.getWorkAgiExpGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.agilityExpGain * company.expMultiplier * this.agility_exp_mult; + return this.companyPosition.agilityExpGain * company.expMultiplier * + this.agility_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; } //Charisma exp gained per game cycle PlayerObject.prototype.getWorkChaExpGain = function() { var company = Companies[this.companyName]; - return this.companyPosition.charismaExpGain * company.expMultiplier * this.charisma_exp_mult; + return this.companyPosition.charismaExpGain * company.expMultiplier * + this.charisma_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; } //Reputation gained per game cycle @@ -898,7 +1147,7 @@ PlayerObject.prototype.startCreateProgramWork = function(programName, time, reqL var cancelButton = clearEventListeners("work-in-progress-cancel-button"); cancelButton.innerHTML = "Cancel work on creating program"; cancelButton.addEventListener("click", function() { - Player.finishCreateProgramWork(true, programName); + Player.finishCreateProgramWork(true); return false; }); @@ -911,7 +1160,7 @@ PlayerObject.prototype.createProgramWork = function(numCycles) { var programName = this.createProgramName; if (this.timeWorked >= this.timeNeededToCompleteWork) { - this.finishCreateProgramWork(false, programName); + this.finishCreateProgramWork(false); } var txt = document.getElementById("work-in-progress-text"); @@ -921,8 +1170,9 @@ PlayerObject.prototype.createProgramWork = function(numCycles) { "If you cancel, your work will be saved and you can come back to complete the program later."; } -PlayerObject.prototype.finishCreateProgramWork = function(cancelled, programName) { - if (cancelled == false) { +PlayerObject.prototype.finishCreateProgramWork = function(cancelled, sing=false) { + var programName = this.createProgramName; + if (cancelled === false) { dialogBoxCreate("You've finished creating " + programName + "!
" + "The new program can be found on your home computer."); @@ -1009,12 +1259,12 @@ PlayerObject.prototype.startClass = function(costMult, expMult, className) { } this.workMoneyLossRate = cost; - this.workHackExpGainRate = hackExp * this.hacking_exp_mult; - this.workStrExpGainRate = strExp * this.strength_exp_mult; - this.workDefExpGainRate = defExp * this.defense_exp_mult; - this.workDexExpGainRate = dexExp * this.dexterity_exp_mult; - this.workAgiExpGainRate = agiExp * this.agility_exp_mult; - this.workChaExpGainRate = chaExp * this.charisma_exp_mult; + this.workHackExpGainRate = hackExp * this.hacking_exp_mult * BitNodeMultipliers.ClassGymExpGain; + this.workStrExpGainRate = strExp * this.strength_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workDefExpGainRate = defExp * this.defense_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workDexExpGainRate = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workAgiExpGainRate = agiExp * this.agility_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workChaExpGainRate = chaExp * this.charisma_exp_mult * BitNodeMultipliers.ClassGymExpGain;; var cancelButton = clearEventListeners("work-in-progress-cancel-button"); if (className == CONSTANTS.ClassGymStrength || @@ -1064,7 +1314,9 @@ PlayerObject.prototype.takeClass = function(numCycles) { "You may cancel at any time"; } -PlayerObject.prototype.finishClass = function() { +//The 'sing' argument defines whether or not this function was called +//through a Singularity Netscript function +PlayerObject.prototype.finishClass = function(sing=false) { this.gainWorkExp(); if (this.workMoneyGained > 0) { @@ -1082,8 +1334,7 @@ PlayerObject.prototype.finishClass = function() { formatNumber(this.workDexExpGained, 4) + " dexterity exp
" + formatNumber(this.workAgiExpGained, 4) + " agility exp
" + formatNumber(this.workChaExpGained, 4) + " charisma exp
"; - - dialogBoxCreate(txt); + if (!sing) {dialogBoxCreate(txt);} var mainMenu = document.getElementById("mainmenu-container"); mainMenu.style.visibility = "visible"; @@ -1091,6 +1342,16 @@ PlayerObject.prototype.finishClass = function() { this.isWorking = false; Engine.loadLocationContent(); + + if (sing) {return "After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", " + + "you spent a total of $" + formatNumber(this.workMoneyGained * -1, 2) + ". " + + "You earned a total of: " + + formatNumber(this.workHackExpGained, 3) + " hacking exp, " + + formatNumber(this.workStrExpGained, 3) + " strength exp, " + + formatNumber(this.workDefExpGained, 3) + " defense exp, " + + formatNumber(this.workDexExpGained, 3) + " dexterity exp, " + + formatNumber(this.workAgiExpGained, 3) + " agility exp, and " + + formatNumber(this.workChaExpGained, 3) + " charisma exp";} } //The EXP and $ gains are hardcoded. Time is in ms @@ -1099,12 +1360,12 @@ PlayerObject.prototype.startCrime = function(hackExp, strExp, defExp, dexExp, ag this.isWorking = true; this.workType = CONSTANTS.WorkTypeCrime; - this.workHackExpGained = hackExp * this.hacking_exp_mult; - this.workStrExpGained = strExp * this.strength_exp_mult; - this.workDefExpGained = defExp * this.defense_exp_mult; - this.workDexExpGained = dexExp * this.dexterity_exp_mult; - this.workAgiExpGained = agiExp * this.agility_exp_mult; - this.workChaExpGained = chaExp * this.charisma_exp_mult; + this.workHackExpGained = hackExp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workStrExpGained = strExp * this.strength_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workDefExpGained = defExp * this.defense_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workDexExpGained = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workAgiExpGained = agiExp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workChaExpGained = chaExp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain; this.workMoneyGained = money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney; this.timeNeededToCompleteWork = time; @@ -1147,24 +1408,20 @@ PlayerObject.prototype.finishCrime = function(cancelled) { switch(this.crimeType) { case CONSTANTS.CrimeShoplift: this.karma -= 0.1; - ++this.numTimesShoplifted; break; case CONSTANTS.CrimeRobStore: this.karma -= 0.5; break; case CONSTANTS.CrimeMug: this.karma -= 0.25; - ++this.numPeopleMugged; break; case CONSTANTS.CrimeLarceny: this.karma -= 1.5; break; case CONSTANTS.CrimeDrugs: - ++this.numTimesDealtDrugs; this.karma -= 0.5; break; case CONSTANTS.CrimeTraffickArms: - ++this.numTimesTraffickArms; this.karma -= 1; break; case CONSTANTS.CrimeHomicide: @@ -1172,11 +1429,9 @@ PlayerObject.prototype.finishCrime = function(cancelled) { this.karma -= 3; break; case CONSTANTS.CrimeGrandTheftAuto: - ++this.numTimesGrandTheftAuto; this.karma -= 5; break; case CONSTANTS.CrimeKidnap: - ++this.numTimesKidnapped; this.karma -= 6; break; case CONSTANTS.CrimeAssassination: @@ -1184,7 +1439,6 @@ PlayerObject.prototype.finishCrime = function(cancelled) { this.karma -= 10; break; case CONSTANTS.CrimeHeist: - ++this.numTimesHeist; this.karma -= 15; break; default: @@ -1232,6 +1486,34 @@ PlayerObject.prototype.finishCrime = function(cancelled) { Engine.loadLocationContent(); } +//Cancels the player's current "work" assignment and gives the proper rewards +//Used only for Singularity functions, so no popups are created +PlayerObject.prototype.singularityStopWork = function() { + if (!this.isWorking) {return "";} + var res; //Earnings text for work + switch (this.workType) { + case CONSTANTS.WorkTypeStudyClass: + res = this.finishClass(true); + break; + case CONSTANTS.WorkTypeCompany: + res = this.finishWork(true, true); + break; + case CONSTANTS.WorkTypeCompanyPartTime: + res = this.finishWorkPartTime(true); + break; + case CONSTANTS.WorkTypeFaction: + res = this.finishFactionWork(true, true); + break; + case CONSTANTS.WorkTypeCreateProgram: + res = this.finishCreateProgramWork(true, true); + break; + default: + console.log("ERROR: Unrecognized work type"); + return ""; + } + return res; +} + //Returns true if hospitalized, false otherwise PlayerObject.prototype.takeDamage = function(amt) { @@ -1252,7 +1534,644 @@ PlayerObject.prototype.hospitalize = function() { this.hp = this.max_hp; } +/********* Company job application **********/ +//Determines the job that the Player should get (if any) at the current company +//The 'sing' argument designates whether or not this is being called from +//the applyToCompany() Netscript Singularity function +PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) { + var currCompany = ""; + if (this.companyName != "") { + currCompany = Companies[this.companyName]; + } + var currPositionName = ""; + if (this.companyPosition != "") { + currPositionName = this.companyPosition.positionName; + } + var company = Companies[this.location]; //Company being applied to + if (sing && !(company instanceof Company)) { + return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed"; + } + + var pos = entryPosType; + + if (!this.isQualified(company, pos)) { + var reqText = getJobRequirementText(company, pos); + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position
" + reqText); + return; + } + + while (true) { + if (Engine.Debug) {console.log("Determining qualification for next Company Position");} + var newPos = getNextCompanyPosition(pos); + if (newPos == null) {break;} + + //Check if this company has this position + if (company.hasPosition(newPos)) { + if (!this.isQualified(company, newPos)) { + //If player not qualified for next job, break loop so player will be given current job + break; + } + pos = newPos; + } else { + break; + } + } + + //Check if the determined job is the same as the player's current job + if (currCompany != "") { + if (currCompany.companyName == company.companyName && + pos.positionName == currPositionName) { + var nextPos = getNextCompanyPosition(pos); + if (nextPos == null) { + if (sing) {return false;} + dialogBoxCreate("You are already at the highest position for your field! No promotion available"); + } else if (company.hasPosition(nextPos)) { + if (sing) {return false;} + var reqText = getJobRequirementText(company, nextPos); + dialogBoxCreate("Unfortunately, you do not qualify for a promotion
" + reqText); + } else { + if (sing) {return false;} + dialogBoxCreate("You are already at the highest position for your field! No promotion available"); + } + return; //Same job, do nothing + } + } + + + //Lose reputation from a Company if you are leaving it for another job + var leaveCompany = false; + var oldCompanyName = ""; + if (currCompany != "") { + if (currCompany.companyName != company.companyName) { + leaveCompany = true; + oldCompanyName = currCompany.companyName; + company.playerReputation -= 1000; + if (company.playerReputation < 0) {company.playerReputation = 0;} + } + } + + this.companyName = company.companyName; + this.companyPosition = pos; + + Player.firstJobRecvd = true; + + if (leaveCompany) { + if (sing) {return true;} + dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + + pos.positionName + "!
" + + "You lost 1000 reputation at your old company " + oldCompanyName + " because you left."); + } else { + if (sing) {return true;} + dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.positionName + "!"); + } + + Engine.loadLocationContent(); +} + +//Returns your next position at a company given the field (software, business, etc.) +PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType) { + var currCompany = null; + if (this.companyName != "") { + currCompany = Companies[this.companyName]; + } + + //Not employed at this company, so return the entry position + if (currCompany == null || (currCompany.companyName != company.companyName)) { + return entryPosType; + } + + //If the entry pos type and the player's current position have the same type, + //return the player's "nextCompanyPosition". Otherwise return the entryposType + //Employed at this company, so just return the next position if it exists. + if ((this.companyPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) || + (this.companyPosition.isITJob() && entryPosType.isITJob()) || + (this.companyPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) || + (this.companyPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) || + (this.companyPosition.isSecurityJob() && entryPosType.isSecurityJob()) || + (this.companyPosition.isAgentJob() && entryPosTypeisAgentJob()) || + (this.companyPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) || + (this.companyPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) || + (this.companyPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) { + return getNextCompanyPosition(this.companyPosition); + } + + + return entryPosType; +} + +PlayerObject.prototype.applyForSoftwareJob = function(sing=false) { + return this.applyForJob(CompanyPositions.SoftwareIntern, sing); +} + +PlayerObject.prototype.applyForSoftwareConsultantJob = function(sing=false) { + return this.applyForJob(CompanyPositions.SoftwareConsultant, sing); +} + +PlayerObject.prototype.applyForItJob = function(sing=false) { + return this.applyForJob(CompanyPositions.ITIntern, sing); +} + +PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.SecurityEngineer)) { + return this.applyForJob(CompanyPositions.SecurityEngineer, sing); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.NetworkEngineer)) { + return this.applyForJob(CompanyPositions.NetworkEngineer, sing); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForBusinessJob = function(sing=false) { + return this.applyForJob(CompanyPositions.BusinessIntern, sing); +} + +PlayerObject.prototype.applyForBusinessConsultantJob = function(sing=false) { + return this.applyForJob(CompanyPositions.BusinessConsultant, sing); +} + +PlayerObject.prototype.applyForSecurityJob = function(sing=false) { + //TODO If case for POlice departments + return this.applyForJob(CompanyPositions.SecurityGuard, sing); +} + +PlayerObject.prototype.applyForAgentJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.FieldAgent)) { + return this.applyForJob(CompanyPositions.FieldAgent, sing); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForEmployeeJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.Employee)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = CompanyPositions.Employee; + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed at " + this.companyName); + Engine.loadLocationContent(); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.PartTimeEmployee)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = CompanyPositions.PartTimeEmployee; + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName); + Engine.loadLocationContent(); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForWaiterJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.Waiter)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = CompanyPositions.Waiter; + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName); + Engine.loadLocationContent(); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions.PartTimeWaiter)) { + Player.firstJobRecvd = true; + this.companyName = company.companyName; + this.companyPosition = CompanyPositions.PartTimeWaiter; + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName); + Engine.loadLocationContent(); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +//Checks if the Player is qualified for a certain position +PlayerObject.prototype.isQualified = function(company, position) { + var offset = company.jobStatReqOffset; + var reqHacking = position.requiredHacking > 0 ? position.requiredHacking+offset : 0; + var reqStrength = position.requiredStrength > 0 ? position.requiredStrength+offset : 0; + var reqDefense = position.requiredDefense > 0 ? position.requiredDefense+offset : 0; + var reqDexterity = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; + var reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; + var reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma+offset : 0; + + if (this.hacking_skill >= reqHacking && + this.strength >= reqStrength && + this.defense >= reqDefense && + this.dexterity >= reqDexterity && + this.agility >= reqAgility && + this.charisma >= reqCharisma && + company.playerReputation >= position.requiredReputation) { + return true; + } + return false; +} + +/********** Reapplying Augmentations and Source File ***********/ +PlayerObject.prototype.reapplyAllAugmentations = function(resetMultipliers=true) { + console.log("Re-applying augmentations"); + if (resetMultipliers) { + this.resetMultipliers(); + } + + for (let i = 0; i < this.augmentations.length; ++i) { + //Compatibility with new version + if (typeof this.augmentations[i] === 'string' || this.augmentations[i] instanceof String) { + var newOwnedAug = new PlayerOwnedAugmentation(this.augmentations[i]); + if (this.augmentations[i] == AugmentationNames.NeuroFluxGovernor) { + newOwnedAug.level = Augmentations[AugmentationNames.NeuroFluxGovernor].level; + } + this.augmentations[i] = newOwnedAug; + } + + var augName = this.augmentations[i].name; + var aug = Augmentations[augName]; + aug.owned = true; + if (aug == null) { + console.log("WARNING: Invalid augmentation name"); + continue; + } + if (aug.name == AugmentationNames.NeuroFluxGovernor) { + for (let j = 0; j < aug.level; ++j) { + applyAugmentation(this.augmentations[i], true); + } + continue; + } + applyAugmentation(this.augmentations[i], true); + } +} + +PlayerObject.prototype.reapplyAllSourceFiles = function() { + console.log("Re-applying source files"); + //Will always be called after reapplyAllAugmentations() so multipliers do not have to be reset + //this.resetMultipliers(); + + for (let i = 0; i < this.sourceFiles.length; ++i) { + var srcFileKey = "SourceFile" + this.sourceFiles[i].n; + var sourceFileObject = SourceFiles[srcFileKey]; + if (sourceFileObject == null) { + console.log("ERROR: Invalid source file number: " + this.sourceFiles[i].n); + continue; + } + applySourceFile(this.sourceFiles[i]); + } +} + +/*************** Check for Faction Invitations *************/ +//This function sets the requirements to join a Faction. It checks whether the Player meets +//those requirements and will return an array of all factions that the Player should +//receive an invitation to +PlayerObject.prototype.checkForFactionInvitations = function() { + let invitedFactions = []; //Array which will hold all Factions th eplayer should be invited to + + var numAugmentations = this.augmentations.length; + + var company = Companies[this.companyName]; + var companyRep = 0; + if (company != null) { + companyRep = company.playerReputation; + } + + //Illuminati + var illuminatiFac = Factions["Illuminati"]; + if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(150000000000) && + this.hacking_skill >= 1500 && + this.strength >= 1200 && this.defense >= 1200 && + this.dexterity >= 1200 && this.agility >= 1200) { + invitedFactions.push(illuminatiFac); + } + + //Daedalus + var daedalusFac = Factions["Daedalus"]; + if (!daedalusFac.isBanned && !daedalusFac.isMember && !daedalusFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(100000000000) && + (this.hacking_skill >= 2500 || + (this.strength >= 1500 && this.defense >= 1500 && + this.dexterity >= 1500 && this.agility >= 1500))) { + invitedFactions.push(daedalusFac); + } + + //The Covenant + var covenantFac = Factions["The Covenant"]; + if (!covenantFac.isBanned && !covenantFac.isMember && !covenantFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(75000000000) && + this.hacking_skill >= 850 && + this.strength >= 850 && + this.defense >= 850 && + this.dexterity >= 850 && + this.agility >= 850) { + invitedFactions.push(covenantFac); + } + + //ECorp + var ecorpFac = Factions["ECorp"]; + if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited && + this.companyName == Locations.AevumECorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(ecorpFac); + } + + //MegaCorp + var megacorpFac = Factions["MegaCorp"]; + if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited && + this.companyName == Locations.Sector12MegaCorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(megacorpFac); + } + + //Bachman & Associates + var bachmanandassociatesFac = Factions["Bachman & Associates"]; + if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember && + !bachmanandassociatesFac.alreadyInvited && + this.companyName == Locations.AevumBachmanAndAssociates && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(bachmanandassociatesFac); + } + + //Blade Industries + var bladeindustriesFac = Factions["Blade Industries"]; + if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited && + this.companyName == Locations.Sector12BladeIndustries && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(bladeindustriesFac); + } + + //NWO + var nwoFac = Factions["NWO"]; + if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && + this.companyName == Locations.VolhavenNWO && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(nwoFac); + } + + //Clarke Incorporated + var clarkeincorporatedFac = Factions["Clarke Incorporated"]; + if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited && + this.companyName == Locations.AevumClarkeIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(clarkeincorporatedFac); + } + + //OmniTek Incorporated + var omnitekincorporatedFac = Factions["OmniTek Incorporated"]; + if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited && + this.companyName == Locations.VolhavenOmniTekIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(omnitekincorporatedFac); + } + + //Four Sigma + var foursigmaFac = Factions["Four Sigma"]; + if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited && + this.companyName == Locations.Sector12FourSigma && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(foursigmaFac); + } + + //KuaiGong International + var kuaigonginternationalFac = Factions["KuaiGong International"]; + if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember && + !kuaigonginternationalFac.alreadyInvited && + this.companyName == Locations.ChongqingKuaiGongInternational && companyRep >= CONSTANTS.CorpFactionRepRequirement) { + invitedFactions.push(kuaigonginternationalFac); + } + + //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company + var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"]; + var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]]; + if (fulcrumSecretServer == null) { + console.log("ERROR: Could not find Fulcrum Secret Technologies Server"); + } else { + if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && + !fulcrumsecrettechonologiesFac.alreadyInvited && + fulcrumSecretServer.manuallyHacked && + this.companyName == Locations.AevumFulcrumTechnologies && companyRep >= 250000) { + invitedFactions.push(fulcrumsecrettechonologiesFac); + } + } + + //BitRunners + var bitrunnersFac = Factions["BitRunners"]; + var homeComp = this.getHomeComputer(); + var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]]; + if (bitrunnersServer == null) { + console.log("ERROR: Could not find BitRunners Server"); + } else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked && + !bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) { + invitedFactions.push(bitrunnersFac); + } + + //The Black Hand + var theblackhandFac = Factions["The Black Hand"]; + var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]]; + if (blackhandServer == null) { + console.log("ERROR: Could not find The Black Hand Server"); + } else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked && + !theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) { + invitedFactions.push(theblackhandFac); + } + + //NiteSec + var nitesecFac = Factions["NiteSec"]; + var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]]; + if (nitesecServer == null) { + console.log("ERROR: Could not find NiteSec Server"); + } else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked && + !nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) { + invitedFactions.push(nitesecFac); + } + + //Chongqing + var chongqingFac = Factions["Chongqing"]; + if (!chongqingFac.isBanned && !chongqingFac.isMember && !chongqingFac.alreadyInvited && + this.money.gte(20000000) && this.city == Locations.Chongqing) { + invitedFactions.push(chongqingFac); + } + + //Sector-12 + var sector12Fac = Factions["Sector-12"]; + if (!sector12Fac.isBanned && !sector12Fac.isMember && !sector12Fac.alreadyInvited && + this.money.gte(15000000) && this.city == Locations.Sector12) { + invitedFactions.push(sector12Fac); + } + + //New Tokyo + var newtokyoFac = Factions["New Tokyo"]; + if (!newtokyoFac.isBanned && !newtokyoFac.isMember && !newtokyoFac.alreadyInvited && + this.money.gte(20000000) && this.city == Locations.NewTokyo) { + invitedFactions.push(newtokyoFac); + } + + //Aevum + var aevumFac = Factions["Aevum"]; + if (!aevumFac.isBanned && !aevumFac.isMember && !aevumFac.alreadyInvited && + this.money.gte(40000000) && this.city == Locations.Aevum) { + invitedFactions.push(aevumFac); + } + + //Ishima + var ishimaFac = Factions["Ishima"]; + if (!ishimaFac.isBanned && !ishimaFac.isMember && !ishimaFac.alreadyInvited && + this.money.gte(30000000) && this.city == Locations.Ishima) { + invitedFactions.push(ishimaFac); + } + + //Volhaven + var volhavenFac = Factions["Volhaven"]; + if (!volhavenFac.isBanned && !volhavenFac.isMember && !volhavenFac.alreadyInvited && + this.money.gte(50000000) && this.city == Locations.Volhaven) { + invitedFactions.push(volhavenFac); + } + + //Speakers for the Dead + var speakersforthedeadFac = Factions["Speakers for the Dead"]; + if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited && + this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 && + this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 && + this.karma <= -45 && this.companyName != Locations.Sector12CIA && + this.companyName != Locations.Sector12NSA) { + invitedFactions.push(speakersforthedeadFac); + } + + //The Dark Army + var thedarkarmyFac = Factions["The Dark Army"]; + if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited && + this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 && + this.dexterity >= 300 && this.agility >= 300 && this.city == Locations.Chongqing && + this.numPeopleKilled >= 5 && this.karma <= -45 && this.companyName != Locations.Sector12CIA && + this.companyName != Locations.Sector12NSA) { + invitedFactions.push(thedarkarmyFac); + } + + //The Syndicate + var thesyndicateFac = Factions["The Syndicate"]; + if (!thesyndicateFac.isBanned && !thesyndicateFac.isMember && !thesyndicateFac.alreadyInvited && + this.hacking_skill >= 200 && this.strength >= 200 && this.defense >= 200 && + this.dexterity >= 200 && this.agility >= 200 && + (this.city == Locations.Aevum || this.city == Locations.Sector12) && + this.money.gte(10000000) && this.karma <= -90 && + this.companyName != Locations.Sector12CIA && this.companyName != Locations.Sector12NSA) { + invitedFactions.push(thesyndicateFac); + } + + //Silhouette + var silhouetteFac = Factions["Silhouette"]; + if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited && + (this.companyPosition.positionName == CompanyPositions.CTO.positionName || + this.companyPosition.positionName == CompanyPositions.CFO.positionName || + this.companyPosition.positionName == CompanyPositions.CEO.positionName) && + this.money.gte(15000000) && this.karma <= -22) { + invitedFactions.push(silhouetteFac); + } + + //Tetrads + var tetradsFac = Factions["Tetrads"]; + if (!tetradsFac.isBanned && !tetradsFac.isMember && !tetradsFac.alreadyInvited && + (this.city == Locations.Chongqing || this.city == Locations.NewTokyo || + this.city == Locations.Ishima) && this.strength >= 75 && this.defense >= 75 && + this.dexterity >= 75 && this.agility >= 75 && this.karma <= -18) { + invitedFactions.push(tetradsFac); + } + + //SlumSnakes + var slumsnakesFac = Factions["Slum Snakes"]; + if (!slumsnakesFac.isBanned && !slumsnakesFac.isMember && !slumsnakesFac.alreadyInvited && + this.strength >= 30 && this.defense >= 30 && this.dexterity >= 30 && + this.agility >= 30 && this.karma <= -9 && this.money.gte(1000000)) { + invitedFactions.push(slumsnakesFac); + } + + //Netburners + var netburnersFac = Factions["Netburners"]; + var totalHacknetRam = 0; + var totalHacknetCores = 0; + var totalHacknetLevels = 0; + for (var i = 0; i < Player.hacknetNodes.length; ++i) { + totalHacknetLevels += Player.hacknetNodes[i].level; + totalHacknetRam += Player.hacknetNodes[i].ram; + totalHacknetCores += Player.hacknetNodes[i].cores; + } + if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited && + this.hacking_skill >= 80 && totalHacknetRam >= 8 && + totalHacknetCores >= 4 && totalHacknetLevels >= 100) { + invitedFactions.push(netburnersFac); + } + + //Tian Di Hui + var tiandihuiFac = Factions["Tian Di Hui"]; + if (!tiandihuiFac.isBanned && !tiandihuiFac.isMember && !tiandihuiFac.alreadyInvited && + this.money.gte(1000000) && this.hacking_skill >= 50 && + (this.city == Locations.Chongqing || this.city == Locations.NewTokyo || + this.city == Locations.Ishima)) { + invitedFactions.push(tiandihuiFac); + } + + //CyberSec + var cybersecFac = Factions["CyberSec"]; + var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]]; + if (cybersecServer == null) { + console.log("ERROR: Could not find CyberSec Server"); + } else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked && + !cybersecFac.alreadyInvited && this.hacking_skill >= 50) { + invitedFactions.push(cybersecFac); + } + + return invitedFactions; +} + + +/*************** Gang ****************/ +//Returns true if Player is in a gang and false otherwise +PlayerObject.prototype.inGang = function() { + if (this.gang == null || this.gang == undefined) {return false;} + return (this.gang instanceof Gang); +} + +PlayerObject.prototype.startGang = function(factionName, hacking) { + this.gang = new Gang(factionName, hacking); +} + +/************* BitNodes **************/ +PlayerObject.prototype.setBitNodeNumber = function(n) { + this.bitNodeN = n; +} + /* Functions for saving and loading the Player data */ +function loadPlayer(saveString) { + Player = JSON.parse(saveString, Reviver); + + //Parse Decimal.js objects + Player.money = new Decimal(Player.money); + Player.total_money = new Decimal(Player.total_money); + Player.lifetime_money = new Decimal(Player.lifetime_money); +} + PlayerObject.prototype.toJSON = function() { return Generic_toJSON("PlayerObject", this); } @@ -1263,4 +2182,5 @@ PlayerObject.fromJSON = function(value) { Reviver.constructors.PlayerObject = PlayerObject; -Player = new PlayerObject(); +let Player = new PlayerObject(); +export {Player, loadPlayer}; diff --git a/src/Prestige.js b/src/Prestige.js index c989df1ed..a625ec434 100644 --- a/src/Prestige.js +++ b/src/Prestige.js @@ -1,113 +1,49 @@ -/* Prestige functions */ +import {deleteActiveScriptsItem} from "./ActiveScriptsUI.js"; +import {Augmentations, augmentationExists, + initAugmentations, AugmentationNames} from "./Augmentations.js"; +import {initBitNodeMultipliers} from "./BitNode.js"; +import {Companies, Company, initCompanies} from "./Company.js"; +import {Programs} from "./CreateProgram.js"; +import {Engine} from "./engine.js"; +import {Factions, Faction, initFactions, + joinFaction} from "./Faction.js"; +import {Locations} from "./Location.js"; +import {initMessages, Messages, Message} from "./Message.js"; +import {WorkerScript, workerScripts, + prestigeWorkerScripts} from "./NetscriptWorker.js"; +import {Player} from "./Player.js"; +import {AllServers, AddToAllServers, + initForeignServers, Server, + prestigeAllServers, + prestigeHomeComputer} from "./Server.js"; +import {SpecialServerIps, SpecialServerIpsMap, + prestigeSpecialServerIps, + SpecialServerNames} from "./SpecialServerIps.js"; +import {initStockMarket, initSymbolToStockMap, + stockMarketContentCreated, + setStockMarketContentCreated} from "./StockMarket.js"; +import {Terminal, postNetburnerText} from "./Terminal.js"; +import Decimal from '../utils/decimal.js'; //Prestige by purchasing augmentation function prestigeAugmentation() { initBitNodeMultipliers(); - //Crime statistics - Player.numTimesShoplifted = 0; - Player.numPeopleMugged = 0; - Player.numTimesDealtDrugs = 0; - Player.numTimesTraffickArms = 0; - Player.numPeopleKilled = 0; - Player.numTimesGrandTheftAuto = 0; - Player.numTimesKidnapped = 0; - Player.numTimesHeist = 0; - - Player.karma = 0; - - //Reset stats - Player.hacking_skill = 1; - - Player.strength = 1; - Player.defense = 1; - Player.dexterity = 1; - Player.agility = 1; - - Player.charisma = 1; - - Player.hacking_exp = 0; - Player.strength_exp = 0; - Player.defense_exp = 0; - Player.dexterity_exp = 0; - Player.agility_exp = 0; - Player.charisma_exp = 0; - - Player.money = new Decimal(1000); - - Player.city = Locations.Sector12; - Player.location = ""; - - Player.companyName = ""; - Player.companyPosition = ""; - - Player.currentServer = ""; - Player.discoveredServers = []; - Player.purchasedServers = []; - - Player.factions = []; - Player.factionInvitations = []; - - Player.queuedAugmentations = []; - - Player.startAction = false; - Player.actionTime = 0; - - Player.isWorking = false; - Player.currentWorkFactionName = ""; - Player.currentWorkFactionDescription = ""; - this.createProgramName = ""; - this.className = ""; - this.crimeType = ""; - - Player.workHackExpGainRate = 0; - Player.workStrExpGainRate = 0; - Player.workDefExpGainRate = 0; - Player.workDexExpGainRate = 0; - Player.workAgiExpGainRate = 0; - Player.workChaExpGainRate = 0; - Player.workRepGainRate = 0; - Player.workMoneyGainRate = 0; - - Player.workHackExpGained = 0; - Player.workStrExpGained = 0; - Player.workDefExpGained = 0; - Player.workDexExpGained = 0; - Player.workAgiExpGained = 0; - Player.workChaExpGained = 0; - Player.workRepGained = 0; - Player.workMoneyGained = 0; - - Player.timeWorked = 0; - - Player.lastUpdate = new Date().getTime(); + Player.prestigeAugmentation(); //Delete all Worker Scripts objects - for (var i = 0; i < workerScripts.length; ++i) { - deleteActiveScriptsItem(workerScripts[i]); - workerScripts[i].env.stopFlag = true; - } - workerScripts.length = 0; + prestigeWorkerScripts(); var homeComp = Player.getHomeComputer(); //Delete all servers except home computer - for (var member in AllServers) { - delete AllServers[member]; - } - AllServers = {}; + prestigeAllServers(); + //Delete Special Server IPs - for (var member in SpecialServerIps) { - delete SpecialServerIps[member]; - } - SpecialServersIps = null; + prestigeSpecialServerIps(); //Must be done before initForeignServers() //Reset home computer (only the programs) and add to AllServers - homeComp.programs.length = 0; - homeComp.runningScripts = []; - homeComp.serversOnNetwork = []; - homeComp.isConnectedTo = true; - homeComp.ramUsed = 0; - homeComp.programs.push(Programs.NukeProgram); + prestigeHomeComputer(homeComp); + if (augmentationExists(AugmentationNames.Neurolink) && Augmentations[AugmentationNames.Neurolink].owned) { homeComp.programs.push(Programs.FTPCrackProgram); @@ -115,31 +51,18 @@ function prestigeAugmentation() { } if (augmentationExists(AugmentationNames.CashRoot) && Augmentations[AugmentationNames.CashRoot].owned) { - Player.money = new Decimal(1000000); + Player.setMoney(new Decimal(1000000)); homeComp.programs.push(Programs.BruteSSHProgram); } - Player.currentServer = homeComp.ip; - Player.homeComputer = homeComp.ip; + AddToAllServers(homeComp); //Re-create foreign servers - SpecialServerIps = new SpecialServerIpsMap(); //Must be done before initForeignServers() initForeignServers(); //Darkweb is purchase-able document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button"); - //Reset statistics of all scripts on home computer - for (var i = 0; i < homeComp.scripts.length; ++i) { - var s = homeComp.scripts[i]; - } - //Delete messages on home computer - homeComp.messages.length = 0; - - //Delete Hacknet Nodes - Player.hacknetNodes.length = 0; - Player.totalHacknetNodeProduction = 0; - //Gain favor for Companies for (var member in Companies) { if (Companies.hasOwnProperty(member)) { @@ -177,7 +100,7 @@ function prestigeAugmentation() { if (Player.hasWseAccount) { initStockMarket(); initSymbolToStockMap(); - stockMarketContentCreated = false; + setStockMarketContentCreated(false); var stockMarketList = document.getElementById("stock-market-list"); while(stockMarketList.firstChild) { stockMarketList.removeChild(stockMarketList.firstChild); @@ -192,8 +115,6 @@ function prestigeAugmentation() { } } - Player.playtimeSinceLastAug = 0; - var mainMenu = document.getElementById("mainmenu-container"); mainMenu.style.visibility = "visible"; Engine.loadTerminalContent(); @@ -216,110 +137,22 @@ function prestigeSourceFile() { initBitNodeMultipliers(); //Crime statistics - Player.numTimesShoplifted = 0; - Player.numPeopleMugged = 0; - Player.numTimesDealtDrugs = 0; - Player.numTimesTraffickArms = 0; - Player.numPeopleKilled = 0; - Player.numTimesGrandTheftAuto = 0; - Player.numTimesKidnapped = 0; - Player.numTimesHeist = 0; - - Player.karma = 0; - - //Reset stats - Player.hacking_skill = 1; - - Player.strength = 1; - Player.defense = 1; - Player.dexterity = 1; - Player.agility = 1; - - Player.charisma = 1; - - Player.hacking_exp = 0; - Player.strength_exp = 0; - Player.defense_exp = 0; - Player.dexterity_exp = 0; - Player.agility_exp = 0; - Player.charisma_exp = 0; - - Player.money = new Decimal(1000); - - Player.city = Locations.Sector12; - Player.location = ""; - - Player.companyName = ""; - Player.companyPosition = ""; - - Player.currentServer = ""; - Player.discoveredServers = []; - Player.purchasedServers = []; - - Player.factions = []; - Player.factionInvitations = []; - - Player.queuedAugmentations = []; - Player.augmentations = []; - - Player.startAction = false; - Player.actionTime = 0; - - Player.isWorking = false; - Player.currentWorkFactionName = ""; - Player.currentWorkFactionDescription = ""; - this.createProgramName = ""; - this.className = ""; - this.crimeType = ""; - - Player.workHackExpGainRate = 0; - Player.workStrExpGainRate = 0; - Player.workDefExpGainRate = 0; - Player.workDexExpGainRate = 0; - Player.workAgiExpGainRate = 0; - Player.workChaExpGainRate = 0; - Player.workRepGainRate = 0; - Player.workMoneyGainRate = 0; - - Player.workHackExpGained = 0; - Player.workStrExpGained = 0; - Player.workDefExpGained = 0; - Player.workDexExpGained = 0; - Player.workAgiExpGained = 0; - Player.workChaExpGained = 0; - Player.workRepGained = 0; - Player.workMoneyGained = 0; - - Player.timeWorked = 0; - - Player.lastUpdate = new Date().getTime(); + Player.prestigeSourceFile(); //Delete all Worker Scripts objects - for (var i = 0; i < workerScripts.length; ++i) { - deleteActiveScriptsItem(workerScripts[i]); - workerScripts[i].env.stopFlag = true; - } - workerScripts.length = 0; + prestigeWorkerScripts(); var homeComp = Player.getHomeComputer(); + //Delete all servers except home computer - for (var member in AllServers) { - delete AllServers[member]; - } - AllServers = {}; + prestigeAllServers(); //Must be done before initForeignServers() + //Delete Special Server IPs - for (var member in SpecialServerIps) { - delete SpecialServerIps[member]; - } - SpecialServersIps = null; + prestigeSpecialServerIps(); //Reset home computer (only the programs) and add to AllServers - homeComp.programs.length = 0; - homeComp.runningScripts = []; - homeComp.serversOnNetwork = []; - homeComp.isConnectedTo = true; - homeComp.ramUsed = 0; - homeComp.programs.push(Programs.NukeProgram); + prestigeHomeComputer(homeComp); + var srcFile1Owned = false; for (var i = 0; i < Player.sourceFiles.length; ++i) { if (Player.sourceFiles[i].n == 1) { @@ -327,32 +160,19 @@ function prestigeSourceFile() { } } if (srcFile1Owned) { - homeComp.maxRam = 32; + homeComp.setMaxRam(32); } else { - homeComp.maxRam = 8; + homeComp.setMaxRam(8); } - Player.currentServer = homeComp.ip; - Player.homeComputer = homeComp.ip; + AddToAllServers(homeComp); //Re-create foreign servers - SpecialServerIps = new SpecialServerIpsMap(); //Must be done before initForeignServers() initForeignServers(); //Darkweb is purchase-able document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button"); - //Reset statistics of all scripts on home computer - for (var i = 0; i < homeComp.scripts.length; ++i) { - var s = homeComp.scripts[i]; - } - //Delete messages on home computer - homeComp.messages.length = 0; - - //Delete Hacknet Nodes - Player.hacknetNodes.length = 0; - Player.totalHacknetNodeProduction = 0; - //Reset favor for Companies for (var member in Companies) { if (Companies.hasOwnProperty(member)) { @@ -393,16 +213,9 @@ function prestigeSourceFile() { //Messages initMessages(); - //Gang - Player.gang = null; - - //Reset Stock market - Player.hasWseAccount = false; - Player.hasTixApiAccess = false; - - Player.playtimeSinceLastAug = 0; - var mainMenu = document.getElementById("mainmenu-container"); mainMenu.style.visibility = "visible"; Engine.loadTerminalContent(); } + +export {prestigeAugmentation, prestigeSourceFile}; diff --git a/src/RedPill.js b/src/RedPill.js index 768a29d04..2948749b4 100644 --- a/src/RedPill.js +++ b/src/RedPill.js @@ -1,3 +1,16 @@ +import {BitNode, BitNodes} from "./BitNode.js"; +import {Engine} from "./engine.js"; +import {Player} from "./Player.js"; +import {prestigeSourceFile} from "./Prestige.js"; +import {SourceFiles, SourceFile, + PlayerOwnedSourceFile} from "./SourceFile.js"; +import {Terminal} from "./Terminal.js"; + +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {yesNoBoxCreate, yesNoBoxGetYesButton, + yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js"; + /* RedPill.js * Implements what happens when you have Red Pill augmentation and then hack the world daemon */ @@ -38,7 +51,7 @@ function writeRedPillLetter(pElem, line, i=0) { }); } -redPillFlag = false; +let redPillFlag = false; function hackWorldDaemon(currentNodeNumber) { redPillFlag = true; Engine.loadRedPillContent(); @@ -193,7 +206,7 @@ function loadBitVerse(destroyedBitNodeNum) { var elemId = "bitnode-" + i.toString(); var elem = clearEventListeners(elemId); if (elem == null) {return;} - if (i == 1 || i == 2) { + if (i === 1 || i === 2 || i === 4 || i === 11) { elem.addEventListener("click", function() { var bitNodeKey = "BitNode" + i; var bitNode = BitNodes[bitNodeKey]; @@ -282,6 +295,7 @@ function createBitNodeYesNoEventListeners(newBitNode, destroyedBitNode) { //Set new Bit Node Player.bitNodeN = newBitNode; + console.log("Entering Bit Node " + Player.bitNodeN); //Reenable terminal $("#hack-progress-bar").attr('id', "old-hack-progress-bar"); @@ -293,7 +307,6 @@ function createBitNodeYesNoEventListeners(newBitNode, destroyedBitNode) { prestigeSourceFile(); yesNoBoxClose(); - //TODO Dialog box for going ot new Bit node }); var noBtn = yesNoBoxGetNoButton(); noBtn.innerHTML = "Back"; @@ -302,3 +315,5 @@ function createBitNodeYesNoEventListeners(newBitNode, destroyedBitNode) { }); } + +export {redPillFlag, hackWorldDaemon}; diff --git a/src/SaveObject.js b/src/SaveObject.js index 8b7151dca..e402d44e1 100644 --- a/src/SaveObject.js +++ b/src/SaveObject.js @@ -1,7 +1,33 @@ +import {loadAliases, loadGlobalAliases, + Aliases, GlobalAliases} from "./Alias.js"; +import {loadCompanies, Companies, + CompanyPositions} from "./Company.js"; +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {loadFactions, Factions, + processPassiveFactionRepGain} from "./Faction.js"; +import {loadAllGangs, AllGangs} from "./Gang.js"; +import {processAllHacknetNodeEarnings} from "./HacknetNode.js"; +import {loadMessages, initMessages, Messages} from "./Message.js"; +import {Player, loadPlayer} from "./Player.js"; +import {loadAllRunningScripts} from "./Script.js"; +import {AllServers, loadAllServers} from "./Server.js"; +import {loadSettings, initSettings, Settings} from "./Settings.js"; +import {loadSpecialServerIps, SpecialServerIps} from "./SpecialServerIps.js"; +import {loadStockMarket, StockMarket} from "./StockMarket.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {gameOptionsBoxClose} from "../utils/GameOptions.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; + +import Decimal from '../utils/decimal.js'; + /* SaveObject.js * Defines the object used to save/load games */ -var saveObject = new BitburnerSaveObject(); +let saveObject = new BitburnerSaveObject(); function BitburnerSaveObject() { this.PlayerSave = ""; @@ -53,7 +79,7 @@ BitburnerSaveObject.prototype.saveGame = function() { Engine.createStatusText("Game saved!"); } -loadGame = function(saveObj) { +function loadGame(saveObj) { if (!window.localStorage.getItem("bitburnerSave")) { console.log("No save file to load"); return false; @@ -61,39 +87,33 @@ loadGame = function(saveObj) { var saveString = decodeURIComponent(escape(atob(window.localStorage.getItem("bitburnerSave")))); saveObj = JSON.parse(saveString, Reviver); - Player = JSON.parse(saveObj.PlayerSave, Reviver); - - //Parse Decimal.js objects - Player.money = new Decimal(Player.money); - Player.total_money = new Decimal(Player.total_money); - Player.lifetime_money = new Decimal(Player.lifetime_money); - - AllServers = JSON.parse(saveObj.AllServersSave, Reviver); - Companies = JSON.parse(saveObj.CompaniesSave, Reviver); - Factions = JSON.parse(saveObj.FactionsSave, Reviver); - SpecialServerIps = JSON.parse(saveObj.SpecialServerIpsSave, Reviver); + loadPlayer(saveObj.PlayerSave); + loadAllServers(saveObj.AllServersSave); + loadCompanies(saveObj.CompaniesSave); + loadFactions(saveObj.FactionsSave); + loadSpecialServerIps(saveObj.SpecialServerIpsSave); if (saveObj.hasOwnProperty("AliasesSave")) { try { - Aliases = JSON.parse(saveObj.AliasesSave, Reviver); + loadAliases(saveObj.AliasesSave); } catch(e) { - Aliases = {}; + loadAliases(""); } } else { - Aliases = {}; + loadAliases(""); } if (saveObj.hasOwnProperty("GlobalAliasesSave")) { try { - GlobalAliases = JSON.parse(saveObj.GlobalAliasesSave, Reviver); + loadGlobalAliases(saveObj.GlobalAliasesSave); } catch(e) { - GlobalAliases = {}; + loadGlobalAliases(""); } } else { - GlobalAliases = {}; + loadGlobalAliases(""); } if (saveObj.hasOwnProperty("MessagesSave")) { try { - Messages = JSON.parse(saveObj.MessagesSave, Reviver); + loadMessages(saveObj.MessagesSave); } catch(e) { initMessages(); } @@ -102,17 +122,18 @@ loadGame = function(saveObj) { } if (saveObj.hasOwnProperty("StockMarketSave")) { try { - StockMarket = JSON.parse(saveObj.StockMarketSave, Reviver); + loadStockMarket(saveObj.StockMarketSave); } catch(e) { - StockMarket = {}; + loadStockMarket(""); } } else { - StockMarket = {}; + loadStockMarket(""); } if (saveObj.hasOwnProperty("SettingsSave")) { try { - Settings = JSON.parse(saveObj.SettingsSave, Reviver); + loadSettings(saveObj.SettingsSave); } catch(e) { + console.log("ERROR: Failed to parse Settings. Re-initing default values"); initSettings(); } } else { @@ -121,13 +142,30 @@ loadGame = function(saveObj) { if (saveObj.hasOwnProperty("VersionSave")) { try { var ver = JSON.parse(saveObj.VersionSave, Reviver); - if (ver.startsWith("0.27.")) { + if (Player.bitNodeN === null || Player.bitNodeN === 0) { + Player.setBitNodeNumber(1); + } + if (ver.startsWith("0.27.") || ver.startsWith("0.28.")) { console.log("Evaluating changes needed for version compatibility"); - if (Player.bitNodeN == null || Player.bitNodeN == 0) { - Player.bitNodeN = 1; - } - if (Player.sourceFiles == null) { - Player.sourceFiles = []; + if (Player.augmentations.length > 0 || Player.queuedAugmentations.length > 0 || + Player.sourceFiles.length > 0) { + //If you have already purchased an Aug...you are far enough in the game + //that everything should be available + Player.firstFacInvRecvd = true; + Player.firstAugPurchased = true; + Player.firstJobRecvd = true; + Player.firstTimeTraveled = true; + Player.firstProgramAvailable = true; + } else { + if (Player.factions.length > 0 || Player.factionInvitations.length > 0) { + Player.firstFacInvRecvd = true; + } + if (Player.companyName !== "" || Player.companyPosition !== "") { + Player.firstJobRecvd = true; + } + if (Player.hacking_skill >= 25) { + Player.firstScriptAvailable = true; + } } } if (ver != CONSTANTS.Version) { @@ -141,7 +179,7 @@ loadGame = function(saveObj) { } if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) { try { - AllGangs = JSON.parse(saveObj.AllGangsSave, Reviver); + loadAllGangs(saveObj.AllGangsSave); } catch(e) { console.log("ERROR: Failed to parse AllGangsSave: " + e); } @@ -150,24 +188,26 @@ loadGame = function(saveObj) { return true; } -loadImportedGame = function(saveObj, saveString) { +function loadImportedGame(saveObj, saveString) { var tempSaveObj = null; var tempPlayer = null; var tempAllServers = null; var tempCompanies = null; var tempFactions = null; var tempSpecialServerIps = null; - var tempAugmentations = null; var tempAliases = null; var tempGlobalAliases = null; var tempMessages = null; var tempStockMarket = null; - try { - saveString = decodeURIComponent(escape(atob(saveString))); - tempSaveObj = new BitburnerSaveObject(); - tempSaveObj = JSON.parse(saveString, Reviver); - tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver); + //Check to see if the imported save file can be parsed. If any + //errors are caught it will fail + try { + var decodedSaveString = decodeURIComponent(escape(atob(saveString))); + tempSaveObj = new BitburnerSaveObject(); + tempSaveObj = JSON.parse(decodedSaveString, Reviver); + + tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver); //Parse Decimal.js objects tempPlayer.money = new Decimal(tempPlayer.money); @@ -178,11 +218,11 @@ loadImportedGame = function(saveObj, saveString) { tempCompanies = JSON.parse(tempSaveObj.CompaniesSave, Reviver); tempFactions = JSON.parse(tempSaveObj.FactionsSave, Reviver); tempSpecialServerIps = JSON.parse(tempSaveObj.SpecialServerIpsSave, Reviver); - tempAugmentations = JSON.parse(tempSaveObj.AugmentationsSave, Reviver); if (tempSaveObj.hasOwnProperty("AliasesSave")) { try { tempAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver); } catch(e) { + console.log("Parsing Aliases save failed: " + e); tempAliases = {}; } } else { @@ -192,6 +232,7 @@ loadImportedGame = function(saveObj, saveString) { try { tempGlobalAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver); } catch(e) { + console.log("Parsing Global Aliases save failed: " + e); tempGlobalAliases = {}; } } else { @@ -201,6 +242,7 @@ loadImportedGame = function(saveObj, saveString) { try { tempMessages = JSON.parse(tempSaveObj.MessagesSave, Reviver); } catch(e) { + console.log("Parsing Messages save failed: " + e); initMessages(); } } else { @@ -210,6 +252,7 @@ loadImportedGame = function(saveObj, saveString) { try { tempStockMarket = JSON.parse(saveObj.StockMarketSave, Reviver); } catch(e) { + console.log("Parsing StockMarket save failed: " + e); tempStockMarket = {}; } } else { @@ -218,7 +261,7 @@ loadImportedGame = function(saveObj, saveString) { if (tempSaveObj.hasOwnProperty("VersionSave")) { try { var ver = JSON.parse(tempSaveObj.VersionSave, Reviver); - if (ver == "0.27.0" || ver == "0.27.1") { + if (ver.startsWith("0.27.") || ver.startsWith("0.28.")) { if (tempPlayer.bitNodeN == null || tempPlayer.bitNodeN == 0) { tempPlayer.bitNodeN = 1; } @@ -227,13 +270,14 @@ loadImportedGame = function(saveObj, saveString) { } } if (ver != CONSTANTS.Version) { - createNewUpdateText(); + //createNewUpdateText(); } } catch(e) { - createNewUpdateText(); + console.log("Parsing Version save failed: " + e); + //createNewUpdateText(); } } else { - createNewUpdateText(); + //createNewUpdateText(); } if (tempPlayer.bitNodeN == 2 && tempPlayer.inGang() && saveObj.hasOwnProperty("AllGangsSave")) { try { @@ -243,31 +287,110 @@ loadImportedGame = function(saveObj, saveString) { } } } catch(e) { - dialogBoxCreate("Error importing game"); + dialogBoxCreate("Error importing game: " + e.toString()); return false; } - saveObj = tempSaveObj; - Player = tempPlayer; - AllServers = tempAllServers; - Companies = tempCompanies; - Factions = tempFactions; - SpecialServerIps = tempSpecialServerIps; - Augmentations = tempAugmentations; - if (tempAliases) { - Aliases = tempAliases; - } + //Since the save file is valid, load everything for real + saveString = decodeURIComponent(escape(atob(saveString))); + saveObj = JSON.parse(saveString, Reviver); - if (tempGlobalAliases) { - GlobalAliases = tempGlobalAliases; - } + loadPlayer(saveObj.PlayerSave); + loadAllServers(saveObj.AllServersSave); + loadCompanies(saveObj.CompaniesSave); + loadFactions(saveObj.FactionsSave); + loadSpecialServerIps(saveObj.SpecialServerIpsSave); - if (tempMessages) { - Messages = tempMessages; + if (saveObj.hasOwnProperty("AliasesSave")) { + try { + loadAliases(saveObj.AliasesSave); + } catch(e) { + loadAliases(""); + } + } else { + loadAliases(""); } + if (saveObj.hasOwnProperty("GlobalAliasesSave")) { + try { + loadGlobalAliases(saveObj.GlobalAliasesSave); + } catch(e) { + loadGlobalAliases(""); + } + } else { + loadGlobalAliases(""); + } + if (saveObj.hasOwnProperty("MessagesSave")) { + try { + loadMessages(saveObj.MessagesSave); + } catch(e) { + initMessages(); + } + } else { + initMessages(); + } + if (saveObj.hasOwnProperty("StockMarketSave")) { + try { + loadStockMarket(saveObj.StockMarketSave); + } catch(e) { + loadStockMarket(""); + } + } else { + loadStockMarket(""); + } + if (saveObj.hasOwnProperty("SettingsSave")) { + try { + loadSettings(saveObj.SettingsSave); + } catch(e) { + initSettings(); + } + } else { + initSettings(); + } + if (saveObj.hasOwnProperty("VersionSave")) { + try { + var ver = JSON.parse(saveObj.VersionSave, Reviver); + if (Player.bitNodeN == null || Player.bitNodeN == 0) { + Player.setBitNodeNumber(1); - if (tempStockMarket) { - StockMarket = tempStockMarket; + } + if (ver.startsWith("0.27.") || ver.startsWith("0.28.")) { + console.log("Evaluating changes needed for version compatibility"); + if (Player.augmentations.length > 0 || Player.queuedAugmentations.length > 0 || + Player.sourceFiles.length > 0) { + //If you have already purchased an Aug...you are far enough in the game + //that everything should be available + Player.firstFacInvRecvd = true; + Player.firstAugPurchased = true; + Player.firstJobRecvd = true; + Player.firstTimeTraveled = true; + Player.firstProgramAvailable = true; + } else { + if (Player.factions.length > 0 || Player.factionInvitations.length > 0) { + Player.firstFacInvRecvd = true; + } + if (Player.companyName !== "" || Player.companyPosition !== "") { + Player.firstJobRecvd = true; + } + if (Player.hacking_skill >= 25) { + Player.firstScriptAvailable = true; + } + } + } + if (ver != CONSTANTS.Version) { + createNewUpdateText(); + } + } catch(e) { + createNewUpdateText(); + } + } else { + createNewUpdateText(); + } + if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) { + try { + loadAllGangs(saveObj.AllGangsSave); + } catch(e) { + console.log("ERROR: Failed to parse AllGangsSave: " + e); + } } dialogBoxCreate("Imported game! I would suggest saving the game and then reloading the page " + @@ -337,7 +460,6 @@ BitburnerSaveObject.prototype.exportGame = function() { this.CompaniesSave = JSON.stringify(Companies); this.FactionsSave = JSON.stringify(Factions); this.SpecialServerIpsSave = JSON.stringify(SpecialServerIps); - this.AugmentationsSave = JSON.stringify(Augmentations); this.AliasesSave = JSON.stringify(Aliases); this.GlobalAliasesSave = JSON.stringify(GlobalAliases); this.MessagesSave = JSON.stringify(Messages); @@ -380,7 +502,7 @@ BitburnerSaveObject.prototype.deleteGame = function() { Engine.createStatusText("Game deleted!"); } -createNewUpdateText = function() { +function createNewUpdateText() { dialogBoxCreate("New update!
" + "Please report any bugs/issues through the github repository " + "or the Bitburner subreddit (reddit.com/r/bitburner).

" + @@ -414,3 +536,5 @@ function openImportFileHandler(evt) { }; reader.readAsText(file); } + +export {saveObject, loadGame}; diff --git a/src/Script.js b/src/Script.js index 06e912208..545242b20 100644 --- a/src/Script.js +++ b/src/Script.js @@ -1,6 +1,22 @@ -/* Script.js - * Script object - */ +var ace = require('brace'); +require('brace/mode/javascript'); +require('brace/theme/monokai'); + +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {iTutorialSteps, iTutorialNextStep, + iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js"; +import {addWorkerScript, killWorkerScript} from "./NetscriptWorker.js"; +import {Player} from "./Player.js"; +import {AllServers, processSingleServerGrowth} from "./Server.js"; +import {Settings} from "./Settings.js"; + +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {compareArrays} from "../utils/HelperFunctions.js"; +import {formatNumber, numOccurrences, + numNetscriptOperators} from "../utils/StringHelperFunctions.js"; function scriptEditorInit() { //Initialize save and close button @@ -22,7 +38,7 @@ function scriptEditorInit() { var end = this.selectionEnd; //Set textarea value to: text before caret + four spaces + text after caret - spaces = " "; + let spaces = " "; this.value = this.value.substring(0, start) + spaces + this.value.substring(end); //Put caret at after the four spaces @@ -34,15 +50,13 @@ function scriptEditorInit() { document.addEventListener("DOMContentLoaded", scriptEditorInit, false); //Updates line number and RAM usage in script -function upgradeScriptEditorContent() { - var txt = $("#script-editor-text")[0]; - var lineNum = txt.value.substr(0, txt.selectionStart).split("\n").length; - - var code = document.getElementById("script-editor-text").value; +function updateScriptEditorContent() { + var editor = ace.edit('javascript-editor'); + var code = editor.getValue(); var codeCopy = code.repeat(1); var ramUsage = calculateRamUsage(codeCopy); document.getElementById("script-editor-status-text").innerText = - "Line Number: " + lineNum + ", RAM: " + formatNumber(ramUsage, 2).toString() + "GB"; + "RAM: " + formatNumber(ramUsage, 2).toString() + "GB"; } //Define key commands in script editor (ctrl o to save + close, etc.) @@ -63,7 +77,8 @@ function saveAndCloseScriptEditor() { dialogBoxCreate("Leave the script name as 'foodnstuff'!"); return; } - var code = document.getElementById("script-editor-text").value; + var editor = ace.edit('javascript-editor'); + var code = editor.getValue(); code = code.replace(/\s/g, ""); if (code.indexOf("while(true){hack('foodnstuff');}") == -1) { dialogBoxCreate("Please copy and paste the code from the tutorial!"); @@ -122,7 +137,8 @@ function Script() { Script.prototype.saveScript = function() { if (Engine.currentPage == Engine.Page.ScriptEditor) { //Update code and filename - var code = document.getElementById("script-editor-text").value; + var editor = ace.edit('javascript-editor'); + var code = editor.getValue(); this.code = code.replace(/^\s+|\s+$/g, ''); var filename = document.getElementById("script-editor-filename").value + ".script"; @@ -200,6 +216,30 @@ function calculateRamUsage(codeCopy) { var getHackTimeCount = numOccurrences(codeCopy, "getHackTime(") + numOccurrences(codeCopy, "getGrowTime(") + numOccurrences(codeCopy, "getWeakenTime("); + var singFn1Count = numOccurrences(codeCopy, "universityCourse(") + + numOccurrences(codeCopy, "gymWorkout(") + + numOccurrences(codeCopy, "travelToCity(") + + numOccurrences(codeCopy, "purchaseTor(") + + numOccurrences(codeCopy, "purchaseProgram("); + var singFn2Count = numOccurrences(codeCopy, "upgradeHomeRam(") + + numOccurrences(codeCopy, "getUpgradeHomeRamCost(") + + numOccurrences(codeCopy, "workForCompany(") + + numOccurrences(codeCopy, "applyToCompany(") + + numOccurrences(codeCopy, "getCompanyRep(") + + numOccurrences(codeCopy, "checkFactionInvitations(") + + numOccurrences(codeCopy, "joinFaction(") + + numOccurrences(codeCopy, "workForFaction(") + + numOccurrences(codeCopy, "getFactionRep("); + var singFn3Count = numOccurrences(codeCopy, "createProgram(") + + numOccurrences(codeCopy, "getAugmentationCost(") + + numOccurrences(codeCopy, "purchaseAugmentation(") + + numOccurrences(codeCopy, "installAugmentations("); + + if (Player.bitNodeN != 4) { + singFn1Count *= 10; + singFn2Count *= 10; + singFn3Count *= 10; + } return baseRam + ((whileCount * CONSTANTS.ScriptWhileRamCost) + @@ -238,8 +278,11 @@ function calculateRamUsage(codeCopy) { (scriptWriteCount * CONSTANTS.ScriptReadWriteRamCost) + (scriptReadCount * CONSTANTS.ScriptReadWriteRamCost) + (arbScriptCount * CONSTANTS.ScriptArbScriptRamCost) + - (getScriptCount * CONSTANTS.ScriptGetScriptCost) + - (getHackTimeCount * CONSTANTS.ScriptGetHackTimeCost)); + (getScriptCount * CONSTANTS.ScriptGetScriptRamCost) + + (getHackTimeCount * CONSTANTS.ScriptGetHackTimeRamCost) + + (singFn1Count * CONSTANTS.ScriptSingularityFn1RamCost) + + (singFn2Count * CONSTANTS.ScriptSingularityFn2RamCost) + + (singFn3Count * CONSTANTS.ScriptSingularityFn3RamCost)); } Script.prototype.toJSON = function() { @@ -255,7 +298,7 @@ Reviver.constructors.Script = Script; //Called when the game is loaded. Loads all running scripts (from all servers) //into worker scripts so that they will start running -loadAllRunningScripts = function() { +function loadAllRunningScripts() { var count = 0; var total = 0; for (var property in AllServers) { @@ -278,7 +321,7 @@ loadAllRunningScripts = function() { console.log("Loaded " + count.toString() + " running scripts"); } -scriptCalculateOfflineProduction = function(runningScriptObj) { +function scriptCalculateOfflineProduction(runningScriptObj) { //The Player object stores the last update time from when we were online var thisUpdate = new Date().getTime(); var lastUpdate = Player.lastUpdate; @@ -473,6 +516,8 @@ RunningScript.fromJSON = function(value) { return Generic_fromJSON(RunningScript, value.data); } +Reviver.constructors.RunningScript = RunningScript; + //Creates an object that creates a map/dictionary with the IP of each existing server as //a key. Initializes every key with a specified value that can either by a number or an array function AllServersMap(arr=false) { @@ -517,3 +562,6 @@ AllServersMap.fromJSON = function(value) { } Reviver.constructors.AllServersMap = AllServersMap; + +export {updateScriptEditorContent, loadAllRunningScripts, findRunningScript, + RunningScript, Script, AllServersMap}; diff --git a/src/Server.js b/src/Server.js index 97df42c87..9205e9145 100644 --- a/src/Server.js +++ b/src/Server.js @@ -1,6 +1,14 @@ -//Netburner Server class -//TODO Make a map of all IPS in the game so far so that we don't accidentally -// get duplicate IPs..however unlikely it is +import {BitNodeMultipliers} from "./BitNode.js"; +import {CONSTANTS} from "./Constants.js"; +import {Programs} from "./CreateProgram.js"; +import {Player} from "./Player.js"; +import {RunningScript, Script} from "./Script.js"; +import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps.js"; +import {getRandomInt} from "../utils/HelperFunctions.js"; +import {createRandomIp, isValidIPAddress, ipExists} from "../utils/IPAddress.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; + function Server(ip=createRandomIp(), hostname="", organizationName="", isConnectedTo=false, adminRights=false, purchasedByPlayer=false, maxRam=0) { /* Properties */ @@ -67,9 +75,9 @@ Server.prototype.setHackingParameters = function(requiredHackingSkill, moneyAvai if (isNaN(moneyAvailable)) { this.moneyAvailable = 1000000; } else { - this.moneyAvailable = moneyAvailable; + this.moneyAvailable = moneyAvailable * BitNodeMultipliers.ServerStartingMoney; } - this.moneyMax = 25 * moneyAvailable * BitNodeMultipliers.ServerMaxMoney; + this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney; this.hackDifficulty = hackDifficulty; this.baseDifficulty = hackDifficulty; this.minDifficulty = Math.max(1, Math.round(hackDifficulty / 3)); @@ -82,6 +90,10 @@ Server.prototype.setPortProperties = function(numOpenPortsReq) { this.numOpenPortsRequired = numOpenPortsReq; } +Server.prototype.setMaxRam = function(ram) { + this.maxRam = ram; +} + //The serverOnNetwork array holds the IP of all the servers. This function //returns the actual Server objects Server.prototype.getServerOnNetwork = function(i) { @@ -110,7 +122,7 @@ Server.prototype.fortify = function(amt) { } Server.prototype.weaken = function(amt) { - this.hackDifficulty -= amt; + this.hackDifficulty -= (amt * BitNodeMultipliers.ServerWeakenRate); if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;} if (this.hackDifficulty < 1) {this.hackDifficulty = 1;} } @@ -126,7 +138,7 @@ Server.fromJSON = function(value) { Reviver.constructors.Server = Server; -initForeignServers = function() { +function initForeignServers() { //MegaCorporations var ECorpServer = new Server(createRandomIp(), "ecorp", "ECorp", false, false, false, 0); ECorpServer.setHackingParameters(getRandomInt(1150, 1300), getRandomInt(30000000000, 70000000000), 99, 99); @@ -637,7 +649,7 @@ initForeignServers = function() { } //Applied server growth for a single server. Returns the percentage growth -processSingleServerGrowth = function(server, numCycles) { +function processSingleServerGrowth(server, numCycles) { //Server growth processed once every 450 game cycles var numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0); @@ -645,11 +657,10 @@ processSingleServerGrowth = function(server, numCycles) { var growthRate = CONSTANTS.ServerBaseGrowthRate; var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty; if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;} - //console.log("Adjusted growth rate: " + adjGrowthRate); //Calculate adjusted server growth rate based on parameters var serverGrowthPercentage = server.serverGrowth / 100; - var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage; + var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate; //Apply serverGrowth for the calculated number of growth cycles var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult); @@ -666,14 +677,38 @@ processSingleServerGrowth = function(server, numCycles) { server.moneyAvailable = server.moneyMax; return 1; } + + //Growing increases server security twice as much as hacking server.fortify(2 * CONSTANTS.ServerFortifyAmount * numServerGrowthCycles); return serverGrowth; } -//List of all servers that exist in the game, indexed by their ip -AllServers = {}; +function prestigeHomeComputer(homeComp) { + homeComp.programs.length = 0; + homeComp.runningScripts = []; + homeComp.serversOnNetwork = []; + homeComp.isConnectedTo = true; + homeComp.ramUsed = 0; + homeComp.programs.push(Programs.NukeProgram); -SizeOfAllServers = function() { + homeComp.messages.length = 0; +} + +//List of all servers that exist in the game, indexed by their ip +let AllServers = {}; + +function prestigeAllServers() { + for (var member in AllServers) { + delete AllServers[member]; + } + AllServers = {}; +} + +function loadAllServers(saveString) { + AllServers = JSON.parse(saveString, Reviver); +} + +function SizeOfAllServers() { var size = 0, key; for (key in AllServers) { if (AllServers.hasOwnProperty(key)) size++; @@ -682,7 +717,7 @@ SizeOfAllServers = function() { } //Add a server onto the map of all servers in the game -AddToAllServers = function(server) { +function AddToAllServers(server) { var serverIp = server.ip; if (ipExists(serverIp)) { console.log("IP of server that's being added: " + serverIp); @@ -696,7 +731,7 @@ AddToAllServers = function(server) { //Returns server object with corresponding hostname // Relatively slow, would rather not use this a lot -GetServerByHostname = function(hostname) { +function GetServerByHostname(hostname) { for (var ip in AllServers) { if (AllServers.hasOwnProperty(ip)) { if (AllServers[ip].hostname == hostname) { @@ -708,7 +743,7 @@ GetServerByHostname = function(hostname) { } //Get server by IP or hostname. Returns null if invalid -getServer = function(s) { +function getServer(s) { if (!isValidIPAddress(s)) { return GetServerByHostname(s); } else { @@ -717,10 +752,14 @@ getServer = function(s) { } //Debugging tool -PrintAllServers = function() { +function PrintAllServers() { for (var ip in AllServers) { if (AllServers.hasOwnProperty(ip)) { console.log("Ip: " + ip + ", hostname: " + AllServers[ip].hostname); } } } + +export {Server, AllServers, getServer, GetServerByHostname, loadAllServers, + AddToAllServers, processSingleServerGrowth, initForeignServers, + prestigeAllServers, prestigeHomeComputer}; diff --git a/src/ServerPurchases.js b/src/ServerPurchases.js index 7ec910f53..b9fab3cb6 100644 --- a/src/ServerPurchases.js +++ b/src/ServerPurchases.js @@ -1,8 +1,14 @@ +import {CONSTANTS} from "./Constants.js"; +import {Player} from "./Player.js"; +import {AllServers} from "./Server.js"; +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {yesNoTxtInpBoxGetInput} from "../utils/YesNoBox.js"; + /* Functions to handle any server-related purchasing: * Purchasing new servers * Purchasing more RAM for home computer */ -purchaseServer = function(ram, cost) { +function purchaseServer(ram, cost) { //Check if player has enough money if (Player.money.lt(cost)) { dialogBoxCreate("You don't have enough money to purchase this server!"); @@ -41,7 +47,7 @@ purchaseServer = function(ram, cost) { } -purchaseRamForHomeComputer = function(cost) { +function purchaseRamForHomeComputer(cost) { if (Player.money.lt(cost)) { dialogBoxCreate("You do not have enough money to purchase additional RAM for your home computer"); return; @@ -54,3 +60,5 @@ purchaseRamForHomeComputer = function(cost) { dialogBoxCreate("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM."); } + +export {purchaseServer, purchaseRamForHomeComputer}; diff --git a/src/Settings.js b/src/Settings.js index f9aa4a127..1f56d676f 100644 --- a/src/Settings.js +++ b/src/Settings.js @@ -1,5 +1,5 @@ /* Settings.js */ -Settings = { +let Settings = { CodeInstructionRunTime: 100, MaxLogCapacity: 50, MaxPortCapacity: 50, @@ -7,6 +7,10 @@ Settings = { SuppressFactionInvites: false, } +function loadSettings(saveString) { + Settings = JSON.parse(saveString); +} + function initSettings() { Settings.CodeInstructionRunTime = 100; Settings.MaxLogCapacity = 50; @@ -16,14 +20,42 @@ function initSettings() { } function setSettingsLabels() { - document.getElementById("settingsNSExecTimeRangeValLabel").innerHTML - = Settings.CodeInstructionRunTime + "ms"; - document.getElementById("settingsNSLogRangeValLabel").innerHTML - = Settings.MaxLogCapacity; - document.getElementById("settingsNSPortRangeValLabel").innerHTML - = Settings.MaxPortCapacity; - document.getElementById("settingsSuppressMessages").checked - = Settings.SuppressMessages; - document.getElementById("settingsSuppressFactionInvites").checked - = Settings.SuppressFactionInvites; + var nsExecTime = document.getElementById("settingsNSExecTimeRangeValLabel"); + var nsLogLimit = document.getElementById("settingsNSLogRangeValLabel"); + var nsPortLimit = document.getElementById("settingsNSPortRangeValLabel"); + var suppressMsgs = document.getElementById("settingsSuppressMessages"); + var suppressFactionInv = document.getElementById("settingsSuppressFactionInvites") + + //Initialize values on labels + nsExecTime.innerHTML = Settings.CodeInstructionRunTime + "ms"; + nsLogLimit.innerHTML = Settings.MaxLogCapacity; + nsPortLimit.innerHTML = Settings.MaxPortCapacity; + suppressMsgs.checked = Settings.SuppressMessages; + suppressFactionInv.checked = Settings.SuppressFactionInvites; + + //Set handlers for when input changes + document.getElementById("settingsNSExecTimeRangeVal").oninput = function() { + nsExecTime.innerHTML = this.value + 'ms'; + Settings.CodeInstructionRunTime = this.value; + }; + + document.getElementById("settingsNSLogRangeVal").oninput = function() { + nsLogLimit.innerHTML = this.value; + Settings.MaxLogCapacity = this.value; + }; + + document.getElementById("settingsNSPortRangeVal").oninput = function() { + nsPortLimit.innerHTML = this.value; + Settings.MaxPortCapacity = this.value; + }; + + document.getElementById("settingsSuppressMessages").onclick = function() { + Settings.SuppressMessages = this.checked; + }; + + document.getElementById("settingsSuppressFactionInvites").onclick = function() { + Settings.SuppressFactionInvites = this.checked; + }; } + +export {Settings, initSettings, setSettingsLabels, loadSettings}; diff --git a/src/SourceFile.js b/src/SourceFile.js index 28119efdf..b9191da6c 100644 --- a/src/SourceFile.js +++ b/src/SourceFile.js @@ -1,5 +1,7 @@ -/* SourceFile.js */ +import {Player} from "./Player.js"; +import {BitNode, BitNodes} from "./BitNode.js"; +/* SourceFile.js */ //Each SourceFile corresponds to a BitNode with the same number function SourceFile(number, info="") { var bitnodeKey = "BitNode" + number; @@ -15,27 +17,33 @@ function SourceFile(number, info="") { this.owned = false; } -SourceFiles = { - SourceFile1: new SourceFile(1, "This Source-File lets the player start with 32GB of RAM on his/her " + +let SourceFiles = {}; +function initSourceFiles() { + SourceFiles = {}; + SourceFiles["SourceFile1"] = new SourceFile(1, "This Source-File lets the player start with 32GB of RAM on his/her " + "home computer. It also increases all of the player's multipliers by:

" + "Level 1: 16%
" + "Level 2: 24%
" + - "Level 3: 28%"), - SourceFile2: new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " + + "Level 3: 28%"); + SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " + "multipliers by:

" + "Level 1: 20%
" + "Level 2: 30%
" + - "Level 3: 35%"), - SourceFile3: new SourceFile(3), - SourceFile4: new SourceFile(4), - SourceFile5: new SourceFile(5), - SourceFile6: new SourceFile(6), - SourceFile7: new SourceFile(7), - SourceFile8: new SourceFile(8), - SourceFile9: new SourceFile(9), - SourceFile10: new SourceFile(10), - SourceFile11: new SourceFile(11), - SourceFile12: new SourceFile(12), + "Level 3: 35%"); + SourceFiles["SourceFile3"] = new SourceFile(3); + SourceFiles["SourceFile4"] = new SourceFile(4, "This Source-File lets you access and use the Singularity Functions in every BitNode. Every " + + "level of this Source-File opens up more of the Singularity Functions you can use."); + SourceFiles["SourceFile5"] = new SourceFile(5); + SourceFiles["SourceFile6"] = new SourceFile(6); + SourceFiles["SourceFile7"] = new SourceFile(7); + SourceFiles["SourceFile8"] = new SourceFile(8); + SourceFiles["SourceFile9"] = new SourceFile(9); + SourceFiles["SourceFile10"] = new SourceFile(10); + SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File increases the player's company salary and reputation gain multipliers by:

" + + "Level 1: 60%
" + + "Level 2: 90%
" + + "Level 3: 105%
"); + SourceFiles["SourceFile12"] = new SourceFile(12); } function PlayerOwnedSourceFile(number, level) { @@ -97,6 +105,18 @@ function applySourceFile(srcFile) { Player.crime_success_mult *= incMult; Player.charisma_mult *= incMult; break; + case 4: //The Singularity + //No effects, just gives access to Singularity functions + break; + case 11: //The Big Crash + var mult = 0; + for (var i = 0; i < srcFile.lvl; ++i) { + mult += (60 / (Math.pow(2, i))); + } + var incMult = 1 + (mult / 100); + Player.work_money_mult *= incMult; + Player.company_rep_mult *= incMult; + break; default: console.log("ERROR: Invalid source file number: " + srcFile.n); break; @@ -105,18 +125,4 @@ function applySourceFile(srcFile) { sourceFileObject.owned = true; } -PlayerObject.prototype.reapplyAllSourceFiles = function() { - console.log("Re-applying source files"); - //Will always be called after reapplyAllAugmentations() so multipliers do not have to be reset - //this.resetMultipliers(); - - for (i = 0; i < this.sourceFiles.length; ++i) { - var srcFileKey = "SourceFile" + this.sourceFiles[i].n; - var sourceFileObject = SourceFiles[srcFileKey]; - if (sourceFileObject == null) { - console.log("ERROR: Invalid source file number: " + this.sourceFiles[i].n); - continue; - } - applySourceFile(this.sourceFiles[i]); - } -} +export {SourceFiles, PlayerOwnedSourceFile, applySourceFile, initSourceFiles}; diff --git a/src/SpecialServerIps.js b/src/SpecialServerIps.js index c5d760d04..d92d12692 100644 --- a/src/SpecialServerIps.js +++ b/src/SpecialServerIps.js @@ -1,5 +1,8 @@ +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; + /* Holds IP of Special Servers */ -SpecialServerNames = { +let SpecialServerNames = { FulcrumSecretTechnologies: "Fulcrum Secret Technologies Server", CyberSecServer: "CyberSec Server", NiteSecServer: "NiteSec Server", @@ -23,6 +26,25 @@ SpecialServerIpsMap.fromJSON = function(value) { return Generic_fromJSON(SpecialServerIpsMap, value.data); } -Reviver.constructors.SpecialServerIpsMap = SpecialServerIpsMap(); +Reviver.constructors.SpecialServerIpsMap = SpecialServerIpsMap; -SpecialServerIps = null; \ No newline at end of file +let SpecialServerIps = new SpecialServerIpsMap(); + +function prestigeSpecialServerIps() { + for (var member in SpecialServerIps) { + delete SpecialServerIps[member]; + } + SpecialServerIps = null; + SpecialServerIps = new SpecialServerIpsMap(); +} + +function loadSpecialServerIps(saveString) { + SpecialServerIps = JSON.parse(saveString, Reviver); +} + +function initSpecialServerIps() { + SpecialServerIps = new SpecialServerIpsMap(); +} + +export {SpecialServerNames, SpecialServerIps, SpecialServerIpsMap, loadSpecialServerIps, + prestigeSpecialServerIps, initSpecialServerIps}; diff --git a/src/StockMarket.js b/src/StockMarket.js index 7e76b43ad..5f06a2daa 100644 --- a/src/StockMarket.js +++ b/src/StockMarket.js @@ -1,3 +1,14 @@ +import {CONSTANTS} from "./Constants.js"; +import {Engine} from "./engine.js"; +import {Locations} from "./Location.js"; +import {Player} from "./Player.js"; + +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {clearEventListeners, getRandomInt} from "../utils/HelperFunctions.js"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../utils/JSONReviver.js"; +import {formatNumber} from "../utils/StringHelperFunctions.js"; + /* StockMarket.js */ function Stock(name, symbol, mv, b, otlkMag, initPrice=10000) { this.symbol = symbol; @@ -11,10 +22,27 @@ function Stock(name, symbol, mv, b, otlkMag, initPrice=10000) { this.otlkMag = otlkMag; } +Stock.prototype.toJSON = function() { + return Generic_toJSON("Stock", this); +} -StockMarket = {} //Full name to stock object -StockSymbols = {} //Full name to symbol -SymbolToStockMap = {}; //Symbol to Stock object +Stock.fromJSON = function(value) { + return Generic_fromJSON(Stock, value.data); +} + +Reviver.constructors.Stock = Stock; + +let StockMarket = {} //Full name to stock object +let StockSymbols = {} //Full name to symbol +let SymbolToStockMap = {}; //Symbol to Stock object + +function loadStockMarket(saveString) { + if (saveString === "") { + StockMarket = {}; + } else { + StockMarket = JSON.parse(saveString, Reviver); + } +} function initStockSymbols() { //Stocks for companies at which you can work @@ -51,7 +79,6 @@ function initStockSymbols() { StockSymbols["Sigma Cosmetics"] = "SGC"; StockSymbols["Joes Guns"] = "JGN"; StockSymbols["Catalyst Ventures"] = "CTYS"; - StockSymbols["Taiyang Digital"] = "TAI"; StockSymbols["Microdyne Technologies"] = "MDYN"; StockSymbols["Titan Laboratories"] = "TITN"; } @@ -119,10 +146,6 @@ function initStockMarket() { var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], 0.55, true, 10, getRandomInt(20000, 25000)); StockMarket[universalenergy] = universalenergyStk; - var galactic = Locations.AevumGalacticCybersystems; - var galacticStk = new Stock(galactic, StockSymbols[galactic], 0.6, true, 5, getRandomInt(8000, 10000)); - StockMarket[galactic] = galacticStk; - var aerocorp = Locations.AevumAeroCorp; var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], 0.6, true, 6, getRandomInt(10000, 15000)); StockMarket[aerocorp] = aerocorpStk; @@ -191,10 +214,6 @@ function initStockMarket() { var catalystStk = new Stock(catalyst, StockSymbols[catalyst], 1.25, true, 0, getRandomInt(1000, 1500)); StockMarket[catalyst] = catalystStk; - var taiyang = "Taiyang Digital"; - var taiyangStk = new Stock(taiyang, StockSymbols[taiyang], 0.75, true, 12, getRandomInt(25000, 30000)); - StockMarket[taiyang] = taiyangStk; - var microdyne = "Microdyne Technologies"; var microdyneStk = new Stock(microdyne, StockSymbols[microdyne], 0.75, true, 8, getRandomInt(20000, 25000)); StockMarket[microdyne] = microdyneStk; @@ -330,6 +349,10 @@ function updateStockPrices() { } } +function setStockMarketContentCreated(b) { + stockMarketContentCreated = b; +} + var stockMarketContentCreated = false; function displayStockMarketContent() { if (Player.hasWseAccount == null) {Player.hasWseAccount = false;} @@ -537,9 +560,9 @@ function displayStockMarketContent() { //'increase' argument is a boolean indicating whether the price increased or decreased function updateStockTicker(stock, increase) { var tickerId = "stock-market-ticker-" + stock.symbol; - stkName = document.getElementById(tickerId + "-name"); - stkSym = document.getElementById(tickerId + "-sym"); - stkPrice = document.getElementById(tickerId + "-price"); + let stkName = document.getElementById(tickerId + "-name"); + let stkSym = document.getElementById(tickerId + "-sym"); + let stkPrice = document.getElementById(tickerId + "-price"); if (stkName == null || stkSym == null || stkPrice == null) { console.log("ERROR, couldn't find elements with tickerId " + tickerId); @@ -584,3 +607,9 @@ function updateStockPlayerPosition(stock) { avgPriceTxt.innerText = "$" + formatNumber(stock.playerAvgPx, 2); sharesTxt.innerText = stock.playerShares.toString(); } + +export {StockMarket, StockSymbols, SymbolToStockMap, initStockSymbols, + initStockMarket, initSymbolToStockMap, stockMarketCycle, buyStock, + sellStock, updateStockPrices, displayStockMarketContent, + updateStockTicker, updateStockPlayerPosition, loadStockMarket, + setStockMarketContentCreated}; diff --git a/src/Terminal.js b/src/Terminal.js index 555d522f2..638ab1787 100644 --- a/src/Terminal.js +++ b/src/Terminal.js @@ -1,7 +1,35 @@ -//Terminal +import {substituteAliases, printAliases, + parseAliasDeclaration, + removeAlias, GlobalAliases, + Aliases} from "./Alias.js"; +import {CONSTANTS} from "./Constants.js"; +import {Programs} from "./CreateProgram.js"; +import {executeDarkwebTerminalCommand, + checkIfConnectedToDarkweb} from "./DarkWeb.js"; +import {Engine} from "./engine.js"; +import {TerminalHelpText, HelpTexts} from "./HelpText.js"; +import {iTutorialNextStep, iTutorialSteps, + iTutorialIsRunning, + currITutorialStep} from "./InteractiveTutorial.js"; +import {showLiterature} from "./Literature.js"; +import {showMessage, Message} from "./Message.js"; +import {killWorkerScript, addWorkerScript} from "./NetscriptWorker.js"; +import {Player} from "./Player.js"; +import {hackWorldDaemon} from "./RedPill.js"; +import {findRunningScript, RunningScript, + AllServersMap, Script} from "./Script.js"; +import {AllServers, GetServerByHostname, + getServer, Server} from "./Server.js"; +import {SpecialServerIps, + SpecialServerNames} from "./SpecialServerIps.js"; + +import {containsAllStrings, longestCommonStart, + formatNumber} from "../utils/StringHelperFunctions.js"; +import {addOffset, printArray} from "../utils/HelperFunctions.js"; +import {logBoxCreate} from "../utils/LogBox.js"; /* Write text to terminal */ -var post = function(input, replace=true) { +function post(input, replace=true) { if (replace) { $("#terminal-input").before('' + input.replace( / /g, " " ) + ''); } else { @@ -12,12 +40,12 @@ var post = function(input, replace=true) { } //Same thing as post but the td cells have ids so they can be animated for the hack progress bar -var hackProgressBarPost = function(input) { +function hackProgressBarPost(input) { $("#terminal-input").before('' + input + ''); updateTerminalScroll(); } -var hackProgressPost = function(input) { +function hackProgressPost(input) { $("#terminal-input").before('' + input + ''); updateTerminalScroll(); } @@ -28,7 +56,7 @@ function updateTerminalScroll() { element.scrollTop = element.scrollHeight; } -var postNetburnerText = function() { +function postNetburnerText() { post("Bitburner v" + CONSTANTS.Version); } @@ -134,7 +162,7 @@ $(document).keydown(function(event) { }); //Keep terminal in focus -terminalCtrlPressed = false; +let terminalCtrlPressed = false; $(document).ready(function() { if (Engine.currentPage == Engine.Page.Terminal) { $('.terminal-input').focus(); @@ -346,7 +374,7 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) { return allPos; } -var Terminal = { +let Terminal = { //Flags to determine whether the player is currently running a hack or an analyze hackFlag: false, analyzeFlag: false, @@ -1592,5 +1620,6 @@ var Terminal = { post("ERROR: No such script"); } - }; + +export {postNetburnerText, post, Terminal}; diff --git a/src/engine.js b/src/engine.js index f7112545d..76b8a382c 100644 --- a/src/engine.js +++ b/src/engine.js @@ -1,3 +1,65 @@ +var ace = require('brace'); +require('brace/mode/javascript'); +require('brace/theme/monokai'); +require('brace/theme/terminal'); +require('brace/theme/twilight'); + +import {dialogBoxCreate} from "../utils/DialogBox.js"; +import {gameOptionsBoxOpen, gameOptionsBoxClose}from "../utils/GameOptions.js"; +import {clearEventListeners} from "../utils/HelperFunctions.js"; +import numeral from "../utils/numeral.min.js"; +import {formatNumber, + convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js"; +import {loxBoxCreate, logBoxUpdateText, + logBoxOpened} from "../utils/LogBox.js"; + +import {setActiveScriptsClickHandlers, + updateActiveScriptsItems} from "./ActiveScriptsUI.js"; +import {Augmentations, installAugmentations, + initAugmentations, AugmentationNames} from "./Augmentations.js"; +import {BitNodes, initBitNodes, + initBitNodeMultipliers} from "./BitNode.js"; +import {CompanyPositions, initCompanies} from "./Company.js"; +import {CONSTANTS} from "./Constants.js"; +import {Programs, displayCreateProgramContent, + getNumAvailableCreateProgram, + initCreateProgramButtons} from "./CreateProgram.js"; +import {displayFactionContent, joinFaction, + processPassiveFactionRepGain, Factions, + inviteToFaction, initFactions} from "./Faction.js"; +import {Locations, displayLocationContent, + initLocationButtons} from "./Location.js"; +import {displayGangContent, updateGangContent, + Gang} from "./Gang.js"; +import {displayHacknetNodesContent, processAllHacknetNodeEarnings, + updateHacknetNodesContent} from "./HacknetNode.js"; +import {iTutorialStart} from "./InteractiveTutorial.js"; +import {initLiterature} from "./Literature.js"; +import {checkForMessagesToSend, initMessages} from "./Message.js"; +import {initSingularitySFFlags, + hasSingularitySF} from "./NetscriptFunctions.js"; +import {updateOnlineScriptTimes, + runScriptsLoop} from "./NetscriptWorker.js"; +import {Player} from "./Player.js"; +import {prestigeAugmentation, + prestigeSourceFile} from "./Prestige.js"; +import {redPillFlag} from "./RedPill.js"; +import {saveObject, loadGame} from "./SaveObject.js"; +import {loadAllRunningScripts, + updateScriptEditorContent} from "./Script.js"; +import {AllServers, Server, initForeignServers} from "./Server.js"; +import {Settings, setSettingsLabels} from "./Settings.js"; +import {initSourceFiles, SourceFiles} from "./SourceFile.js"; +import {SpecialServerIps, initSpecialServerIps} from "./SpecialServerIps.js"; +import {StockMarket, StockSymbols, + SymbolToStockMap, initStockSymbols, + initSymbolToStockMap, stockMarketCycle, + updateStockPrices, + displayStockMarketContent} from "./StockMarket.js"; +import {Terminal, postNetburnerText, post} from "./Terminal.js"; + + + /* Shortcuts to navigate through the game * Alt-t - Terminal * Alt-c - Character @@ -60,7 +122,7 @@ $(document).keydown(function(e) { } }); -var Engine = { +let Engine = { version: "", Debug: true, @@ -125,9 +187,6 @@ var Engine = { //Character info characterInfo: null, - - //Script editor text - scriptEditorText: null, }, //Current page status @@ -177,12 +236,13 @@ var Engine = { loadScriptEditorContent: function(filename = "", code = "") { Engine.hideAllContent(); Engine.Display.scriptEditorContent.style.visibility = "visible"; + var editor = ace.edit('javascript-editor'); if (filename != "") { document.getElementById("script-editor-filename").value = filename; - document.getElementById("script-editor-text").value = code; + editor.setValue(code); } - document.getElementById("script-editor-text").focus(); - upgradeScriptEditorContent(); + editor.focus(); + updateScriptEditorContent(); Engine.currentPage = Engine.Page.ScriptEditor; document.getElementById("create-script-menu-link").classList.add("active"); }, @@ -324,7 +384,7 @@ var Engine = { loadGangContent: function() { Engine.hideAllContent(); - if (document.getElementById("gang-container") || Player.gang) { + if (document.getElementById("gang-container") || Player.inGang()) { displayGangContent(); Engine.currentPage = Engine.Page.Gang; } else { @@ -383,7 +443,6 @@ var Engine = { if (Player.hp == null) {Player.hp = Player.max_hp;} document.getElementById("character-overview-text").innerHTML = ("Hp: " + Player.hp + " / " + Player.max_hp + "
" + - //"Money: $" + formatNumber(Player.money.toNumber(), 2) + "
" + "Money: " + numeral(Player.money.toNumber()).format('($0.000a)') + "
" + "Hack: " + (Player.hacking_skill).toLocaleString() + "
" + "Str: " + (Player.strength).toLocaleString() + "
" + @@ -473,7 +532,6 @@ var Engine = { document.getElementById("world-city-name").innerHTML = Player.city; var cityDesc = document.getElementById("world-city-desc"); //TODO switch(Player.city) { - case Locations.Aevum: Engine.aevumLocationsList.style.display = "inline"; break; @@ -857,6 +915,7 @@ var Engine = { if (Engine.Counters.checkFactionInvitations <= 0) { var invitedFactions = Player.checkForFactionInvitations(); if (invitedFactions.length > 0) { + Player.firstFacInvRecvd = true; var randFaction = invitedFactions[Math.floor(Math.random() * invitedFactions.length)]; inviteToFaction(randFaction); } @@ -891,7 +950,7 @@ var Engine = { if (Engine.Counters.updateScriptEditorDisplay <= 0) { if (Engine.currentPage == Engine.Page.ScriptEditor) { - upgradeScriptEditorContent(); + updateScriptEditorContent(); } Engine.Counters.updateScriptEditorDisplay = 5; } @@ -960,6 +1019,13 @@ var Engine = { }, load: function() { + //Load script editor + var editor = ace.edit('javascript-editor'); + editor.getSession().setMode('ace/mode/javascript'); + editor.setTheme('ace/theme/monokai'); + document.getElementById('javascript-editor').style.fontSize='16px'; + editor.setOption("showPrintMargin", false); + //Initialize main menu accordion panels to all start as "open" var terminal = document.getElementById("terminal-tab"); var createScript = document.getElementById("create-script-tab"); @@ -978,7 +1044,9 @@ var Engine = { //Load game from save or create new game if (loadGame(saveObject)) { console.log("Loaded game from save"); + initBitNodes(); initBitNodeMultipliers(); + initSourceFiles(); Engine.setDisplayElements(); //Sets variables for important DOM elements Engine.init(); //Initialize buttons, work, etc. CompanyPositions.init(); @@ -989,6 +1057,7 @@ var Engine = { initSymbolToStockMap(); } initLiterature(); + initSingularitySFFlags(); //Calculate the number of cycles have elapsed while offline Engine._lastUpdate = new Date().getTime(); @@ -1081,8 +1150,10 @@ var Engine = { } else { //No save found, start new game console.log("Initializing new game"); + initBitNodes(); initBitNodeMultipliers(); - SpecialServerIps = new SpecialServerIpsMap(); + initSourceFiles(); + initSpecialServerIps(); Engine.setDisplayElements(); //Sets variables for important DOM elements Engine.start(); //Run main game loop and Scripts loop Player.init(); @@ -1094,6 +1165,7 @@ var Engine = { initMessages(); initStockSymbols(); initLiterature(); + initSingularitySFFlags(); //Open main menu accordions for new game //Main menu accordions @@ -1212,9 +1284,6 @@ var Engine = { //Init Location buttons initLocationButtons(); - //Script editor - Engine.Display.scriptEditorText = document.getElementById("script-editor-text"); - //Tutorial buttons Engine.Clickables.tutorialNetworkingButton = document.getElementById("tutorial-networking-link"); Engine.Clickables.tutorialNetworkingButton.addEventListener("click", function() { @@ -1233,7 +1302,12 @@ var Engine = { Engine.Clickables.tutorialNetscriptButton = document.getElementById("tutorial-netscript-link"); Engine.Clickables.tutorialNetscriptButton.addEventListener("click", function() { - Engine.displayTutorialPage(CONSTANTS.TutorialNetscriptText); + if (Player.bitNodeN === 4 || hasSingularitySF) { + Engine.displayTutorialPage(CONSTANTS.TutorialNetscriptText + CONSTANTS.TutorialSingularityFunctionsText); + } else { + Engine.displayTutorialPage(CONSTANTS.TutorialNetscriptText); + } + }); Engine.Clickables.tutorialTravelingButton = document.getElementById("tutorial-traveling-link"); @@ -1269,6 +1343,11 @@ var Engine = { /* Initialization */ init: function() { + //Import game link + document.getElementById("import-game-link").onclick = function() { + saveObject.importGame(); + }; + //Main menu accordions var hackingHdr = document.getElementById("hacking-menu-header"); //hackingHdr.classList.toggle("opened"); @@ -1603,9 +1682,9 @@ var Engine = { cancelButton.addEventListener("click", function() { if (Player.workType == CONSTANTS.WorkTypeFaction) { var fac = Factions[Player.currentWorkFactionName]; - Player.finishFactionWork(true, fac); + Player.finishFactionWork(true); } else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) { - Player.finishCreateProgramWork(true, Player.createProgramName); + Player.finishCreateProgramWork(true); } else if (Player.workType == CONSTANTS.WorkTypeStudyClass) { Player.finishClass(); } else if (Player.workType == CONSTANTS.WorkTypeCrime) { @@ -1661,3 +1740,5 @@ var Engine = { window.onload = function() { Engine.load(); }; + +export {Engine}; diff --git a/utils/DialogBox.js b/utils/DialogBox.js index cb24770d4..1f09e8532 100644 --- a/utils/DialogBox.js +++ b/utils/DialogBox.js @@ -1,5 +1,5 @@ /* Pop up Dialog Box */ -dialogBoxes = []; +let dialogBoxes = []; //Close dialog box when clicking outside $(document).click(function(event) { @@ -32,31 +32,33 @@ $(document).on('click', '.dialog-box-close-button', function( event ) { var dialogBoxOpened = false; -dialogBoxCreate = function(txt) { +function dialogBoxCreate(txt) { var container = document.createElement("div"); container.setAttribute("class", "dialog-box-container"); - + var content = document.createElement("div"); content.setAttribute("class", "dialog-box-content"); - + var closeButton = document.createElement("span"); closeButton.setAttribute("class", "dialog-box-close-button"); closeButton.innerHTML = "×" - + var textE = document.createElement("p"); textE.innerHTML = txt; - + content.appendChild(closeButton); content.appendChild(textE); container.appendChild(content); - + document.body.appendChild(container); if (dialogBoxes.length >= 1) { container.style.visibility = "hidden"; } dialogBoxes.push(container); - + setTimeout(function() { dialogBoxOpened = true; }, 400); -} \ No newline at end of file +} + +export {dialogBoxCreate}; diff --git a/utils/FactionInvitationBox.js b/utils/FactionInvitationBox.js index 65832f01e..55dcae2d0 100644 --- a/utils/FactionInvitationBox.js +++ b/utils/FactionInvitationBox.js @@ -1,26 +1,30 @@ +import {Faction, joinFaction} from "../src/Faction.js"; +import {Player} from "../src/Player.js"; +import {clearEventListeners} from "./HelperFunctions.js"; + /* Faction Invitation Pop-up box */ -factionInvitationBoxClose = function() { +function factionInvitationBoxClose() { var factionInvitationBox = document.getElementById("faction-invitation-box-container"); factionInvitationBox.style.display = "none"; } -factionInvitationBoxOpen = function() { +function factionInvitationBoxOpen() { var factionInvitationBox = document.getElementById("faction-invitation-box-container"); factionInvitationBox.style.display = "block"; } -factionInvitationSetText = function(txt) { +function factionInvitationSetText(txt) { var textBox = document.getElementById("faction-invitation-box-text"); textBox.innerHTML = txt; } -factionInvitationSetMessage = function(msg) { +function factionInvitationSetMessage(msg) { var msgBox = document.getElementById("faction-invitation-box-message"); msgBox.innerHTML = msg; } //ram argument is in GB -factionInvitationBoxCreate = function(faction) { +function factionInvitationBoxCreate(faction) { factionInvitationSetText("You have received a faction invitation from " + faction.name); //TODO Faction invitation message @@ -41,3 +45,5 @@ factionInvitationBoxCreate = function(faction) { factionInvitationBoxOpen(); } + +export {factionInvitationBoxCreate}; diff --git a/utils/GameOptions.js b/utils/GameOptions.js index 019e9e0fc..4181d6ec4 100644 --- a/utils/GameOptions.js +++ b/utils/GameOptions.js @@ -2,9 +2,9 @@ //Close box when clicking outside $(document).click(function(event) { - if (gameOptionsOpened) { - if ( $(event.target).closest(".game-options-box").get(0) == null ) { - gameOptionsBoxClose(); + if (gameOptionsOpened) { + if ( $(event.target).closest(".game-options-box").get(0) == null ) { + gameOptionsBoxClose(); } } }); @@ -16,7 +16,7 @@ function gameOptionsBoxInit() { gameOptionsBoxOpen(); return false; }); - + //Close button var closeButton = document.getElementById("game-options-close-button"); closeButton.addEventListener("click", function() { @@ -27,17 +27,19 @@ function gameOptionsBoxInit() { document.addEventListener("DOMContentLoaded", gameOptionsBoxInit, false); -gameOptionsBoxClose = function() { +function gameOptionsBoxClose() { gameOptionsOpened = false; var box = document.getElementById("game-options-container"); box.style.display = "none"; } -gameOptionsBoxOpen = function() { +function gameOptionsBoxOpen() { var box = document.getElementById("game-options-container"); box.style.display = "block"; setTimeout(function() { gameOptionsOpened = true; }, 500); - -} \ No newline at end of file + +} + +export {gameOptionsBoxOpen, gameOptionsBoxClose}; diff --git a/utils/HelperFunctions.js b/utils/HelperFunctions.js index bd0f00d8c..c16a0a20a 100644 --- a/utils/HelperFunctions.js +++ b/utils/HelperFunctions.js @@ -10,13 +10,13 @@ function sizeOfObject(obj) { } //Adds a random offset to a number within a certain percentage -//e.g. addOffset(100, 5) will return anything from 95 to 105. +//e.g. addOffset(100, 5) will return anything from 95 to 105. //The percentage argument must be between 0 and 100; function addOffset(n, percentage) { if (percentage < 0 || percentage > 100) {return;} - + var offset = n * (percentage / 100); - + return n + ((Math.random() * (2 * offset)) - offset); } @@ -41,7 +41,7 @@ function compareArrays(a1, a2) { if (a1.length != a2.length) { return false; } - + for (var i = 0; i < a1.length; ++i) { if (a1[i] != a2[i]) {return false;} } @@ -56,4 +56,7 @@ function printArray(a) { function powerOfTwo(n) { if (isNaN(n)) {return false;} return n && (n & (n-1)) === 0; -} \ No newline at end of file +} + +export {sizeOfObject, addOffset, clearEventListeners, getRandomInt, + compareArrays, printArray, powerOfTwo}; diff --git a/utils/IPAddress.js b/utils/IPAddress.js index 3dc16c79c..493d1a041 100644 --- a/utils/IPAddress.js +++ b/utils/IPAddress.js @@ -1,13 +1,14 @@ +import {AllServers} from "../src/Server.js"; /* Functions to deal with manipulating IP addresses*/ //Generate a random IP address //Will not return an IP address that already exists in the AllServers array -createRandomIp = function() { +function createRandomIp() { var ip = createRandomByte(99) +'.' + createRandomByte(9) +'.' + createRandomByte(9) +'.' + createRandomByte(9); - + //If the Ip already exists, recurse to create a new one if (ipExists(ip)) { return createRandomIp(); @@ -16,7 +17,7 @@ createRandomIp = function() { } //Returns true if the IP already exists in one of the game's servers -ipExists = function(ip) { +function ipExists(ip) { for (var property in AllServers) { if (AllServers.hasOwnProperty(property)) { if (property == ip) { @@ -27,14 +28,16 @@ ipExists = function(ip) { return false; } -createRandomByte = function(n=9) { +function createRandomByte(n=9) { return Math.round(Math.random()*n); } -isValidIPAddress = function(ipaddress) { - if (/^(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) - { +function isValidIPAddress(ipaddress) { + if (/^(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-6]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) + { return true; - } + } return false; -} \ No newline at end of file +} + +export {createRandomIp, ipExists, isValidIPAddress}; diff --git a/utils/InfiltrationBox.js b/utils/InfiltrationBox.js index 494138450..2c9fee5b0 100644 --- a/utils/InfiltrationBox.js +++ b/utils/InfiltrationBox.js @@ -1,69 +1,76 @@ +import {CONSTANTS} from "../src/Constants.js"; +import {Factions, Faction} from "../src/Faction.js"; +import {Player} from "../src/Player.js"; +import {dialogBoxCreate} from "./DialogBox.js"; +import {clearEventListeners} from "./HelperFunctions.js"; +import {formatNumber} from "./StringHelperFunctions.js"; + /* InfiltrationBox.js */ -infiltrationBoxClose = function() { +function infiltrationBoxClose() { var box = document.getElementById("infiltration-box-container"); box.style.display = "none"; } -infiltrationBoxOpen = function() { +function infiltrationBoxOpen() { var box = document.getElementById("infiltration-box-container"); box.style.display = "block"; } -infiltrationSetText = function(txt) { +function infiltrationSetText(txt) { var textBox = document.getElementById("infiltration-box-text"); textBox.innerHTML = txt; } //ram argument is in GB -infiltrationBoxCreate = function(inst) { +function infiltrationBoxCreate(inst) { var totalValue = 0; for (var i = 0; i < inst.secretsStolen.length; ++i) { totalValue += inst.secretsStolen[i]; } if (totalValue == 0) { - dialogBoxCreate("You successfully escaped the facility but you did not steal " + - "anything of worth when infiltrating.

" + - "You gained:
" + - formatNumber(inst.hackingExpGained, 3) + " hacking exp
" + - formatNumber(inst.strExpGained, 3) + " str exp
" + - formatNumber(inst.defExpGained, 3) + " def exp
" + - formatNumber(inst.dexExpGained, 3) + " dex exp
" + - formatNumber(inst.agiExpGained, 3) + " agi exp
" + + dialogBoxCreate("You successfully escaped the facility but you did not steal " + + "anything of worth when infiltrating.

" + + "You gained:
" + + formatNumber(inst.hackingExpGained, 3) + " hacking exp
" + + formatNumber(inst.strExpGained, 3) + " str exp
" + + formatNumber(inst.defExpGained, 3) + " def exp
" + + formatNumber(inst.dexExpGained, 3) + " dex exp
" + + formatNumber(inst.agiExpGained, 3) + " agi exp
" + formatNumber(inst.chaExpGained, 3) + " cha exp
"); return; } var facValue = totalValue * Player.faction_rep_mult * 1.2 var moneyValue = totalValue * CONSTANTS.InfiltrationMoneyValue; - infiltrationSetText("You can sell the classified documents and secrets " + - "you stole from " + inst.companyName + " for $" + - formatNumber(moneyValue, 2) + " on the black market or you can give it " + - "to a faction to gain " + formatNumber(facValue, 3) + " reputation with " + + infiltrationSetText("You can sell the classified documents and secrets " + + "you stole from " + inst.companyName + " for $" + + formatNumber(moneyValue, 2) + " on the black market or you can give it " + + "to a faction to gain " + formatNumber(facValue, 3) + " reputation with " + "that faction."); var selector = document.getElementById("infiltration-faction-select"); selector.innerHTML = ""; for (var i = 0; i < Player.factions.length; ++i) { - selector.innerHTML += ""; } - + var sellButton = clearEventListeners("infiltration-box-sell"); setTimeout(function() { sellButton.addEventListener("click", function() { Player.gainMoney(moneyValue); dialogBoxCreate("You sold the classified information you stole from " + inst.companyName + - " for $" + moneyValue + " on the black market!

" + - "You gained:
" + - formatNumber(inst.hackingExpGained, 3) + " hacking exp
" + - formatNumber(inst.strExpGained, 3) + " str exp
" + - formatNumber(inst.defExpGained, 3) + " def exp
" + - formatNumber(inst.dexExpGained, 3) + " dex exp
" + - formatNumber(inst.agiExpGained, 3) + " agi exp
" + + " for $" + moneyValue + " on the black market!

" + + "You gained:
" + + formatNumber(inst.hackingExpGained, 3) + " hacking exp
" + + formatNumber(inst.strExpGained, 3) + " str exp
" + + formatNumber(inst.defExpGained, 3) + " def exp
" + + formatNumber(inst.dexExpGained, 3) + " dex exp
" + + formatNumber(inst.agiExpGained, 3) + " agi exp
" + formatNumber(inst.chaExpGained, 3) + " cha exp
"); infiltrationBoxClose(); return false; }); }, 750); - + var factionButton = clearEventListeners("infiltration-box-faction"); setTimeout(function() { factionButton.addEventListener("click", function() { @@ -74,18 +81,20 @@ infiltrationBoxCreate = function(inst) { return false; } faction.playerReputation += facValue; - dialogBoxCreate("You gave the classified information you stole from " + inst.companyName + - " to " + facName + " and gained " + formatNumber(facValue, 3) + " reputation with the faction.

" + - "You gained:
" + - formatNumber(inst.hackingExpGained, 3) + " hacking exp
" + - formatNumber(inst.strExpGained, 3) + " str exp
" + - formatNumber(inst.defExpGained, 3) + " def exp
" + - formatNumber(inst.dexExpGained, 3) + " dex exp
" + - formatNumber(inst.agiExpGained, 3) + " agi exp
" + + dialogBoxCreate("You gave the classified information you stole from " + inst.companyName + + " to " + facName + " and gained " + formatNumber(facValue, 3) + " reputation with the faction.

" + + "You gained:
" + + formatNumber(inst.hackingExpGained, 3) + " hacking exp
" + + formatNumber(inst.strExpGained, 3) + " str exp
" + + formatNumber(inst.defExpGained, 3) + " def exp
" + + formatNumber(inst.dexExpGained, 3) + " dex exp
" + + formatNumber(inst.agiExpGained, 3) + " agi exp
" + formatNumber(inst.chaExpGained, 3) + " cha exp
"); infiltrationBoxClose(); return false; }); }, 750); infiltrationBoxOpen(); -} \ No newline at end of file +} + +export {infiltrationBoxCreate}; diff --git a/utils/JSONReviver.js b/utils/JSONReviver.js index b1080ff35..f306c4809 100644 --- a/utils/JSONReviver.js +++ b/utils/JSONReviver.js @@ -17,13 +17,13 @@ function Reviver(key, value) { ctor = Reviver.constructors[value.ctor] || window[value.ctor]; if (typeof ctor === "function" && typeof ctor.fromJSON === "function") { - + return ctor.fromJSON(value); } - } + } return value; } -Reviver.constructors = {}; // A list of constructors the smart reviver should know about +Reviver.constructors = {}; // A list of constructors the smart reviver should know about // A generic "toJSON" function that creates the data expected // by Reviver. @@ -67,3 +67,5 @@ function Generic_fromJSON(ctor, data) { } return obj; } + +export {Reviver, Generic_toJSON, Generic_fromJSON}; diff --git a/utils/LogBox.js b/utils/LogBox.js index 4a0ef4941..4cc62a672 100644 --- a/utils/LogBox.js +++ b/utils/LogBox.js @@ -1,26 +1,15 @@ -/* Log Box */ - -//Close box when clicking outside -/* -$(document).click(function(event) { - if (logBoxOpened) { - if ( $(event.target).closest("#log-box-container").get(0) == null ) { - logBoxClose(); - } - } -}); -*/ +import {printArray} from "./HelperFunctions.js"; $(document).keydown(function(event) { if (logBoxOpened && event.keyCode == 27) { logBoxClose(); } }); - + function logBoxInit() { var closeButton = document.getElementById("log-box-close"); logBoxClose(); - + //Close Dialog box closeButton.addEventListener("click", function() { logBoxClose(); @@ -30,15 +19,15 @@ function logBoxInit() { document.addEventListener("DOMContentLoaded", logBoxInit, false); -logBoxClose = function() { +function logBoxClose() { logBoxOpened = false; var logBox = document.getElementById("log-box-container"); logBox.style.display = "none"; } -logBoxOpen = function() { +function logBoxOpen() { logBoxOpened = true; - + var logBox = document.getElementById("log-box-container"); logBox.style.display = "block"; } @@ -47,13 +36,13 @@ logBoxOpen = function() { var logBoxOpened = false; var logBoxCurrentScript = null; //ram argument is in GB -logBoxCreate = function(script) { +function logBoxCreate(script) { logBoxCurrentScript = script; logBoxOpen(); logBoxUpdateText(); } -logBoxUpdateText = function() { +function logBoxUpdateText() { var txt = document.getElementById("log-box-text"); if (logBoxCurrentScript && logBoxOpened && txt) { txt.innerHTML = logBoxCurrentScript.filename + printArray(logBoxCurrentScript.args) + ":

"; @@ -62,4 +51,6 @@ logBoxUpdateText = function() { txt.innerHTML += "
"; } } -} \ No newline at end of file +} + +export {logBoxCreate, logBoxUpdateText, logBoxOpened, logBoxCurrentScript}; diff --git a/utils/StringHelperFunctions.js b/utils/StringHelperFunctions.js index 73319a473..cd0d4c955 100644 --- a/utils/StringHelperFunctions.js +++ b/utils/StringHelperFunctions.js @@ -1,3 +1,5 @@ +import {dialogBoxCreate} from "./DialogBox.js"; + //Netburner String helper functions //Searches for every occurence of searchStr within str and returns an array of the indices of @@ -31,18 +33,18 @@ String.prototype.replaceAt=function(index, character) { function convertTimeMsToTimeElapsedString(time) { //Convert ms to seconds, since we only have second-level precision time = Math.floor(time / 1000); - + var days = Math.floor(time / 86400); time %= 86400; - + var hours = Math.floor(time / 3600); time %= 3600; - + var minutes = Math.floor(time / 60); time %= 60; - + var seconds = time; - + var res = ""; if (days) {res += days + " days ";} if (hours) {res += hours + " hours ";} @@ -55,8 +57,8 @@ function convertTimeMsToTimeElapsedString(time) { function longestCommonStart(strings) { if (!containsAllStrings(strings)) {return;} if (strings.length == 0) {return;} - - var A = strings.concat().sort(), + + var A = strings.concat().sort(), a1= A[0], a2= A[A.length-1], L= a1.length, i= 0; while(i