v0.29.3 Changed - Bug fixes for new player-defined Netscript functions. Rebalancing/bug fixes for Infiltration and Hacking Mission. Added function name autocompletion in Script Editor

This commit is contained in:
danielyxie 2017-10-03 20:50:13 -05:00
parent 51c37176f1
commit 0927c4251e
9 changed files with 4351 additions and 2248 deletions

6451
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

@ -696,6 +696,7 @@
<a id="location-purchase-1tb" class="a-link-button"> Purchase 1TB Server - $75,000,000</a>
<a id="location-purchase-tor" class="a-link-button"> Purchase TOR Router - $100,000</a>
<a id="location-purchase-home-ram" class="a-link-button"> Purchase additional RAM for Home computer </a>
<!--<a id="location-purchase-home-cores" class="a-link-button"> Purchase additional Core for Home computer </a>-->
<!-- Infiltrate -->
<a id="location-infiltrate" class="a-link-button tooltip"> Infiltrate Company

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.29.2",
Version: "0.29.3",
//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
@ -116,17 +116,18 @@ let CONSTANTS = {
IntelligenceCrimeWeight: 0.05, //Weight for how much int affects crime success rates
IntelligenceInfiltrationWeight: 0.1, //Weight for how much int affects infiltration success rates
IntelligenceCrimeBaseExpGain: 0.001,
IntelligenceProgramBaseExpGain: 1000, //Program required hack level divided by this to determine int exp gain
IntelligenceProgramBaseExpGain: 500, //Program required hack level divided by this to determine int exp gain
IntelligenceTerminalHackBaseExpGain: 200, //Hacking exp divided by this to determine int exp gain
IntelligenceSingFnBaseExpGain: 0.0005,
IntelligenceClassBaseExpGain: 0.0000001,
IntelligenceClassBaseExpGain: 0.0000005,
//Hacking Missions
HackingMissionRepToDiffConversion: 10000, //Faction rep is divided by this to get mission difficulty
HackingMissionRepToRewardConversion: 10, //Faction rep divided byt his to get mission rep reward
HackingMissionSpamTimeIncrease: 15000, //How much time limit increase is gained when conquering a Spam Node (ms)
HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
HackingMissionMiscDefenseIncrease: 10, //The amount by which every misc node's defense increases when one is conquered
HackingMissionMiscDefenseIncrease: 1.12, //The amount by which every misc node's defense is multiplied when one is conquered
HackingMissionDifficultyToHacking: 120, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc)
HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.<br><br>" +
"In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " +
"are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " +
@ -168,7 +169,7 @@ let CONSTANTS = {
"or press 'd'.<br><br>" +
"Other Notes:<br><br>" +
"-Whenever you conquer a miscellenaous Node (not owned by the enemy), the defense of all remaining miscellaneous Nodes will increase " +
"by a smal fixed amount.",
"by a fixed percentage.",
//Gang constants
@ -1019,6 +1020,10 @@ let CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>",
LatestUpdate:
"v0.29.3<br>" +
"-Fixed bug for killing scripts and showing error messages when there are errors in a player-defined function<br>" +
"-Added function name autocompletion in Script Editor. Press Ctrl+space on a prefix to show autocompletion options.<br>" +
"-Minor rebalancing and bug fixes for Infiltration<br><br>" +
"v0.29.2<br>" +
"-installAugmentations() Singularity Function now takes a callback script as an argument. This is a script " +
"that gets ran automatically after Augmentations are installed. The script is run with no arguments and only a single thread, " +

@ -601,7 +601,7 @@ function getInfiltrationKillChance(inst) {
return Math.min(0.95,
(Player.strength +
Player.dexterity +
Player.agility) / (1.5 * lvl));
Player.agility) / (1.45 * lvl));
}
@ -627,7 +627,7 @@ function getInfiltrationKnockoutChance(inst) {
return Math.min(0.95,
(Player.strength +
Player.dexterity +
Player.agility) / (1.75 * lvl));
Player.agility) / (1.7 * lvl));
}
//Stealth knockout
@ -648,7 +648,7 @@ function attemptInfiltrationStealthKnockout(inst) {
function getInfiltrationStealthKnockoutChance(inst) {
var lvl = inst.securityLevel;
return Math.min(0.95,
(0.5 * Player.strength +
(0.55 * Player.strength +
2 * Player.dexterity +
2 * Player.agility +
intWgt * Player.intelligence) / (3 * lvl));

@ -203,7 +203,7 @@ HackingMission.prototype.init = function() {
var home = Player.getHomeComputer()
for (var i = 0; i < home.cpuCores; ++i) {
var stats = {
atk: (Player.hacking_skill / 6),
atk: (Player.hacking_skill / 5),
def: (Player.hacking_skill / 20),
hp: (Player.hacking_skill / 5),
};
@ -214,7 +214,7 @@ HackingMission.prototype.init = function() {
}
//Randomly generate enemy nodes (CPU and Firewall) based on difficulty
var numNodes = this.difficulty;
var numNodes = Math.max(1, Math.round(this.difficulty / 3));
var numFirewalls = getRandomInt(this.difficulty, this.difficulty + 1);
var numDatabases = getRandomInt(this.difficulty, this.difficulty + 1);
var totalNodes = numNodes + numFirewalls + numDatabases;
@ -223,10 +223,11 @@ HackingMission.prototype.init = function() {
console.log("numFirewalls: " + numFirewalls);
console.log("numDatabases: " + numDatabases);
console.log("totalNodes: " + totalNodes);
var randMult = addOffset(this.difficulty, 20);
console.log("xlimit: " + xlimit);
var randMult = addOffset(0.85 + (this.difficulty / 6), 10);
for (var i = 0; i < numNodes; ++i) {
var stats = {
atk: randMult * getRandomInt(40, 60),
atk: randMult * getRandomInt(50, 75),
def: randMult * getRandomInt(20, 40),
hp: randMult * getRandomInt(100, 120)
}
@ -246,7 +247,7 @@ HackingMission.prototype.init = function() {
}
for (var i = 0; i < numDatabases; ++i) {
var stats = {
atk: randMult * getRandomInt(10, 20),
atk: 0,
def: randMult * getRandomInt(20, 30),
hp: randMult * getRandomInt(120, 150)
}
@ -586,6 +587,10 @@ HackingMission.prototype.setNodePosition = function(nodeObj, x, y) {
HackingMission.prototype.setNodeRandomPosition = function(nodeObj, xlimit=0) {
var i = getRandomInt(0, this.availablePositions.length - 1);
if (this.availablePositions[i][1] < xlimit) {
//Recurse if not within limit
return this.setNodeRandomPosition(nodeObj, xlimit);
}
var pos = this.availablePositions.splice(i, 1);
pos = pos[0];
this.setNodePosition(nodeObj, pos[0], pos[1]);
@ -604,7 +609,7 @@ HackingMission.prototype.createMap = function() {
for (var y = 0; y < 8; ++y) {
if (!(this.map[x][y] instanceof Node)) {
var node, type = getRandomInt(0, 2);
var randMult = addOffset(this.difficulty, 20);
var randMult = addOffset(0.75 + (this.difficulty / 3), 20);
switch (type) {
case 0: //Spam
var stats = {
@ -828,6 +833,7 @@ HackingMission.prototype.nodeReachable = function(node) {
}
HackingMission.prototype.nodeReachableByEnemy = function(node) {
if (node === null) {return false;}
var x = node.pos[0], y = node.pos[1];
if (x > 0 && this.map[x-1][y].enmyCtrl) {return true;}
if (x < 7 && this.map[x+1][y].enmyCtrl) {return true;}
@ -987,11 +993,18 @@ HackingMission.prototype.process = function(numCycles=1) {
this.calculateDefenses();
}
//Win if all enemy databases are conquered
if (this.enemyDatabases.length === 0) {
this.finishMission(true);
return;
}
//Lose if all your cores are gone
if (this.playerCores.length === 0) {
this.finishMission(false);
return;
}
//Defense of every misc Node increase by 0.5 per second
this.miscNodes.forEach((node)=>{
node.def += (0.1 * storedCycles);
@ -1037,22 +1050,23 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
}
//Calculations are per second, so divide everything by 5
var calcStats = false;
var calcStats = false, plyr = nodeObj.plyrCtrl;
var enmyHacking = this.difficulty * CONSTANTS.HackingMissionDifficultyToHacking;
switch(nodeObj.action) {
case NodeActions.Attack:
if (nodeObj.conn === null) {break;}
var dmg = this.calculateAttackDamage(atk, def, Player.hacking_skill);
var dmg = this.calculateAttackDamage(atk, def, plyr ? Player.hacking_skill : enmyHacking);
targetNode.hp -= (dmg/5 * numCycles);
break;
case NodeActions.Scan:
if (nodeObj.conn === null) {break;}
var eff = this.calculateScanEffect(atk, def, Player.hacking_skill);
var eff = this.calculateScanEffect(atk, def, plyr ? Player.hacking_skill : enmyHacking);
targetNode.def -= (eff/5 * numCycles);
calcStats = true;
break;
case NodeActions.Weaken:
if (nodeObj.conn === null) {break;}
var eff = this.calculateWeakenEffect(atk, def, Player.hacking_skill);
var eff = this.calculateWeakenEffect(atk, def, plyr ? Player.hacking_skill : enmyHacking);
targetNode.atk -= (eff/5 * numCycles);
calcStats = true;
break;
@ -1086,7 +1100,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
targetNode.action = null;
targetNode.conn = null;
if (this.selectedNode == targetNode) {
targetNode.deselect();
targetNode.deselect(this.actionButtons);
}
//Flag for whether the target node was a misc node
@ -1191,9 +1205,11 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
}
//If a misc node was conquered, the defense for all misc nodes increases by some fixed amount
this.miscNodes.forEach((node)=>{
node.def += CONSTANTS.HackingMissionMiscDefenseIncrease;
});
if (isMiscNode && conqueredByPlayer) {
this.miscNodes.forEach((node)=>{
node.def *= CONSTANTS.HackingMissionMiscDefenseIncrease;
});
}
}
//Update node DOMs
@ -1214,7 +1230,12 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
if (this.miscNodes.length === 0) {
//Randomly pick a player node and attack it if its reachable
var rand = getRandomInt(0, this.playerNodes.length-1);
var node = this.playerNodes[rand];
var node;
if (this.playerNodes.length === 0) {
node = null;
} else {
node = this.playerNodes[rand];
}
if (this.nodeReachableByEnemy(node)) {
//Create connection
console.log("Enemy core selected a Player Node as target");
@ -1225,7 +1246,12 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
} else {
//Randomly pick a player core and attack it if its reachable
rand = getRandomInt(0, this.playerCores.length-1);
node = this.playerCores[rand];
if (this.playerCores.length === 0) {
return; //No Misc Nodes, no player Nodes, no Player cores. Player lost
} else {
node = this.playerCores[rand];
}
if (this.nodeReachableByEnemy(node)) {
//Create connection
console.log("Enemy core selected a Player Core as target");
@ -1251,6 +1277,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
//If no connection was made, set the Core to Fortify
nodeObj.action = NodeActions.Fortify;
} else {
//If this node has a selected target
var targetNode;
if (nodeObj.conn.target) {
targetNode = this.getNodeFromElement(nodeObj.conn.target);
@ -1261,7 +1288,13 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
console.log("Error getting Target node Object in enemyAISelectAction()");
}
if (targetNode.def > this.enemyAtk - 25) {
if (targetNode.def > this.enemyAtk + 25) {
if (nodeObj.def < 50) {
nodeObj.action = NodeActions.Fortify;
} else {
nodeObj.action = NodeActions.Overflow;
}
} else if (Math.abs(targetNode.def - this.enemyAtk) <= 25) {
nodeObj.action = NodeActions.Scan;
} else {
nodeObj.action = NodeActions.Attack;
@ -1291,11 +1324,11 @@ HackingMission.prototype.calculateAttackDamage = function(atk, def, hacking = 0)
}
HackingMission.prototype.calculateScanEffect = function(atk, def, hacking=0) {
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 1);
return Math.max((atk) + hacking / hackEffWeightTarget - def, 1);
}
HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) {
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 1);
return Math.max((atk) + hacking / hackEffWeightTarget - def, 1);
}
HackingMission.prototype.calculateFortifyEffect = function(hacking=0) {

@ -84,8 +84,6 @@ function evaluate(exp, workerScript) {
//Create new Environment for the function
//Should be automatically garbage collected...
var funcEnv = env.extend();
console.log("Printing new environment for function:");
console.log(funcEnv);
//Define function arguments in this new environment
for (var i = 0; i < func.params.length; ++i) {
@ -105,7 +103,23 @@ function evaluate(exp, workerScript) {
evaluate(func.body, funcWorkerScript).then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
if (isString(e)) {
reject(makeRuntimeRejectMsg(workerScript, e));
} else if (e instanceof WorkerScript) {
//Parse out the err message from the WorkerScript and re-reject
var errorMsg = e.errorMessage;
var errorTextArray = errorMsg.split("|");
console.log("Printing error message from Function:");
console.log(errorMsg);
if (errorTextArray.length === 4) {
errorMsg = errorTextArray[3];
reject(makeRuntimeRejectMsg(workerScript, errorMsg));
} else {
reject(makeRuntimeRejectMsg(workerScript, "Error in one of your functions. Could not identify which function"));
}
} else if (e instanceof Error) {
reject(makeRuntimeRejectMsg(workerScript, e.toString()));
}
});
} else if (exp.callee.type == "MemberExpression"){
evaluate(exp.callee.object, workerScript).then(function(object) {

@ -665,8 +665,7 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) {
txt = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " <br><br> " +
"Since you cancelled your work early, you only gained half of the reputation you earned. <br><br>" + txt;
} else {
txt = "You worked a full shift of 8 hours! <br><br> " +
"You earned a total of: <br>" + txt;
txt = "You worked a full shift of 8 hours! <br><br> " + txt;
}
if (!sing) {dialogBoxCreate(txt);}
@ -1483,16 +1482,16 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
break;
case CONSTANTS.CrimeKidnap:
this.karma -= 6;
this.gainIntelligenceExp(CONSTANTS.IntelligenceCrimeBaseExpGain);
this.gainIntelligenceExp(2 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeAssassination:
++this.numPeopleKilled;
this.karma -= 10;
this.gainIntelligenceExp(CONSTANTS.IntelligenceCrimeBaseExpGain);
this.gainIntelligenceExp(5 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeHeist:
this.karma -= 15;
this.gainIntelligenceExp(5 * CONSTANTS.IntelligenceCrimeBaseExpGain);
this.gainIntelligenceExp(10 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
default:
console.log(this.crimeType);

@ -11,11 +11,13 @@ require('brace/theme/twilight');
require('brace/theme/xcode');
require("brace/keybinding/vim");
require("brace/keybinding/emacs");
require("brace/ext/language_tools");
import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
import {iTutorialSteps, iTutorialNextStep,
iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js";
import {NetscriptFunctions} from "./NetscriptFunctions.js";
import {addWorkerScript, killWorkerScript} from "./NetscriptWorker.js";
import {Player} from "./Player.js";
import {AllServers, processSingleServerGrowth} from "./Server.js";
@ -101,6 +103,26 @@ function scriptEditorInit() {
saveAndCloseScriptEditor();
});
});
//Function autocompleter
editor.setOption("enableBasicAutocompletion", true);
var autocompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {callback(null, []); return;}
var words = [];
var fns = NetscriptFunctions(null);
for (var name in fns) {
if (fns.hasOwnProperty(name)) {
words.push({
name: name,
value: name,
});
}
}
callback(null, words);
},
}
editor.completers = [autocompleter];
}
document.addEventListener("DOMContentLoaded", scriptEditorInit, false);

@ -508,7 +508,7 @@ let Engine = {
" (" + numeral(Player.agility_exp).format('(0.000a)') + ' experience)<br>' +
'Charisma: ' + (Player.charisma).toLocaleString() +
" (" + numeral(Player.charisma_exp).format('(0.000a)') + ' experience)<br>' +
intText +
intText +
'<b>Multipliers</b><br><br>' +
'Hacking Chance multiplier: ' + formatNumber(Player.hacking_chance_mult * 100, 2) + '%<br>' +
'Hacking Speed multiplier: ' + formatNumber(Player.hacking_speed_mult * 100, 2) + '%<br>' +
@ -1146,6 +1146,8 @@ let Engine = {
initLiterature();
initSingularitySFFlags();
console.log(Player.intelligence_exp);
//Calculate the number of cycles have elapsed while offline
Engine._lastUpdate = new Date().getTime();
var lastUpdate = Player.lastUpdate;