mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-22 06:02:26 +01:00
Implemented Coding Contracts
This commit is contained in:
parent
a114904fd3
commit
fd8bcf35ed
47
doc/source/codingcontracts.rst
Normal file
47
doc/source/codingcontracts.rst
Normal file
@ -0,0 +1,47 @@
|
||||
.. _codingcontracts:
|
||||
|
||||
Coding Contracts
|
||||
================
|
||||
Coding Contracts are a mechanic that lets players earn rewards in
|
||||
exchange for solving programming problems.
|
||||
|
||||
Coding Contracts are files with the ".cct" extensions. They can
|
||||
be accessed through the :ref:`terminal` or through scripts using
|
||||
the :ref:`netscriptcodingcontractapi`
|
||||
|
||||
Each contract has a limited number of attempts. If you
|
||||
provide the wrong answer too many times and exceed the
|
||||
number of attempts, the contract will self destruct (delete itself)
|
||||
|
||||
Currently, Coding Contracts are randomly generated and
|
||||
spawned over time. They can appear on any server (including your
|
||||
home computer), except for your purchased servers.
|
||||
|
||||
|
||||
Running in Terminal
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
To run a Coding Contract in the Terminal, simply use the
|
||||
:ref:`run_terminal_command` command::
|
||||
|
||||
$ run some-contract.cct
|
||||
|
||||
Doing this will bring up a popup. The popup will display
|
||||
the contract's problem, the number of attempts remaining, and
|
||||
an area to provide an answer.
|
||||
|
||||
Interacting through Scripts
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
See :ref:`netscriptcodingcontractapi`.
|
||||
|
||||
Rewards
|
||||
^^^^^^^
|
||||
There are currently four possible rewards for solving a Coding Contract:
|
||||
|
||||
* Faction Reputation for a specific Faction
|
||||
* Faction Reputation for all Factions that you are a member of
|
||||
* Company reputation for a specific Company
|
||||
* Money
|
||||
|
||||
The 'amount' of reward varies based on the difficulty of the problem
|
||||
posed by the Coding Contract. There is no way to know what a
|
||||
Coding Contract's exact reward will be until it is solved.
|
@ -21,6 +21,7 @@ secrets that you've been searching for.
|
||||
|
||||
Netscript <netscript>
|
||||
Terminal <terminal>
|
||||
Coding Contracts <codingcontracts>
|
||||
Keyboard Shortcuts <shortcuts>
|
||||
Changelog <changelog>
|
||||
|
||||
|
@ -25,4 +25,5 @@ to reach out to the developer!
|
||||
Trade Information eXchange (TIX) API <netscriptixapi>
|
||||
Singularity Functions <netscriptsingularityfunctions>
|
||||
Bladeburner API <netscriptbladeburnerapi>
|
||||
Coding Contract API <netscriptcodingcontractapi>
|
||||
Miscellaneous <netscriptmisc>
|
||||
|
@ -1,9 +1,8 @@
|
||||
Netscript Bladeburner API
|
||||
=========================
|
||||
|
||||
Netscript provides the following API for interacting with the game's Bladeburner mechanic.
|
||||
|
||||
The Bladeburner API is **not** immediately available to the palyer and must be unlocked
|
||||
The Bladeburner API is **not** immediately available to the player and must be unlocked
|
||||
later in the game
|
||||
|
||||
**WARNING: This page contains spoilers for the game**
|
||||
@ -12,9 +11,9 @@ The Bladeburner API is unlocked in BitNode-7. If you are in BitNode-7, you will
|
||||
automatically gain access to this API. Otherwise, you must have Source-File 7 in
|
||||
order to use this API in other BitNodes
|
||||
|
||||
**Bladeburner API functions must be accessed through the bladeburner namespace**
|
||||
**Bladeburner API functions must be accessed through the 'bladeburner' namespace**
|
||||
|
||||
In Netscript 1.0::
|
||||
In :ref:`netscript1`::
|
||||
|
||||
bladeburner.getContractNames();
|
||||
bladeburner.startAction("general", "Training");
|
||||
|
74
doc/source/netscriptcodingcontractapi.rst
Normal file
74
doc/source/netscriptcodingcontractapi.rst
Normal file
@ -0,0 +1,74 @@
|
||||
.. _netscriptcodingcontractapi:
|
||||
|
||||
Netscript Coding Contract API
|
||||
=============================
|
||||
Netscript provides the following API for interacting with
|
||||
:ref:`codingcontracts`.
|
||||
|
||||
**The Coding Contract API must be accessed through the 'codingcontract' namespace**
|
||||
|
||||
In :ref:`netscript1`::
|
||||
|
||||
codingcontract.getDescription("foo.cct", "home");
|
||||
codingcontract.attempt(1, "foo.cct", "foodnstuff");
|
||||
|
||||
In :ref:`netscriptjs`::
|
||||
|
||||
ns.codingcontract.getDescription("foo.cct", "home");
|
||||
ns.codingcontract.attempt(1, "foo.cct", "foodnstuff");
|
||||
|
||||
attempt
|
||||
-------
|
||||
|
||||
.. js:function:: attempt(answer, fn[, hostname/ip=current ip])
|
||||
|
||||
:param answer: Solution for the contract
|
||||
:param string fn: Filename of the contract
|
||||
:param string hostname/ip: Hostname or IP of the server containing the contract.
|
||||
Optional. Defaults to current server if not provided
|
||||
|
||||
Attempts to solve the Coding Contract with the provided solution.
|
||||
|
||||
:returns: Boolean indicating whether the solution was correct
|
||||
|
||||
getDescription
|
||||
--------------
|
||||
|
||||
.. js:function:: getDescription(fn[, hostname/ip=current ip])
|
||||
|
||||
:param string fn: Filename of the contract
|
||||
:param string hostname/ip: Hostname or IP of the server containing the contract.
|
||||
Optional. Defaults to current server if not provided
|
||||
|
||||
Get the full text description for the problem posed by the Coding Contract
|
||||
|
||||
:returns: A string with the contract's text description
|
||||
|
||||
getData
|
||||
-------
|
||||
|
||||
.. js:function:: getData(fn[, hostname/ip=current ip])
|
||||
|
||||
:param string fn: Filename of the contract
|
||||
:param string hostname/ip: Hostname or IP of the server containing the contract.
|
||||
Optional. Defaults to current server if not provided
|
||||
|
||||
Get the data associated with the specific Coding Contract. Note that this is
|
||||
not the same as the contract's description. This is just the data that
|
||||
the contract wants you to act on in order to solve
|
||||
|
||||
:returns: The specified contract's data
|
||||
|
||||
getNumTriesRemaining
|
||||
--------------------
|
||||
|
||||
.. js:function:: getNumTriesRemaining(fn[, hostname/ip=current ip])
|
||||
|
||||
:param string fn: Filename of the contract
|
||||
:param string hostname/ip: Hostname or IP of the server containing the contract.
|
||||
Optional. Defaults to current server if not provided
|
||||
|
||||
Get the number of tries remaining on the contract before it
|
||||
self-destructs.
|
||||
|
||||
:returns: Number indicating how many attempts are remaining
|
@ -154,7 +154,7 @@ getScriptLogs
|
||||
scan
|
||||
^^^^
|
||||
|
||||
.. js:function:: scan(hostname/ip[, hostnames=true])
|
||||
.. js:function:: scan(hostname/ip=current ip[, hostnames=true])
|
||||
|
||||
:param string hostname/ip: IP or hostname of the server to scan
|
||||
:param boolean: Optional boolean specifying whether the function should output hostnames (if true) or IP addresses (if false)
|
||||
|
@ -285,12 +285,15 @@ except literature files (.lit).
|
||||
|
||||
**WARNING: This is permanent and cannot be undone**
|
||||
|
||||
|
||||
.. _run_terminal_command:
|
||||
|
||||
run
|
||||
^^^
|
||||
|
||||
$ run [file name] [-t] [num threads] [args...]
|
||||
|
||||
Execute a program or a script.
|
||||
Execute a program, script, or :ref:`codingcontracts`.
|
||||
|
||||
The '[-t]', '[num threads]', and '[args...]' arguments are only valid when
|
||||
running a script. The '-t' flag is used to indicate that the script should
|
||||
@ -305,13 +308,17 @@ argument must be separated by a space.
|
||||
|
||||
**Examples**
|
||||
|
||||
Run a program:
|
||||
Run a program::
|
||||
|
||||
run BruteSSH.exe
|
||||
$ run BruteSSH.exe
|
||||
|
||||
Run *foo.script* with 50 threads and the arguments [1e3, 0.5, foodnstuff]::
|
||||
|
||||
run foo.script -t 50 1e3 0.5 foodnstuff
|
||||
$ run foo.script -t 50 1e3 0.5 foodnstuff
|
||||
|
||||
Run a Coding Contract::
|
||||
|
||||
$ run foo-contract.cct
|
||||
|
||||
scan
|
||||
^^^^
|
||||
|
13
netscript.js
13
netscript.js
@ -78,7 +78,7 @@ let NetscriptFunctions =
|
||||
"getHackTime|getGrowTime|getWeakenTime|getScriptIncome|getScriptExpGain|" +
|
||||
"getTimeSinceLastAug|prompt|" +
|
||||
|
||||
//Singularity Functions
|
||||
// Singularity Functions
|
||||
"universityCourse|getCharacterInformation|" +
|
||||
"gymWorkout|travelToCity|purchaseTor|purchaseProgram|upgradeHomeRam|" +
|
||||
"getUpgradeHomeRamCost|workForCompany|applyToCompany|getCompanyRep|" +
|
||||
@ -91,16 +91,16 @@ let NetscriptFunctions =
|
||||
"getAugmentationCost|purchaseAugmentation|" +
|
||||
"installAugmentations|" +
|
||||
|
||||
//TIX API
|
||||
// TIX API
|
||||
"getStockPrice|getStockPosition|buyStock|sellStock|shortStock|sellShort|" +
|
||||
"placeOrder|cancelOrder|" +
|
||||
|
||||
//Hacknet Node API
|
||||
// Hacknet Node API
|
||||
"hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" +
|
||||
"upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" +
|
||||
"getRamUpgradeCost|getCoreUpgradeCost|" +
|
||||
|
||||
//Bladeburner functions
|
||||
// Bladeburner functions
|
||||
"bladeburner|getContractNames|getOperationNames|getBlackOpNames|" +
|
||||
"getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" +
|
||||
"getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" +
|
||||
@ -109,7 +109,10 @@ let NetscriptFunctions =
|
||||
"getRank|getSkillPoints|getSkillLevel|getSkillUpgradeCost|" +
|
||||
"upgradeSkill|getTeamSize|getCity|" +
|
||||
"setTeamSize|getCityEstimatedPopulation|getCityEstimatedCommunities|" +
|
||||
"getCityChaos|switchCity|getStamina|joinBladeburnerFaction|getBonusTime";
|
||||
"getCityChaos|switchCity|getStamina|joinBladeburnerFaction|getBonusTime|" +
|
||||
|
||||
// Coding Contract API
|
||||
"codingcontract|attempt|getData|getDescription|getNumTriesRemaining";
|
||||
|
||||
var NetscriptHighlightRules = function(options) {
|
||||
var keywordMapper = this.createKeywordMapper({
|
||||
|
@ -70,7 +70,7 @@ export enum CodingContractRewardType {
|
||||
FactionReputation,
|
||||
FactionReputationAll,
|
||||
CompanyReputation,
|
||||
Money, // This must always be the last reward type
|
||||
Money, // This must always be the last reward type
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,6 +137,14 @@ export class CodingContract {
|
||||
this.reward = reward;
|
||||
}
|
||||
|
||||
getData(): any {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return CodingContractTypes[this.type].desc(this.data);
|
||||
}
|
||||
|
||||
getDifficulty(): number {
|
||||
return CodingContractTypes[this.type].difficulty;
|
||||
}
|
||||
@ -155,15 +163,21 @@ export class CodingContract {
|
||||
async prompt(): Promise<CodingContractResult> {
|
||||
// tslint:disable-next-line
|
||||
return new Promise<CodingContractResult>((resolve: Function, reject: Function) => {
|
||||
const contractType: ContractType = CodingContractTypes[this.type];
|
||||
const contractType: CodingContractType = CodingContractTypes[this.type];
|
||||
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
||||
const txt: HTMLElement = createElement("p", {
|
||||
innerText: ["You are attempting to solve a Coding Contract. Note that",
|
||||
"you only have one chance. Providing the wrong solution",
|
||||
"will cause the contract to self-destruct.\n\n",
|
||||
innerText: ["You are attempting to solve a Coding Contract. You have",
|
||||
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
||||
"after which the contract will self-destruct.\n\n",
|
||||
`${contractType.desc(this.data)}`].join(" "),
|
||||
});
|
||||
const answerInput: HTMLInputElement = createElement("input", {
|
||||
onkeydown:(e)=>{
|
||||
if (e.keyCode === 13 && answerInput.value !== "") {
|
||||
e.preventDefault();
|
||||
solveBtn.click();
|
||||
}
|
||||
},
|
||||
placeholder: "Enter Solution here",
|
||||
}) as HTMLInputElement;
|
||||
const solveBtn: HTMLElement = createElement("a", {
|
||||
@ -189,6 +203,7 @@ export class CodingContract {
|
||||
});
|
||||
const lineBreak: HTMLElement = createElement("br");
|
||||
createPopup(popupId, [txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
||||
answerInput.focus();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,7 @@ let CONSTANTS = {
|
||||
ScriptGetScriptRamCost: 0.1,
|
||||
ScriptGetHackTimeRamCost: 0.05,
|
||||
ScriptGetFavorToDonate: 0.10,
|
||||
ScriptGetContractDataRamCost: 25,
|
||||
ScriptAttemptContractRamCost: 25,
|
||||
ScriptCodingContractBaseRamCost:10,
|
||||
|
||||
ScriptSingularityFn1RamCost: 1,
|
||||
ScriptSingularityFn2RamCost: 2,
|
||||
@ -274,7 +273,7 @@ let CONSTANTS = {
|
||||
/* Coding Contract Constants */
|
||||
CodingContractBaseFactionRepGain: 2500,
|
||||
CodingContractBaseCompanyRepGain: 4000,
|
||||
CodingContractBaseMoneyGain: 10e6,
|
||||
CodingContractBaseMoneyGain: 50e6,
|
||||
|
||||
/* Tutorial related things */
|
||||
TutorialNetworkingText: "Servers are a central part of the game. You start with a single personal server (your home computer) " +
|
||||
@ -508,35 +507,13 @@ let CONSTANTS = {
|
||||
LatestUpdate:
|
||||
`
|
||||
v0.40.4<br>
|
||||
* (TODO NEEDS DOCUMENTATION) The write() and read() Netscript functions now work on scripts<br>
|
||||
* It is now possible to use freely use angled bracket (<, >) and create DOM elements using tprint()<br>
|
||||
* Added Coding Contracts (not yet generated in game, but the data/implementation exists)<br>
|
||||
* Added new Coding Contracts mechanic. Solve programming problems to earn rewards
|
||||
* (TODO NEEDS DOCUMENTATION) The write() and read() Netscript functions now work on scripts
|
||||
* It is now possible to use freely use angled bracket (<, >) and create DOM elements using tprint()
|
||||
* The game's theme colors can now be set through the Terminal configuration (.fconf).
|
||||
* You can now switch to the old left-hand main menu bar through the Terminal configuration (.fconf)
|
||||
`
|
||||
|
||||
v0.40.3<br>
|
||||
-----------------------------------------------<br>
|
||||
* Bladeburner Changes:<br>
|
||||
*** Increased the effect that agi and dexterity have on action time<br>
|
||||
*** Starting number of contracts/operations available will be slightly lower<br>
|
||||
*** Random events will now happen slightly more often<br>
|
||||
*** Slightly increased the rate at which the Overclock skill point cost increases<br>
|
||||
-----------------------------------------------<br>
|
||||
* The maximum volatility of stocks is now randomized (randomly generated within a certain range every time the game resets)<br>
|
||||
* Increased the range of possible values for initial stock prices<br>
|
||||
* b1t_flum3.exe program can now be created immediately at Hacking level 1 (rather than hacking level 5)<br>
|
||||
* UI improvements for the character overview panel and the left-hand menu (by mat-jaworski)<br>
|
||||
* General UI improvements for displays and Terminal (by mat-jaworski)<br>
|
||||
* Added optional parameters to the getHackTime(), getGrowTime(), and getWeakenTime() Netscript functions<br>
|
||||
* Added isLogEnabled() and getScriptLogs() Netscript functions<br>
|
||||
* Added donateToFaction() Singularity function<br>
|
||||
* Updated documentation to reflect the fact that Netscript port handles (getPortHandle()) only works in NetscriptJS (2.0), NOT Netscript 1.0<br>
|
||||
* Added tryWrite() Netscript function<br>
|
||||
* When working (for a company/faction), experience is gained immediately/continuously rather than all at once when the work is finished<br>
|
||||
* Added a setting in .fconf for enabling line-wrap in the Terminal input<br>
|
||||
* Adding a game option for changing the locale that most numbers are displayed in (this mostly applies for whenever money is displayed)<br>
|
||||
* The randomized parameters of many high-level servers can now take on a higher range of values<br>
|
||||
* Many 'foreign' servers (hackable servers that you don't own) now have a randomized amount of RAM<br>
|
||||
* Added 'wget' Terminal command<br>
|
||||
* Improved the introductory tutorial`
|
||||
}
|
||||
|
||||
export {CONSTANTS};
|
||||
|
@ -175,7 +175,21 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
};
|
||||
|
||||
//Utility function to get Hacknet Node object
|
||||
/**
|
||||
* Gets the Server for a specific hostname/ip, throwing an error
|
||||
* if the server doesn't exist.
|
||||
* @param {string} Hostname or IP of the server
|
||||
* @returns {Server} The specified Server
|
||||
*/
|
||||
var safeGetServer = function(ip, callingFnName="") {
|
||||
var server = getServer(ip);
|
||||
if (server == null) {
|
||||
throw makeRuntimeRejectMsg(workerScript, `Invalid IP or hostname passed into ${callingFnName}() function`);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
// Utility function to get Hacknet Node object
|
||||
var getHacknetNode = function(i) {
|
||||
if (isNaN(i)) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Invalid index specified for Hacknet Node: " + i);
|
||||
@ -186,6 +200,11 @@ function NetscriptFunctions(workerScript) {
|
||||
return Player.hacknetNodes[i];
|
||||
};
|
||||
|
||||
var getCodingContract = function(fn, ip) {
|
||||
var server = safeGetServer(ip, "getCodingContract");
|
||||
return server.getContract(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} ram The amount of server RAM to calculate cost of.
|
||||
* @exception {Error} If the value passed in is not numeric, out of range, or too large of a value.
|
||||
@ -1057,6 +1076,16 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < server.contracts.length; ++i) {
|
||||
if (filter) {
|
||||
if (server.contracts[i].fn.includes(filter)) {
|
||||
allFiles.push(server.contracts[i].fn);
|
||||
}
|
||||
} else {
|
||||
allFiles.push(server.contracts[i].fn);
|
||||
}
|
||||
}
|
||||
|
||||
//Sort the files alphabetically then print each
|
||||
allFiles.sort();
|
||||
return allFiles;
|
||||
@ -2040,6 +2069,13 @@ function NetscriptFunctions(workerScript) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (fn.endsWith(".cct")) {
|
||||
for (var i = 0; i < s.contracts.length; ++i) {
|
||||
if (s.contracts[i].fn === fn) {
|
||||
s.contracts.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
@ -3947,6 +3983,72 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "getBonusTime() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " +
|
||||
"at the Bladeburner division or because you do not have Source-File 7");
|
||||
}
|
||||
}, // End Bladeburner
|
||||
codingcontract : {
|
||||
attempt : function(answer, fn, ip=workerScript.serverIp) {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("attempt", CONSTANTS.ScriptCodingContractBaseRamCost);
|
||||
}
|
||||
updateDynamicRam("attempt", CONSTANTS.ScriptCodingContractBaseRamCost);
|
||||
const contract = getCodingContract(fn, ip);
|
||||
if (contract == null) {
|
||||
workerScript.log(`ERROR: codingcontract.getData() failed because it could find the specified contract ${fn} on server ${ip}`);
|
||||
return false;
|
||||
}
|
||||
answer = String(answer);
|
||||
const serv = safeGetServer(ip, "codingcontract.attempt()");
|
||||
if (contract.isSolution(answer)) {
|
||||
const reward = Player.gainCodingContractReward(contract.reward, contract.getDifficulty());
|
||||
workerScript.log(`Successfully completed Coding Contract ${fn}. Reward: ${reward}`);
|
||||
serv.removeContract(fn);
|
||||
return true;
|
||||
} else {
|
||||
++contract.tries;
|
||||
if (contract.tries >= contract.getMaxNumTries()) {
|
||||
workerScript.log(`Coding Contract ${fn} failed. Contract is now self-destructing`);
|
||||
serv.removeContract(fn);
|
||||
} else {
|
||||
workerScript.log(`Coding Contract ${fn} failed. ${contract.getMaxNumTries() - contract.tries} attempts remaining`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
getData : function(fn, ip=workerScript.serverIp) {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getData", CONSTANTS.ScriptCodingContractBaseRamCost / 2);
|
||||
}
|
||||
updateDynamicRam("getData", CONSTANTS.ScriptCodingContractBaseRamCost / 2);
|
||||
var contract = getCodingContract(fn, ip);
|
||||
if (contract == null) {
|
||||
workerScript.log(`ERROR: codingcontract.getData() failed because it could find the specified contract ${fn} on server ${ip}`);
|
||||
return null;
|
||||
}
|
||||
return contract.getData();
|
||||
},
|
||||
getDescription : function(fn, ip=workerScript.serverIp) {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getDescription", CONSTANTS.ScriptCodingContractBaseRamCost / 2);
|
||||
}
|
||||
updateDynamicRam("getDescription", CONSTANTS.ScriptCodingContractBaseRamCost / 2);
|
||||
var contract = getCodingContract(fn, ip);
|
||||
if (contract == null) {
|
||||
workerScript.log(`ERROR: codingcontract.getDescription() failed because it could find the specified contract ${fn} on server ${ip}`);
|
||||
return "";
|
||||
}
|
||||
return contract.getDescription();
|
||||
},
|
||||
getNumTriesRemaining : function(fn, ip=workerScript.serverIp) {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getNumTriesRemaining", CONSTANTS.ScriptCodingContractBaseRamCost / 2);
|
||||
}
|
||||
updateDynamicRam("getNumTriesRemaining", CONSTANTS.ScriptCodingContractBaseRamCost / 2);
|
||||
var contract = getCodingContract(fn, ip);
|
||||
if (contract == null) {
|
||||
workerScript.log(`ERROR: codingcontract.getNumTriesRemaining() failed because it could find the specified contract ${fn} on server ${ip}`);
|
||||
return -1;
|
||||
}
|
||||
return contract.getMaxNumTries() - contract.tries;
|
||||
},
|
||||
}
|
||||
} //End return
|
||||
} //End NetscriptFunction()
|
||||
|
@ -2298,12 +2298,26 @@ PlayerObject.prototype.gainCodingContractReward = function(reward, difficulty=1)
|
||||
return `Gained ${repGain} faction reputation for ${reward.name}`;
|
||||
case CodingContractRewardType.FactionReputationAll:
|
||||
const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty;
|
||||
const gainPerFaction = Math.floor(totalGain / this.factions.length);
|
||||
for (const facName of this.factions) {
|
||||
|
||||
// Ignore Bladeburners and other special factions for this calculation
|
||||
const specialFactions = ["Bladeburners"];
|
||||
var factions = this.factions.slice();
|
||||
factions = factions.filter((f) => {
|
||||
return !specialFactions.includes(f);
|
||||
});
|
||||
|
||||
// If the player was only part of the special factions, we'll just give money
|
||||
if (factions.length == 0) {
|
||||
reward.type = CodingContractRewardType.Money;
|
||||
return this.gainCodingContractReward(reward, difficulty);
|
||||
}
|
||||
|
||||
const gainPerFaction = Math.floor(totalGain / factions.length);
|
||||
for (const facName of factions) {
|
||||
if (!(Factions[facName] instanceof Faction)) { continue; }
|
||||
Factions[facName].playerReputation += gainPerFaction;
|
||||
}
|
||||
return `Gained ${gainPerFaction} reputation for each faction you are a member of`;
|
||||
return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.toString()}`;
|
||||
break;
|
||||
case CodingContractRewardType.CompanyReputation:
|
||||
if (reward.name == null || !(Companies[reward.name] instanceof Company)) {
|
||||
|
@ -531,10 +531,12 @@ function parseOnlyRamCalculate(server, code, workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
//Special logic for Bladeburner
|
||||
//Special logic for namespaces (Bladeburner, CodingCOntract)
|
||||
var func;
|
||||
if (ref in workerScript.env.vars.bladeburner) {
|
||||
func = workerScript.env.vars.bladeburner[ref];
|
||||
} else if (ref in workerScript.env.vars.codingcontract) {
|
||||
func = workerScript.env.vars.codingcontract[ref];
|
||||
} else {
|
||||
func = workerScript.env.get(ref);
|
||||
}
|
||||
|
@ -458,35 +458,42 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
|
||||
}
|
||||
|
||||
if (input.startsWith("rm ")) {
|
||||
for (var i = 0; i < currServ.scripts.length; ++i) {
|
||||
for (let i = 0; i < currServ.scripts.length; ++i) {
|
||||
allPos.push(currServ.scripts[i].filename);
|
||||
}
|
||||
for (var i = 0; i < currServ.programs.length; ++i) {
|
||||
for (let i = 0; i < currServ.programs.length; ++i) {
|
||||
allPos.push(currServ.programs[i]);
|
||||
}
|
||||
for (var i = 0; i < currServ.messages.length; ++i) {
|
||||
for (let i = 0; i < currServ.messages.length; ++i) {
|
||||
if (!(currServ.messages[i] instanceof Message) && isString(currServ.messages[i]) &&
|
||||
currServ.messages[i].endsWith(".lit")) {
|
||||
allPos.push(currServ.messages[i]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < currServ.textFiles.length; ++i) {
|
||||
for (let i = 0; i < currServ.textFiles.length; ++i) {
|
||||
allPos.push(currServ.textFiles[i].fn);
|
||||
}
|
||||
for (let i = 0; i < currServ.contracts.length; ++i) {
|
||||
allPos.push(currServ.contracts[i].fn);
|
||||
}
|
||||
return allPos;
|
||||
}
|
||||
|
||||
if (input.startsWith("run ")) {
|
||||
//All programs and scripts
|
||||
for (var i = 0; i < currServ.scripts.length; ++i) {
|
||||
//All programs, scripts, and contracts
|
||||
for (let i = 0; i < currServ.scripts.length; ++i) {
|
||||
allPos.push(currServ.scripts[i].filename);
|
||||
}
|
||||
|
||||
//Programs are on home computer
|
||||
var homeComputer = Player.getHomeComputer();
|
||||
for(var i = 0; i < homeComputer.programs.length; ++i) {
|
||||
for (let i = 0; i < homeComputer.programs.length; ++i) {
|
||||
allPos.push(homeComputer.programs[i]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < currServ.contracts.length; ++i) {
|
||||
allPos.push(currServ.contracts[i].fn);
|
||||
}
|
||||
return allPos;
|
||||
}
|
||||
|
||||
@ -1341,6 +1348,13 @@ let Terminal = {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (delTarget.endsWith(".cct")) {
|
||||
for (var i = 0; i < s.contracts.length; ++i) {
|
||||
if (s.contracts[i].fn === delTarget) {
|
||||
s.contracts.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
post("Error: No such file exists");
|
||||
break;
|
||||
@ -2154,13 +2168,14 @@ let Terminal = {
|
||||
if (Terminal.contractOpen) {
|
||||
return post("ERROR: There's already a Coding Contract in Progress");
|
||||
}
|
||||
Terminal.contractOpen = true;
|
||||
|
||||
const serv = Player.getCurrentServer();
|
||||
const contract = serv.getContract(contractName);
|
||||
if (contract == null) {
|
||||
return post("ERROR: No such contract");
|
||||
}
|
||||
|
||||
Terminal.contractOpen = true;
|
||||
const res = await contract.prompt();
|
||||
|
||||
switch (res) {
|
||||
@ -2170,10 +2185,12 @@ let Terminal = {
|
||||
serv.removeContract(contract);
|
||||
break;
|
||||
case CodingContractResult.Failure:
|
||||
post("Contract <p style='color:red;display:inline'>FAILED</p> - Contract is now self-destructing");
|
||||
++contract.tries;
|
||||
if (contract.tries >= contract.getMaxNumTries()) {
|
||||
post("Contract <p style='color:red;display:inline'>FAILED</p> - Contract is now self-destructing");
|
||||
serv.removeContract(contract);
|
||||
} else {
|
||||
post(`Contract <p style='color:red;display:inline'>FAILED</p> - ${contract.getMaxNumTries() - contract.tries} tries remaining`);
|
||||
}
|
||||
break;
|
||||
case CodingContractResult.Cancelled:
|
||||
@ -2182,6 +2199,7 @@ let Terminal = {
|
||||
break;
|
||||
}
|
||||
Terminal.contractOpen = false;
|
||||
console.log(Terminal.contractOpen);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,28 @@ export interface ICodingContractTypeMetadata {
|
||||
solver: SolverFunc;
|
||||
}
|
||||
|
||||
/* Helper functions for Coding Contract implementations */
|
||||
function removeBracketsFromArrayString(str: string) {
|
||||
let strCpy: string = str;
|
||||
if (strCpy.startsWith("[")) { strCpy = strCpy.slice(1); }
|
||||
if (strCpy.endsWith("]")) { strCpy = strCpy.slice(-1); }
|
||||
|
||||
return strCpy;
|
||||
}
|
||||
|
||||
function convert2DArrayToString(arr: any[][]) {
|
||||
let res = "";
|
||||
const components: string[] = [];
|
||||
arr.forEach((e) => {
|
||||
let s = e.toString();
|
||||
s = ["[", s, "]"].join("");
|
||||
components.push(s);
|
||||
});
|
||||
|
||||
res = components.join(",");
|
||||
return res.replace(/\s/g, "");
|
||||
}
|
||||
|
||||
export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
{
|
||||
desc: (n: number) => {
|
||||
@ -136,6 +158,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
const matrix: number[][] = [];
|
||||
matrix.length = m;
|
||||
for (let i: number = 0; i < m; ++i) {
|
||||
matrix[i] = [];
|
||||
matrix[i].length = n;
|
||||
}
|
||||
|
||||
@ -187,7 +210,9 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
}
|
||||
if (++l > r) { break; }
|
||||
}
|
||||
const playerAns: any[] = ans.split(",");
|
||||
|
||||
const sanitizedPlayerAns: string = removeBracketsFromArrayString(ans);
|
||||
const playerAns: any[] = sanitizedPlayerAns.split(",");
|
||||
for (let i: number = 0; i < playerAns.length; ++i) {
|
||||
playerAns[i] = parseInt(playerAns[i], 10);
|
||||
}
|
||||
@ -282,22 +307,21 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
}
|
||||
result.push([start, end]);
|
||||
|
||||
const sanitizedResult: string = result
|
||||
.toString()
|
||||
.replace(/\s/g, "");
|
||||
const sanitizedResult: string = convert2DArrayToString(result);
|
||||
const sanitizedAns: string = ans.replace(/\s/g, "");
|
||||
|
||||
return sanitizedResult === sanitizedAns;
|
||||
return (sanitizedResult === sanitizedAns ||
|
||||
sanitizedResult === removeBracketsFromArrayString(sanitizedAns));
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: (data: string) => {
|
||||
return ["Given the following string containing only digits, determine",
|
||||
return ["Given the following string containing only digits, return",
|
||||
"an array with all possible valid IP address combinations",
|
||||
"that can be created from the string:\n\n",
|
||||
`${data}\n\n`,
|
||||
"Example:\n\n",
|
||||
"'25525511135' -> ['255.255.11.135', '255.255.111.35']"].join(" ");
|
||||
"25525511135 -> [255.255.11.135, 255.255.111.35]"].join(" ");
|
||||
},
|
||||
difficulty: 3,
|
||||
gen: () => {
|
||||
@ -425,7 +449,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
return ["You are given the following array of stock prices where the i-th element",
|
||||
"represents the stock price on day i:\n\n",
|
||||
`${data}\n\n`,
|
||||
"Determine the maximum possible profit you can earn using at most ",
|
||||
"Determine the maximum possible profit you can earn using at most",
|
||||
"two transactions. A transaction is defined as buying",
|
||||
"and then selling one share of the stock. Note that you cannot",
|
||||
"engage in multiple transactions at once. In other words, you",
|
||||
|
@ -917,7 +917,6 @@ const Engine = {
|
||||
},
|
||||
|
||||
updateGame: function(numCycles = 1) {
|
||||
//Update total playtime
|
||||
var time = numCycles * Engine._idleSpeed;
|
||||
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
|
||||
if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;}
|
||||
@ -1155,20 +1154,66 @@ const Engine = {
|
||||
}
|
||||
|
||||
if (Engine.Counters.contractGeneration <= 0) {
|
||||
// 5% chance of a contract being generated
|
||||
if (Math.random() <= 0.05) {
|
||||
// 20% chance of a contract being generated
|
||||
if (Math.random() < 0.2) {
|
||||
// First select a random problem type
|
||||
let problemTypes = Object.keys(CodingContractTypes);
|
||||
const problemTypes = Object.keys(CodingContractTypes);
|
||||
let randIndex = getRandomInt(0, problemTypes.length - 1);
|
||||
let problemType = CodingContractTypes[problemTypes[randIndex]];
|
||||
let problemType = problemTypes[randIndex];
|
||||
|
||||
// Then select a random reward type. 'Money' will always be the last reward type
|
||||
let rewardType = getRandomInt(1, CodingContractRewardType.Money);
|
||||
var reward = {};
|
||||
reward.type = getRandomInt(0, CodingContractRewardType.Money);
|
||||
|
||||
// Change type based on certain conditions
|
||||
if (Player.factions.length === 0) { reward.type = CodingContractRewardType.CompanyReputation; }
|
||||
if (Player.companyName === "") { reward.type = CodingContractRewardType.Money; }
|
||||
|
||||
// Add additional information based on the reward type
|
||||
switch (rewardType) {
|
||||
case CodingContractRewardType
|
||||
switch (reward.type) {
|
||||
case CodingContractRewardType.FactionReputation:
|
||||
// Get a random faction that player is a part of. That
|
||||
//faction must allow hacking contracts
|
||||
var numFactions = Player.factions.length;
|
||||
var randFaction = Player.factions[getRandomInt(0, numFactions - 1)];
|
||||
try {
|
||||
while(Factions[randFaction].getInfo().offerHackingWork !== true) {
|
||||
randFaction = Player.factions[getRandomInt(0, numFactions - 1)];
|
||||
}
|
||||
reward.name = randFaction;
|
||||
} catch (e) {
|
||||
exceptionAlert("Failed to find a faction for Coding Contract Generation: " + e);
|
||||
}
|
||||
|
||||
break;
|
||||
case CodingContractRewardType.CompanyReputation:
|
||||
if (Player.companyName !== "") {
|
||||
reward.name = Player.companyName;
|
||||
} else {
|
||||
reward.type = CodingContractRewardType.Money;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Choose random server
|
||||
const servers = Object.keys(AllServers);
|
||||
randIndex = getRandomInt(0, servers.length - 1);
|
||||
var randServer = AllServers[servers[randIndex]];
|
||||
while (randServer.purchasedByPlayer === true) {
|
||||
randIndex = getRandomInt(0, servers.length - 1);
|
||||
randServer = AllServers[servers[randIndex]];
|
||||
}
|
||||
|
||||
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
|
||||
while (randServer.contracts.filter((c) => {return c.fn === contractFn}).length > 0) {
|
||||
contractFn = `contract-${getRandomInt(0, 1e6)}`;
|
||||
}
|
||||
if (reward.name) { contractFn += `-${reward.name.replace(/\s/g, "")}`; }
|
||||
let contract = new CodingContract(contractFn, problemType, reward);
|
||||
|
||||
randServer.addContract(contract);
|
||||
}
|
||||
Engine.Counters.contractGeneration = 3000;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ interface ICreateElementListenerOptions {
|
||||
clickListener?(this: HTMLElement, ev: MouseEvent): any;
|
||||
inputListener?(this: HTMLElement, ev: Event): any;
|
||||
onfocus?(this: HTMLElement, ev: FocusEvent): any;
|
||||
onkeydown?(this: HTMLElement, ev: KeyboardEvent): any;
|
||||
onkeyup?(this: HTMLElement, ev: KeyboardEvent): any;
|
||||
}
|
||||
|
||||
@ -148,6 +149,9 @@ function setElementListeners(el: HTMLElement, params: ICreateElementListenerOpti
|
||||
if (params.onkeyup !== undefined) {
|
||||
el.addEventListener("keyup", params.onkeyup);
|
||||
}
|
||||
if (params.onkeydown !== undefined) {
|
||||
el.addEventListener("keydown", params.onkeydown);
|
||||
}
|
||||
if (params.onfocus !== undefined) {
|
||||
el.addEventListener("focus", params.onfocus);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user