From 463948fa73c3de9871fb9d1da4c30400c076dc47 Mon Sep 17 00:00:00 2001
From: Leonard Craft III <leonardcraft64@gmail.com>
Date: Wed, 1 Nov 2023 23:24:15 -0500
Subject: [PATCH] Support more variable best-of challenges (#2173)

---
 js/client-mainmenu.js | 21 +++++++++++++--------
 js/client.js          |  3 +++
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/js/client-mainmenu.js b/js/client-mainmenu.js
index a992382ae5..a241984106 100644
--- a/js/client-mainmenu.js
+++ b/js/client-mainmenu.js
@@ -896,8 +896,9 @@
 			buf += '<p><label class="label">Format:</label>' + this.renderFormats(format) + '</p>';
 			buf += '<p><label class="label">Team:</label>' + this.renderTeams(format) + '</p>';
 			buf += '<p><label class="checkbox"><input type="checkbox" name="private" ' + (Storage.prefs('disallowspectators') ? 'checked' : '') + ' /> <abbr title="You can still invite spectators by giving them the URL or using the /invite command">Don\'t allow spectators</abbr></label></p>';
-			buf += '<p' + (!(format && format.includes('vgc')) ? ' class="hidden">' : '>');
-			buf += '<label class="checkbox"><input type="checkbox" name="bestof" /> <abbr title="Start a team-locked best-of-3 series">Best-of-3</abbr></label></p>';
+			var bestOfDefault = format ? BattleFormats[format].bestOfDefault : false;
+			buf += '<p' + (!bestOfDefault ? ' class="hidden">' : '>');
+			buf += '<label class="checkbox"><input type="checkbox" name="bestof" /> <abbr title="Start a team-locked best-of-n series">Best-of-<input name="bestofvalue" type="number" min="3" max="9" step="2" value="3" style="width: 28px; vertical-align: initial;"></abbr></label></p>';
 			buf += '<p class="buttonbar"><button name="makeChallenge"><strong>Challenge</strong></button> <button type="button" name="dismissChallenge">Cancel</button></p></form>';
 			$challenge.html(buf);
 		},
@@ -942,11 +943,12 @@
 			var teamIndex = $pmWindow.find('button[name=team]').val();
 			var privacy = this.adjustPrivacy($pmWindow.find('input[name=private]').is(':checked'));
 
-			var bestof = $pmWindow.find('input[name=bestof]').is(':checked');
-			var hasCustomRules = format.includes('@@@');
-			if (bestof) {
+			var bestOf = $pmWindow.find('input[name=bestof]').is(':checked');
+			var bestOfValue = $pmWindow.find('input[name=bestofvalue]').val();
+			if (bestOf && bestOfValue) {
+				var hasCustomRules = format.includes('@@@');
 				format += hasCustomRules ? ', ' : '@@@';
-				format += 'Best of = 3';
+				format += 'Best of = ' + bestOfValue;
 			}
 
 			var team = null;
@@ -1381,10 +1383,13 @@
 				if ($teamButton.length) $teamButton.replaceWith(app.rooms[''].renderTeams(format));
 
 				var $bestOfCheckbox = this.sourceEl.closest('form').find('input[name=bestof]');
-				if ($bestOfCheckbox) {
+				var $bestOfValueInput = this.sourceEl.closest('form').find('input[name=bestofvalue]');
+				if ($bestOfCheckbox && $bestOfValueInput) {
 					var $parentTag = $bestOfCheckbox.parent().parent();
-					if (format.includes('vgc')) {
+					var bestOfDefault = BattleFormats[format].bestOfDefault;
+					if (bestOfDefault) {
 						$parentTag.removeClass('hidden');
+						$bestOfValueInput.val(3);
 					} else {
 						$parentTag.addClass('hidden');
 						$bestOfCheckbox.prop('checked', false);
diff --git a/js/client.js b/js/client.js
index 5830583bd0..26147c0471 100644
--- a/js/client.js
+++ b/js/client.js
@@ -1328,6 +1328,7 @@ function toId() {
 					var challengeShow = true;
 					var tournamentShow = true;
 					var partner = false;
+					var bestOfDefault = false;
 					var team = null;
 					var teambuilderLevel = null;
 					var lastCommaIndex = name.lastIndexOf(',');
@@ -1340,6 +1341,7 @@ function toId() {
 						if (!(code & 8)) tournamentShow = false;
 						if (code & 16) teambuilderLevel = 50;
 						if (code & 32) partner = true;
+						if (code & 64) bestOfDefault = true;
 					} else {
 						// Backwards compatibility: late 0.9.0 -> 0.10.0
 						if (name.substr(name.length - 2) === ',#') { // preset teams
@@ -1403,6 +1405,7 @@ function toId() {
 						searchShow: searchShow,
 						challengeShow: challengeShow,
 						tournamentShow: tournamentShow,
+						bestOfDefault: bestOfDefault,
 						rated: searchShow && id.substr(4, 7) !== 'unrated',
 						teambuilderLevel: teambuilderLevel,
 						partner: partner,