TableturfBattleApp/TableturfBattleClient/index.html
2023-06-23 10:04:24 +10:00

536 lines
23 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<base href="https://tableturf.andriocelos.net/tableturf/"/>
<script>
baseUrl = window.location.toString().replace(/\/(?:index.html|deckeditor|game\/[^/]*|replay\/[^/]*)$/, '/');
document.getElementsByTagName('base')[0].href = baseUrl;
</script>
<title>Tableturf Battle</title>
<link rel="apple-touch-icon" sizes="180x180" href="assets/external/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="assets/external/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="assets/external/favicon-16x16.png">
<link rel="manifest" href="assets/site.webmanifest">
<link rel="stylesheet" href="tableturf.css"/>
<script src="config/config.js"></script>
<script src="qrcodejs/qrcode.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:type" content="website"/>
<meta name="title" property="og:title" content="Tableturf Battle"/>
<meta name="description" property="og:description" content="(Beta) An unofficial simulator for Tableturf Battle from Splatoon 3. Play online with friends using any in-game cards!"/>
<meta property="og:url" content="https://tableturf.andriocelos.net/"/>
<meta name="theme-color" content="#0c92f2" data-react-helmet="true"/>
</head>
<body>
<div id="noJSPage">This application requires JavaScript.</div>
<div id="preGamePage" hidden>
<p><img title="Tableturf Battle" alt="Tableturf Battle logo" id="logo" src="assets/external/logo.png"></p>
<h1>Tableturf Battle</h1>
<form id="preGameForm">
<p><label for="nameBox">Choose a nickname: <input type="text" id="nameBox" required minlength="1" maxlength="20"/></label></p>
<div id="preGameDefaultSection">
<button type="submit" id="preGameImplicitSubmitButton" tabindex="-1"></button>
<p>
<button type="submit" id="newGameButton">Create a room</button>
<button type="button" id="newGameSetupButton">More options</button>
</p>
<p>
<label for="gameIDBox">Enter a game link or ID to join a game:<br/>
<input type="text" id="gameIDBox" placeholder="Game link or ID"/></label>
<button type="submit" id="joinGameButton">Join game</button>
<button type="submit" id="spectateGameButton">Spectate</button>
</p>
</div>
<div id="preGameJoinSection" hidden>
<p>
<button type="submit" id="joinGameButton2">Join game</button>
<button type="submit" id="spectateGameButton2">Spectate</button>
</p>
<a id="preGameBackButton" href="../..">Create or join a different room</a>
</div>
<p>
<a id="preGameDeckEditorButton" href="deckeditor">Edit decks</a> |
<a id="preGameReplayButton" href="replay">Replay</a> |
<a id="preGameHelpButton" href="help">Help</a>
</p>
<div id="preGameLoadingSection" class="loadingContainer" hidden>
<div class="lds-ripple"><div></div><div></div></div> <span id="preGameLoadingLabel"></span>
</div>
</form>
<footer>
<p>This website is not affiliated with Nintendo. All product names, logos, and brands are property of their respective owners.</p>
<p><a href="https://github.com/AndrioCelos/TableturfBattleApp">GitHub</a><span id="discordSection"> | <a id="discordLink">Discord</a></span></p>
</footer>
</div>
<div id="lobbyPage" hidden>
<section id="lobbyPlayerListSection">
<p>Other players can join using a link to this page.<br/>
<button type="button" id="shareLinkButton">Share link</button><button type="button" id="showQrCodeButton">Show QR code</button></p>
<ul id="playerList"></ul>
<label for="lobbyTimeLimitBox">Turn time limit: <input type="text" id="lobbyTimeLimitBox" placeholder="None" readonly/><span id="lobbyTimeLimitUnit"> seconds</span></label>
<div id="lobbySelectedStageSection" hidden>
<h3>Stage</h3>
</div>
</section>
<section id="lobbyStageSection" hidden>
<h3>Vote for the stage.</h3>
<form id="stageSelectionForm">
<div class="submitButtonContainer">
<button type="submit" id="submitStageButton">Submit</button>
<div class="loadingContainer">
<div class="lds-ripple"><div></div><div></div></div>
</div>
</div>
<div id="stageList">
<label id="stageRandomLabel" for="stageRandomButton" class="stageRandom checked">
<input type="radio" id="stageRandomButton" name="stage" value="random" checked/> Random
</label>
</div>
<div id="stageListLoadingSection"><div class="lds-ripple"><div></div><div></div></div> Loading stages...</div>
</form>
</section>
<div id="lobbyDeckSection" hidden>
<h3>Choose your deck.</h3>
<form id="deckSelectionForm">
<div class="submitButtonContainer">
<button type="submit" id="submitDeckButton" disabled>Submit</button>
<div class="loadingContainer">
<div class="lds-ripple"><div></div><div></div></div>
</div>
</div>
<div id="lobbyDeckList" class="deckList"></div>
</form>
</div>
<dialog id="qrCodeDialog">
<form method="dialog">
<p>Scan this QR code to join the game.</p>
<div id="qrCode"></div>
<button type="submit">Close</button>
</form>
</dialog>
</div>
<div id="gamePage" hidden>
<div class="playerBar" data-index="1">
<div class="result"></div>
<div class="name">Player 2</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div class="playerBar" data-index="3">
<div class="result"></div>
<div class="name">Player 4</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div id="gameControls">
<div id="debugColour" style="display: none">
<table>
<tr>
<th>Colour</th>
<th>H</th>
<th>S</th>
<th>L</th>
<th>RGB</th>
</tr>
<tr>
<td>1i</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="0" id="colH0I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="0" data-index="0" id="colS0I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="0" id="colL0I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="0" data-index="0" id="colRGB0I" value="#ecf901"/></td>
</tr>
<tr>
<td>1s</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="1" id="colH0S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="0" data-index="1" id="colS0S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="1" id="colL0S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="0" data-index="1" id="colRGB0S" value="#fa9e00"/></td>
</tr>
<tr>
<td>1a</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="2" id="colH0A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="0" data-index="2" id="colS0A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="2" id="colL0A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="0" data-index="2" id="colRGB0A" value="#f9f91f"/></td>
</tr>
<tr>
<td>2i</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="0" id="colH1I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="1" data-index="0" id="colS1I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="0" id="colL1I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="1" data-index="0" id="colRGB1I" value="#4a5cfc"/></td>
</tr>
<tr>
<td>2s</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="1" id="colH1S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="1" data-index="1" id="colS1S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="1" id="colL1S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="1" data-index="1" id="colRGB1S" value="#01edfe"/></td>
</tr>
<tr>
<td>2a</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="2" id="colH1A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="1" data-index="2" id="colS1A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="2" id="colL1A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="1" data-index="2" id="colRGB1A" value="#d5e1e1"/></td>
</tr>
<tr>
<td>3i</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="0" id="colH2I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="2" data-index="0" id="colS2I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="0" id="colL2I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="2" data-index="0" id="colRGB2I" value="#f906e0"/></td>
</tr>
<tr>
<td>3s</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="1" id="colH2S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="2" data-index="1" id="colS2S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="1" id="colL2S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="2" data-index="1" id="colRGB2S" value="#8006f9"/></td>
</tr>
<tr>
<td>3a</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="2" id="colH2A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="2" data-index="2" id="colS2A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="2" id="colL2A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="2" data-index="2" id="colRGB2A" value="#ebb4fd"/></td>
</tr>
<tr>
<td>4i</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="0" id="colH3I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="3" data-index="0" id="colS3I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="0" id="colL3I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="3" data-index="0" id="colRGB3I" value="#06f994"/></td>
</tr>
<tr>
<td>4s</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="1" id="colH3S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="3" data-index="1" id="colS3S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="1" id="colL3S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="3" data-index="1" id="colRGB3S" value="#06f906"/></td>
</tr>
<tr>
<td>4a</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="2" id="colH3A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="3" data-index="2" id="colS3A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="2" id="colL3A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="3" data-index="2" id="colRGB3A" value="#b4fdc7"/></td>
</tr>
</table>
</div>
<div id="passHint" hidden>Select a card to discard.</div>
<div id="handContainer"></div>
<div id="playRow">
<label for="passButton">
<input type="checkbox" id="passButton"/> Pass
</label>
<label for="specialButton">
<input type="checkbox" id="specialButton"/> Special Attack
</label>
</div>
<div id="spectatorRow">
<a id="leaveButton" href="#">Exit</a>
<button id="replayPreviousButton">Previous turn</button>
<button id="replayNextButton">Next turn</button>
<button id="shareReplayLinkButton">Copy replay link</button>
<button id="flipButton">Change view</button>
</div>
</div>
<div class="playerBar" data-index="2">
<div class="result"></div>
<div class="name">Player 3</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div class="playerBar" data-index="0">
<div class="result"></div>
<div class="name">Player 1</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div id="showDeckContainer" hidden>
<div id="showDeck">
<ul id="showDeckList"></ul>
<div>
<button type="button" id="showDeckCloseButton">Close</button>
</div>
</div>
</div>
<div id="testControls">
<div id="testControlsHeader" class="testControls">
<label for="testDeckButton">
<input type="radio" id="testDeckButton" name="testPage"/>Deck
</label>
<label for="testAllCardsButton">
<input type="radio" id="testAllCardsButton" name="testPage"/>All cards
</label>
</div>
<div id="testDeckContainer" class="testControls">
<button id="testAllCardsMobileButton">All cards</button>
<div id="testDeckList"></div>
</div>
<div id="testAllCardsContainer" class="testControls" hidden>
<div id="testAllCardsHeader">
<label for="testAllCardsListSortBox">
Sort by
<select id="testAllCardsListSortBox" autocomplete="off"></select>
</label>
<input type="text" id="testAllCardsListFilterBox" placeholder="Filter"/>
</div>
<div id="testAllCardsList" class="cardListGrid"></div>
</div>
<div id="testControlsFooter" class="testControls">
<button type="button" id="testUndoButton" disabled>Undo</button>
<button type="button" id="testBackButton">End test</button>
</div>
</div>
<div id="testCardListBackdrop" hidden></div>
<div id="timeSection">
<div id="turnNumberContainer" hidden>
<p>Turns left</p>
<div id="turnNumberLabel">12</div>
</div>
<div id="timeContainer">
<div id="timeContainerContent">
<svg viewBox="0 0 100 100">
<path fill-rule="evenodd" d="M 50,0 a 50 50 360 1 1 0,100 a 50 50 360 1 1 0,-100 z M 40,10 h 20 v 30 h 30 v 20 h -50 z"/>
</svg>
<div id="timeLabel">69</div>
</div>
</div>
</div>
<div id="scoreSection">
<div class="pointsContainer" data-index="1"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
<div class="pointsContainer" data-index="3"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
<div class="pointsContainer" data-index="2"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
<div class="pointsContainer" data-index="0"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
</div>
<div id="boardSection">
<table id="gameBoard" tabindex="0"></table>
<div id="redrawModal" hidden>
<div id="redrawBox">
<p>Redraw your starting hand?</p>
<p><button type="button" id="redrawNoButton" data-redraw="false">Hold steady</button></p>
<p><button type="button" id="redrawYesButton" data-redraw="true">Redraw</button></p>
</div>
</div>
</div>
<div id="gameButtonsContainer">
<button id="rotateLeftButton" title="Rotate card anticlockwise (Shift+R)">&cularr;</button>
<button id="rotateRightButton" title="Rotate card clockwise (R)">&curarr;</button>
<button id="gameDeckButton" title="Show deck (D)">&#x1F0A0;</button>
</div>
<div class="playContainer" data-index="1"></div>
<div class="playContainer" data-index="3"></div>
<div class="playContainer" data-index="2"></div>
<div class="playContainer" data-index="0"></div>
<div id="playHint" hidden></div>
<div id="testPlacementList"></div>
</div>
<div id="deckListPage" hidden>
<section id="deckEditordeckListPage">
<a id="deckListBackButton" href=".">Back</a>
<h3>Deck list</h3>
<div id="deckList" class="deckList">
<div id="addDeckControls">
<button id="newDeckButton">New deck</button>
<button id="importDeckButton">Import deck</button>
</div>
</div>
</section>
<section id="deckEditorDeckViewSection" hidden>
<a id="deckViewBackButton" href="#">Back</a>
<h3 id="deckName">Deck</h3>
<div>
<button type="button" id="deckEditButton">Edit</button>
<button type="button" id="deckListTestButton">Test</button>
<button type="button" id="deckExportButton">Export</button>
<button type="button" id="deckRenameButton">Rename</button>
<button type="button" id="deckCopyButton">Copy</button>
<button type="button" id="deckDeleteButton" class="danger">Delete</button>
</div>
<div class="deckSizeContainer">Total: <div id="deckViewSize">0</div></div>
<div id="deckCardListView">
</div>
</section>
<dialog id="deckImportDialog">
<form id="deckImportForm" method="dialog">
<textarea id="deckImportTextBox" rows="24" cols="45"></textarea>
<div id="deckImportErrorBox" class="error" hidden></div>
<div>
<button type="submit" id="deckImportOkButton">OK</button>
<button type="submit" id="deckImportCancelButton">Cancel</button>
</div>
</form>
</dialog>
<dialog id="deckExportDialog">
<form method="dialog">
<textarea id="deckExportTextBox" readonly rows="24" cols="45"></textarea>
<div>
<button type="button" id="deckExportCopyButton">Copy</button>
<button type="submit">Close</button>
</div>
</form>
</dialog>
</div>
<div id="deckEditPage" hidden>
<section id="deckEditordeckEditPage">
<h3 id="deckName2">Deck</h3>
<div>
<button type="button" id="deckTestButton">Test</button>
<button type="button" id="deckSaveButton">Save</button>
<button type="button" id="deckCancelButton">Cancel</button>
</div>
<div class="deckSizeContainer">Total: <div id="deckEditSize">0</div></div>
<div id="deckCardListEdit">
</div>
</section>
<section id="deckEditorCardListSection">
<div id="cardListHeader">
<a id="deckCardListBackButton" href="#">Back</a>
<h3>All cards</h3>
<label for="cardListSortBox">
Sort by
<select id="cardListSortBox" autocomplete="off"></select>
</label>
<input type="text" id="cardListFilterBox" placeholder="Filter"/>
</div>
<div id="cardList" class="cardListGrid"></div>
</section>
<div id="deckEditorCardListBackdrop"></div>
</div>
<dialog id="testStageSelectionDialog">
<h3>Select a stage.</h3>
<form id="testStageSelectionForm" method="dialog">
<div id="testStageSelectionList"></div>
<button type="submit">Cancel</button>
</form>
</dialog>
<dialog id="gameSetupDialog">
<form id="gameSetupForm" method="dialog">
<div id="preGameDefaultSection">
<p>
<label for="maxPlayersBox">
Player limit:
<select id="maxPlayersBox">
<option value="2">2 players</option>
<option value="3">3 players</option>
<option value="4">4 players</option>
</select>
</label>
</p>
<p>
<label for="turnTimeLimitBox">
Turn time limit:
<input type="number" id="turnTimeLimitBox" min="10" max="120" step="10" placeholder="None"/>
<span id="turnTimeLimitUnit">seconds</span>
</label>
</p>
<p>
<button type="submit" id="gameSetupSubmitButton">Create room</button>
<button type="submit">Back</button>
</p>
</div>
</form>
</dialog>
<dialog id="errorDialog">
<div id="errorMessage"></div>
<form id="errorDialogForm" method="dialog">
<button type="submit">OK</button>
</form>
</dialog>
<dialog id="helpDialog">
<h2>Controls</h2>
<section id="helpControls">
<article>
<h3>Keyboard</h3>
<table>
<tr><th>Move card:</th><td>Arrow keys</td></tr>
<tr><th>Rotate clockwise:</th><td>R</td></tr>
<tr><th>Rotate anticlockwise:</th><td>Shift+R</td></tr>
<tr><th>Confirm:</th><td>Enter</td></tr>
<tr><th>Deselect card:</th><td>Backspace</td></tr>
<tr><th>Pass:</th><td>P</td></tr>
<tr><th>Special attack:</th><td>S</td></tr>
<tr><th>Show deck:</th><td>D</td></tr>
</table>
</article>
<article>
<h3>Mouse</h3>
<table>
<tr><th>Move card:</th><td>Pointer</td></tr>
<tr><th>Rotate clockwise:</th><td>Right click or wheel down</td></tr>
<tr><th>Rotate anticlockwise:</th><td>Wheel up</td></tr>
<tr><th>Confirm:</th><td>Left click</td></tr>
</table>
</article>
<article>
<h3>Touch</h3>
<table>
<tr><th>Move card:</th><td>Drag anywhere on the board</td></tr>
<tr><th>Rotate clockwise:</th><td>Tap &curarr;</td></tr>
<tr><th>Rotate anticlockwise:</th><td>Tap &cularr;</td></tr>
<tr><th>Confirm:</th><td>Tap anywhere on the board</td></tr>
</table>
</article>
</section>
<footer>
<form method="dialog">
<button type="submit">OK</button>
</form>
</footer>
</dialog>
<script src="build/tsbuild.js"></script>
</body>
</html>