From ef23033b2ca70cb98267a4468eabcbebf6902b3c Mon Sep 17 00:00:00 2001 From: Alain Bryden <2285037+alainbryden@users.noreply.github.com> Date: Thu, 25 Nov 2021 23:06:13 -0400 Subject: [PATCH 1/3] #1773 - Fix duplicate file extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some time now, filenames have included the extension, so there's no need to append ".js" either on a single-file download or zip download. While I was in the area, I also fixed .txt files in a folder - they had the same bug as scripts used to (appear in the zip as an underscore). I consolidated the code since it was the same for script files and text files. I also added the ability to download *.js and *.ns (previously only supported *, *.script, and *.txt) I also made the wildcard matching just a bit more flexible, so if someone really wanted to, they could go "download *blah.js" and get all scripts ending with that pattern ¯\_(ツ)_/¯ --- src/Script/Script.ts | 2 +- src/Terminal/commands/download.ts | 56 ++++++++++++------------------- 2 files changed, 22 insertions(+), 36 deletions(-) diff --git a/src/Script/Script.ts b/src/Script/Script.ts index 9e201af88..62d71ede2 100644 --- a/src/Script/Script.ts +++ b/src/Script/Script.ts @@ -56,7 +56,7 @@ export class Script { * Download the script as a file */ download(): void { - const filename = this.filename + ".js"; + const filename = this.filename; const file = new Blob([this.code], { type: "text/plain" }); const navigator = window.navigator as any; if (navigator.msSaveOrOpenBlob) { diff --git a/src/Terminal/commands/download.ts b/src/Terminal/commands/download.ts index b55f91165..cd40319ab 100644 --- a/src/Terminal/commands/download.ts +++ b/src/Terminal/commands/download.ts @@ -19,43 +19,29 @@ export function download( return; } const fn = args[0] + ""; - if (fn === "*" || fn === "*.script" || fn === "*.txt") { - // Download all scripts as a zip + // If the parameter starts with *, download all files that match the wildcard pattern + if (fn.startsWith("*")) { + const matchEnding = fn.length == 1 || fn === "*.*" ? null : fn.slice(1); // Treat *.* the same as * const zip = new JSZip(); - if (fn === "*" || fn === "*.script") { - for (let i = 0; i < server.scripts.length; ++i) { - const file = new Blob([server.scripts[i].code], { - type: "text/plain", - }); - let name = server.scripts[i].filename; - if (name.startsWith("/")) { - name = name.slice(1); - } - zip.file(name + ".js", file); + // Helper function to zip any file contents whose name matches the pattern + let zipFiles = (fileNames: string[], fileContents: string[]) => { + for (let i = 0; i < fileContents.length; ++i) { + let name = fileNames[i]; + if (name.startsWith("/")) name = name.slice(1); + if (!matchEnding || name.endsWith(matchEnding)) + zip.file(name, new Blob([fileContents[i]], { type: "text/plain" })); } - } - if (fn === "*" || fn === "*.txt") { - for (let i = 0; i < server.textFiles.length; ++i) { - const file = new Blob([server.textFiles[i].text], { - type: "text/plain", - }); - zip.file(server.textFiles[i].fn, file); - } - } - - let zipFn = ""; - switch (fn) { - case "*.script": - zipFn = "bitburnerScripts.zip"; - break; - case "*.txt": - zipFn = "bitburnerTexts.zip"; - break; - default: - zipFn = "bitburnerFiles.zip"; - break; - } - + }; + // In the case of script files, we pull from the server.scripts array + if (!matchEnding || isScriptFilename(matchEnding)) + zipFiles(server.scripts.map(s => s.filename), server.scripts.map(s => s.code)); + // In the case of text files, we pull from the server.scripts array + if (!matchEnding || matchEnding.endsWith(".txt")) + zipFiles(server.textFiles.map(s => s.fn), server.textFiles.map(s => s.text)); + // Return an error if no files matched, rather than an empty zip folder + if (Object.keys(zip.files).length == 0) + return terminal.error(`No files match the pattern ${fn}`); + const zipFn = `bitburner${isScriptFilename(fn) ? "Scripts" : fn === "*.txt" ? "Texts" : "Files"}.zip`; zip.generateAsync({ type: "blob" }).then((content: any) => FileSaver.saveAs(content, zipFn)); return; } else if (isScriptFilename(fn)) { From dbde0b8112c6f019dfae4104b4aede39180208f8 Mon Sep 17 00:00:00 2001 From: Alain Bryden <2285037+alainbryden@users.noreply.github.com> Date: Thu, 25 Nov 2021 23:28:23 -0400 Subject: [PATCH 2/3] #1766 Fix blackjack double loss Bet was being removed twice instead of just once. This fact was accounted for in the win and tie if branches, but not the loss branch. --- src/Casino/Blackjack.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Casino/Blackjack.tsx b/src/Casino/Blackjack.tsx index 7a0b88cc8..9219775b1 100644 --- a/src/Casino/Blackjack.tsx +++ b/src/Casino/Blackjack.tsx @@ -75,7 +75,7 @@ export class Blackjack extends Game { } // Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could - // always reload without saving but w.e) + // always reload without saving but w.e) TODO: Save/Restore the RNG state to limit the value of save-scumming. this.props.p.loseMoney(this.state.bet, "casino"); const playerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]); @@ -220,12 +220,11 @@ export class Blackjack extends Game { let gains = 0; if (this.isPlayerWinResult(result)) { gains = this.state.bet; - // We 2x the gains because we took away money at the start, so we need to give the original bet back. this.win(this.props.p, 2 * gains); } else if (result === Result.DealerWon) { gains = -1 * this.state.bet; - this.win(this.props.p, -this.state.bet); // Get the original bet back + this.win(this.props.p, 0); // We took away the bet at the start, don't need to take more // Dont need to take money here since we already did it at the start } else if (result === Result.Tie) { this.win(this.props.p, this.state.bet); // Get the original bet back From f7da154411794e433455a78ccc0aee7ec18045d8 Mon Sep 17 00:00:00 2001 From: Alain Bryden <2285037+alainbryden@users.noreply.github.com> Date: Fri, 26 Nov 2021 00:37:18 -0400 Subject: [PATCH 3/3] Blackjack pays 1.5x, fix appearances I'll lead with this so it doesn't look like I snuck it in: Winning by blackjack is special and usually pays 1.5x so I made it so :) All the infrastructure was already in place. Fixed bkack-on-black text, I didn't even know the game kept count of your cards for you! Improved the way it's displayed a bit (screenshot in PR) Also simplified the code that determines gains and applies the win since there was some duplication there. --- src/Casino/Blackjack.tsx | 54 ++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/src/Casino/Blackjack.tsx b/src/Casino/Blackjack.tsx index 9219775b1..c6c9a5b7a 100644 --- a/src/Casino/Blackjack.tsx +++ b/src/Casino/Blackjack.tsx @@ -217,30 +217,19 @@ export class Blackjack extends Game { }; finishGame = (result: Result): void => { - let gains = 0; - if (this.isPlayerWinResult(result)) { - gains = this.state.bet; - // We 2x the gains because we took away money at the start, so we need to give the original bet back. - this.win(this.props.p, 2 * gains); - } else if (result === Result.DealerWon) { - gains = -1 * this.state.bet; - this.win(this.props.p, 0); // We took away the bet at the start, don't need to take more - // Dont need to take money here since we already did it at the start - } else if (result === Result.Tie) { - this.win(this.props.p, this.state.bet); // Get the original bet back - } - + const gains = result === Result.DealerWon ? 0 : // We took away the bet at the start, don't need to take more + result === Result.Tie ? this.state.bet : // We took away the bet at the start, give it back + result === Result.PlayerWon ? 2 * this.state.bet : // Give back their bet plus their winnings + result === Result.PlayerWonByBlackjack ? 2.5 * this.state.bet : // Blackjack pays out 1.5x bet! + (() => { throw new Error(`Unexpected result: ${result}`); })(); // This can't happen, right? + this.win(this.props.p, gains); this.setState({ gameInProgress: false, result, - gains: this.state.gains + gains, + gains: this.state.gains + gains - this.state.bet, // Not updated upfront - only tracks the final outcome }); }; - isPlayerWinResult = (result: Result): boolean => { - return result === Result.PlayerWon || result === Result.PlayerWonByBlackjack; - }; - wagerOnChange = (event: React.ChangeEvent): void => { const { p } = this.props; const betInput = event.target.value; @@ -356,20 +345,20 @@ export class Blackjack extends Game { )} {/* Main game part. Displays both if the game is in progress OR if there's a result so you can see - * the cards that led to that result. */} + * the cards that led to that result. */} {(gameInProgress || result !== Result.Pending) && ( <> -
Player
+ Player {playerHand.cards.map((card, i) => ( ))} -
Value(s): 
- {playerHandValues.map((value, i) => ( -
{value}
- ))} + Count: { + playerHandValues.map((value, i) => {value}) + .reduce((prev, curr) => [prev, ' or ', curr]) + }
@@ -377,7 +366,7 @@ export class Blackjack extends Game { -
Dealer
+ Dealer {dealerHand.cards.map((card, i) => ( // Hide every card except the first while game is in progress
@@ -399,9 +388,10 @@ export class Blackjack extends Game { {/* Results from previous round */} {result !== Result.Pending && ( - {result} - {this.isPlayerWinResult(result) && } - {result === Result.DealerWon && } + {result}  + {result === Result.PlayerWon && } + {result === Result.PlayerWonByBlackjack && } + {result === Result.DealerWon && } )}