forked from MarseyWorld/MarseyWorld
fix casino js
parent
56b80d447d
commit
ed323817f5
|
@ -0,0 +1,224 @@
|
||||||
|
function makeBlackjackRequest(action) {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("post", `/casino/twentyone/${action}`);
|
||||||
|
xhr.setRequestHeader('xhr', 'xhr');
|
||||||
|
xhr.onload = handleBlackjackResponse.bind(null, xhr);
|
||||||
|
xhr.blackjackAction = action;
|
||||||
|
return xhr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBlackjackResponse(xhr) {
|
||||||
|
let status;
|
||||||
|
try {
|
||||||
|
const response = JSON.parse(xhr.response);
|
||||||
|
const succeeded = xhr.status >= 200 &&
|
||||||
|
xhr.status < 300 &&
|
||||||
|
response &&
|
||||||
|
!response.error;
|
||||||
|
|
||||||
|
clearResult();
|
||||||
|
status = xhr.status;
|
||||||
|
|
||||||
|
if (status == 429) {
|
||||||
|
throw new Error(response["details"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (succeeded) {
|
||||||
|
updateBlackjackTable(response.state);
|
||||||
|
updateFeed(response.feed);
|
||||||
|
updatePlayerCurrencies(response.gambler);
|
||||||
|
} else {
|
||||||
|
console.error("Error: ", response.error);
|
||||||
|
throw new Error("Error")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const results = {
|
||||||
|
deal: "Unable to deal a new hand. Is one in progress?",
|
||||||
|
hit: "Unable to hit.",
|
||||||
|
stay: "Unable to stay.",
|
||||||
|
"double-down": "Unable to double down.",
|
||||||
|
"buy-insurance": "Unable to buy insurance."
|
||||||
|
};
|
||||||
|
result = results[xhr.blackjackAction];
|
||||||
|
|
||||||
|
if (status == 429) {
|
||||||
|
result = error.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateResult(result, "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBlackjackActions(state) {
|
||||||
|
const actions = Array.from(document.querySelectorAll('.twentyone-btn'));
|
||||||
|
|
||||||
|
// Hide all actions.
|
||||||
|
actions.forEach(action => action.style.display = 'none');
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
// Show the correct ones.
|
||||||
|
state.actions.forEach(action => document.getElementById(`twentyone-${action}`).style.display = 'inline-block');
|
||||||
|
} else {
|
||||||
|
const dealButton = document.getElementById(`twentyone-DEAL`);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const dealButton = document.getElementById(`twentyone-DEAL`);
|
||||||
|
})
|
||||||
|
|
||||||
|
if (dealButton) {
|
||||||
|
dealButton.style.display = 'inline-block'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBlackjackTable(state) {
|
||||||
|
const table = document.getElementById('blackjack-table');
|
||||||
|
const charactersToRanks = {
|
||||||
|
X: "10"
|
||||||
|
};
|
||||||
|
const charactersToSuits = {
|
||||||
|
S: "♠️",
|
||||||
|
H: "♥️",
|
||||||
|
C: "♣️",
|
||||||
|
D: "♦️",
|
||||||
|
};
|
||||||
|
const makeCardset = (from, who, value) => `
|
||||||
|
<div class="blackjack-cardset">
|
||||||
|
<div class="blackjack-cardset-value">
|
||||||
|
${value === -1 ? `${who} went bust` : `${who} has ${value}`}
|
||||||
|
</div>
|
||||||
|
${from
|
||||||
|
.filter(card => card !== "?")
|
||||||
|
.map(([rankCharacter, suitCharacter]) => {
|
||||||
|
const rank = charactersToRanks[rankCharacter] || rankCharacter;
|
||||||
|
const suit = charactersToSuits[suitCharacter] || suitCharacter;
|
||||||
|
return buildPlayingCard(rank, suit);
|
||||||
|
})
|
||||||
|
.join('')}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
const dealerCards = makeCardset(state.dealer, 'Dealer', state.dealer_value);
|
||||||
|
const playerCards = makeCardset(state.player, 'Player', state.player_value);
|
||||||
|
|
||||||
|
updateBlackjackActions(state);
|
||||||
|
|
||||||
|
table.innerHTML = `
|
||||||
|
<div style="position: relative;">
|
||||||
|
${dealerCards}
|
||||||
|
</div>
|
||||||
|
${playerCards}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const currency = state.wager.currency === 'coins' ? 'coins' : 'marseybux';
|
||||||
|
|
||||||
|
switch (state.status) {
|
||||||
|
case 'BLACKJACK':
|
||||||
|
updateResult(`Blackjack: Received ${state.payout} ${currency}`, "warning");
|
||||||
|
break;
|
||||||
|
case 'WON':
|
||||||
|
updateResult(`Won: Received ${state.payout} ${currency}`, "success");
|
||||||
|
break;
|
||||||
|
case 'PUSHED':
|
||||||
|
updateResult(`Pushed: Received ${state.wager.amount} ${currency}`, "success");
|
||||||
|
break;
|
||||||
|
case 'LOST':
|
||||||
|
updateResult(`Lost ${state.wager.amount} ${currency}`, "danger");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCardsetBackgrounds(state);
|
||||||
|
|
||||||
|
if (state.status === 'PLAYING') {
|
||||||
|
updateResult(`${state.wager.amount} ${currency} are at stake`, "success");
|
||||||
|
} else {
|
||||||
|
enableWager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCardsetBackgrounds(state) {
|
||||||
|
const cardsets = Array.from(document.querySelectorAll('.blackjack-cardset'));
|
||||||
|
|
||||||
|
for (const cardset of cardsets) {
|
||||||
|
['PLAYING', 'LOST', 'PUSHED', 'WON', 'BLACKJACK'].forEach(status => cardset.classList.remove(`blackjack-cardset__${status}`));
|
||||||
|
cardset.classList.add(`blackjack-cardset__${state.status}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deal() {
|
||||||
|
const request = makeBlackjackRequest('deal');
|
||||||
|
const { amount, currency } = getWager();
|
||||||
|
const form = new FormData();
|
||||||
|
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
form.append("wager", amount);
|
||||||
|
form.append("currency", currency);
|
||||||
|
|
||||||
|
request.send(form);
|
||||||
|
|
||||||
|
clearResult();
|
||||||
|
disableWager();
|
||||||
|
drawFromDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hit() {
|
||||||
|
const request = makeBlackjackRequest('hit');
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
request.send(form);
|
||||||
|
|
||||||
|
drawFromDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stay() {
|
||||||
|
const request = makeBlackjackRequest('stay');
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
request.send(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doubleDown() {
|
||||||
|
const request = makeBlackjackRequest('double-down');
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
request.send(form);
|
||||||
|
|
||||||
|
drawFromDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
function buyInsurance() {
|
||||||
|
const request = makeBlackjackRequest('buy-insurance');
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
request.send(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBlackjackDeck() {
|
||||||
|
document.getElementById('blackjack-table-deck').innerHTML = `
|
||||||
|
<div style="position: absolute; top: 150px; left: -100px;">
|
||||||
|
${buildPlayingCardDeck()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeBlackjack() {
|
||||||
|
buildBlackjackDeck();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const passed = document.getElementById('blackjack-table').dataset.state;
|
||||||
|
const state = JSON.parse(passed);
|
||||||
|
updateBlackjackTable(state);
|
||||||
|
} catch (error) {
|
||||||
|
updateBlackjackActions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
document.readyState === "complete" ||
|
||||||
|
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
||||||
|
) {
|
||||||
|
initializeBlackjack();
|
||||||
|
} else {
|
||||||
|
document.addEventListener("load", initializeBlackjack);
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
/**
|
||||||
|
* This script block contains generic helper function usable across casino games:
|
||||||
|
* - Wagers
|
||||||
|
* - Feed
|
||||||
|
* - Leaderboard
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
document.readyState === "complete" ||
|
||||||
|
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
||||||
|
) {
|
||||||
|
initializeGame();
|
||||||
|
} else {
|
||||||
|
document.addEventListener("load", initializeGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeGame() {
|
||||||
|
updateFeed();
|
||||||
|
updateLeaderboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlayerCurrencies(updated) {
|
||||||
|
if (updated.coins) {
|
||||||
|
document.getElementById("user-coins-amount").innerText = updated.coins;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated.marseybux) {
|
||||||
|
document.getElementById("user-bux-amount").innerText = updated.marseybux;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWager() {
|
||||||
|
const amount = document.getElementById("wagerAmount").value;
|
||||||
|
const currency = document.querySelector(
|
||||||
|
'input[name="wagerCurrency"]:checked'
|
||||||
|
).value;
|
||||||
|
const genericCurrency = currency == 'marseybux' ? 'marseybux' : 'coins';
|
||||||
|
|
||||||
|
return { amount, currency: genericCurrency, localCurrency: currency };
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableWager() {
|
||||||
|
document.getElementById("wagerAmount").disabled = true;
|
||||||
|
document.getElementById("wagerCoins").disabled = true;
|
||||||
|
document.getElementById("wagerMarseybux").disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableWager() {
|
||||||
|
document.getElementById("wagerAmount").disabled = false;
|
||||||
|
document.getElementById("wagerCoins").disabled = false;
|
||||||
|
document.getElementById("wagerMarseybux").disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateResult(text, className) {
|
||||||
|
clearResult();
|
||||||
|
const result = document.getElementById("casinoGameResult");
|
||||||
|
result.style.visibility = "visible";
|
||||||
|
result.innerText = text;
|
||||||
|
result.classList.add(`alert-${className}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearResult() {
|
||||||
|
const result = document.getElementById("casinoGameResult");
|
||||||
|
result.style.visibility = "hidden";
|
||||||
|
result.innerText = "N/A";
|
||||||
|
result.classList.remove("alert-success", "alert-danger", "alert-warning");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFeed(newFeed) {
|
||||||
|
let feed;
|
||||||
|
|
||||||
|
if (newFeed) {
|
||||||
|
feed = newFeed;
|
||||||
|
} else {
|
||||||
|
const gameFeed = document.getElementById("casinoGameFeed");
|
||||||
|
feed = gameFeed.dataset.feed;
|
||||||
|
feed = JSON.parse(feed);
|
||||||
|
gameFeed.dataset.feed = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const feedHtml = feed
|
||||||
|
.map(
|
||||||
|
(entry) =>
|
||||||
|
`
|
||||||
|
<li
|
||||||
|
style="display: flex; align-items: center; justify-content: space-between;"
|
||||||
|
class="${entry.won_or_lost === "won" ? "text-success" : "text-danger"}">
|
||||||
|
<div>
|
||||||
|
<a href="/@${entry.user}">@${entry.user}</a> ${entry.won_or_lost} ${entry.amount
|
||||||
|
} ${entry.currency}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
document.getElementById("casinoGameFeedList").innerHTML = feedHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadFeed() {
|
||||||
|
const game = document.getElementById('casino-game-wrapper').dataset.game;
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("get", `/casino/${game}/feed`);
|
||||||
|
xhr.setRequestHeader('xhr', 'xhr');
|
||||||
|
xhr.onload = handleFeedResponse.bind(null, xhr);
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFeedResponse(xhr) {
|
||||||
|
let response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = JSON.parse(xhr.response);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const succeeded =
|
||||||
|
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
||||||
|
|
||||||
|
if (succeeded) {
|
||||||
|
document.getElementById("casinoGameFeed").dataset.feed = JSON.stringify(response.feed);
|
||||||
|
updateFeed();
|
||||||
|
} else {
|
||||||
|
console.error("error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLeaderboard() {
|
||||||
|
const leaderboardContainer = document.getElementById("gameLeaderboard");
|
||||||
|
const leaderboardData = JSON.parse(leaderboardContainer.dataset.leaderboard);
|
||||||
|
const [biggestWinnerAllTime, biggestWinner24h, biggestLoser24h, biggestLoserAllTime] = [
|
||||||
|
'biggestWinnerAllTime', 'biggestWinner24h', 'biggestLoser24h', 'biggestLoserAllTime'
|
||||||
|
].map(id => document.getElementById(id));
|
||||||
|
const formatLocalCurrencyName = currency => ({ coins: 'coins', marseybux: 'marseybux' })[currency];
|
||||||
|
|
||||||
|
biggestWinnerAllTime.innerHTML = `
|
||||||
|
<a href="/@${leaderboardData.all_time.biggest_win.user}">${leaderboardData.all_time.biggest_win.user}</a> <br><small>${leaderboardData.all_time.biggest_win.amount} ${formatLocalCurrencyName(leaderboardData.all_time.biggest_win.currency)}</small>
|
||||||
|
`;
|
||||||
|
|
||||||
|
biggestWinner24h.innerHTML = `
|
||||||
|
<a href="/@${leaderboardData.last_24h.biggest_win.user}">${leaderboardData.last_24h.biggest_win.user}</a> <br> <small>${leaderboardData.last_24h.biggest_win.amount} ${formatLocalCurrencyName(leaderboardData.last_24h.biggest_win.currency)}</small>
|
||||||
|
`;
|
||||||
|
|
||||||
|
biggestLoser24h.innerHTML = `
|
||||||
|
<a href="/@${leaderboardData.last_24h.biggest_loss.user}">${leaderboardData.last_24h.biggest_loss.user}</a> <br> <small>${leaderboardData.last_24h.biggest_loss.amount} ${formatLocalCurrencyName(leaderboardData.last_24h.biggest_loss.currency)}</small>
|
||||||
|
`;
|
||||||
|
|
||||||
|
biggestLoserAllTime.innerHTML = `
|
||||||
|
<a href="/@${leaderboardData.all_time.biggest_loss.user}">${leaderboardData.all_time.biggest_loss.user}</a> <br> <small>${leaderboardData.all_time.biggest_loss.amount} ${formatLocalCurrencyName(leaderboardData.all_time.biggest_loss.currency)}</small>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomInt(min, max) {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomCardAngle() {
|
||||||
|
const skew = 10
|
||||||
|
return getRandomInt(-skew, skew);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPlayingCard(rank, suit) {
|
||||||
|
return `
|
||||||
|
<div
|
||||||
|
style="transform: scale(0.7) rotateZ(${getRandomCardAngle()}deg)"
|
||||||
|
class="playing-card playing-card_${["♥️", "♦️"].includes(suit) ? 'red' : 'black'}">
|
||||||
|
<div class="playing-card_small playing-card_topright">${rank}${suit}</div>
|
||||||
|
<div class="playing-card_large">${rank}${suit}</div>
|
||||||
|
<div class="playing-card_small playing-card_bottomleft">${rank}${suit}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPlayingCardDeck(size = 14) {
|
||||||
|
const cards = Array.from({ length: size }, (_, index) => `
|
||||||
|
<div
|
||||||
|
style="bottom: ${index}px; left: ${-index}px"
|
||||||
|
class="flipped-playing-card"></div>
|
||||||
|
`).join('\n');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div id="playingCardDeck" class="playing-card-deck">
|
||||||
|
${cards}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawFromDeck() {
|
||||||
|
try {
|
||||||
|
const [topCard] = Array.from(document.querySelectorAll("#playingCardDeck > *")).reverse();
|
||||||
|
|
||||||
|
topCard.classList.add('drawing-a-card');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
topCard.classList.remove('drawing-a-card');
|
||||||
|
}, 600);
|
||||||
|
} catch { }
|
||||||
|
}
|
|
@ -0,0 +1,387 @@
|
||||||
|
// Kiss my ass if you're judgin'
|
||||||
|
const CELL_TO_NUMBER_LOOKUP = {
|
||||||
|
1: 3,
|
||||||
|
2: 6,
|
||||||
|
3: 9,
|
||||||
|
4: 12,
|
||||||
|
5: 15,
|
||||||
|
6: 18,
|
||||||
|
7: 21,
|
||||||
|
8: 24,
|
||||||
|
9: 27,
|
||||||
|
10: 30,
|
||||||
|
11: 33,
|
||||||
|
12: 36,
|
||||||
|
13: 2,
|
||||||
|
14: 5,
|
||||||
|
15: 8,
|
||||||
|
16: 11,
|
||||||
|
17: 14,
|
||||||
|
18: 17,
|
||||||
|
19: 20,
|
||||||
|
20: 23,
|
||||||
|
21: 26,
|
||||||
|
22: 29,
|
||||||
|
23: 32,
|
||||||
|
24: 35,
|
||||||
|
25: 1,
|
||||||
|
26: 4,
|
||||||
|
27: 7,
|
||||||
|
28: 10,
|
||||||
|
29: 13,
|
||||||
|
30: 16,
|
||||||
|
31: 19,
|
||||||
|
32: 22,
|
||||||
|
33: 25,
|
||||||
|
34: 28,
|
||||||
|
35: 31,
|
||||||
|
36: 34
|
||||||
|
};
|
||||||
|
|
||||||
|
function initializeGame() {
|
||||||
|
buildRouletteTable();
|
||||||
|
updateResult("Rolls occur every five minutes", "success");
|
||||||
|
requestRouletteBets();
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRouletteTable() {
|
||||||
|
const table = document.getElementById('roulette-table');
|
||||||
|
const reds = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
|
||||||
|
|
||||||
|
let html = "";
|
||||||
|
|
||||||
|
// Lines
|
||||||
|
html += `
|
||||||
|
<div class="roulette-table-row">
|
||||||
|
<div style="flex: 1"></div>
|
||||||
|
<div id="LINE_BET#1" onclick="placeChip('LINE_BET', '1')" class="roulette-table-1to1">Line 1</div>
|
||||||
|
<div id="LINE_BET#2" onclick="placeChip('LINE_BET', '2')" class="roulette-table-1to1">Line 2</div>
|
||||||
|
<div id="LINE_BET#3" onclick="placeChip('LINE_BET', '3')" class="roulette-table-1to1">Line 3</div>
|
||||||
|
<div id="LINE_BET#4" onclick="placeChip('LINE_BET', '4')" class="roulette-table-1to1">Line 4</div>
|
||||||
|
<div id="LINE_BET#5" onclick="placeChip('LINE_BET', '5')" class="roulette-table-1to1">Line 5</div>
|
||||||
|
<div id="LINE_BET#6" onclick="placeChip('LINE_BET', '6')" class="roulette-table-1to1">Line 6</div>
|
||||||
|
<div style="flex: 1"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// First Column
|
||||||
|
html += "<div class=\"roulette-table-row\">";
|
||||||
|
html += `<div id="STRAIGHT_UP_BET#37" onclick="placeChip('STRAIGHT_UP_BET', '37')" class="roulette-table-number roulette-table-number__green">00</div>`
|
||||||
|
for (let i = 1; i < 13; i++) {
|
||||||
|
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
||||||
|
const isRed = reds.includes(correctNumber);
|
||||||
|
|
||||||
|
html += `<div
|
||||||
|
id="STRAIGHT_UP_BET#${correctNumber}"
|
||||||
|
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
||||||
|
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
||||||
|
${correctNumber}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
html += `<div id="COLUMN_BET#3" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '3')">Col 3</div>`;
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Second Column
|
||||||
|
html += "<div class=\"roulette-table-row\">";
|
||||||
|
html += `<div id="roulette-spacer-left-middle" class="roulette-table-number roulette-table-number__green"></div>`
|
||||||
|
for (let i = 13; i < 25; i++) {
|
||||||
|
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
||||||
|
const isRed = reds.includes(correctNumber);
|
||||||
|
|
||||||
|
html += `<div
|
||||||
|
id="STRAIGHT_UP_BET#${correctNumber}"
|
||||||
|
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
||||||
|
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
||||||
|
${correctNumber}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
html += `<div id="COLUMN_BET#2" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '2')">Col 2</div>`;
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Third Column
|
||||||
|
html += "<div class=\"roulette-table-row\">";
|
||||||
|
html += `<div id="STRAIGHT_UP_BET#0" onclick="placeChip('STRAIGHT_UP_BET', '0')" class="roulette-table-number roulette-table-number__green">0</div>`
|
||||||
|
for (let i = 25; i < 37; i++) {
|
||||||
|
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
||||||
|
const isRed = reds.includes(correctNumber);
|
||||||
|
|
||||||
|
html += `<div
|
||||||
|
id="STRAIGHT_UP_BET#${correctNumber}"
|
||||||
|
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
||||||
|
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
||||||
|
${correctNumber}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
html += `<div id="COLUMN_BET#1" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '1')">Col 1</div>`;
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Line Bets and 1:1 Bets
|
||||||
|
html += `
|
||||||
|
<div class="roulette-table-row">
|
||||||
|
<div style="flex: 1"></div>
|
||||||
|
<div id="DOZEN_BET#1" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '1')">1st12</div>
|
||||||
|
<div id="DOZEN_BET#2" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '2')">2nd12</div>
|
||||||
|
<div id="DOZEN_BET#3" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '3')">3rd12</div>
|
||||||
|
<div style="flex: 1"></div>
|
||||||
|
</div>
|
||||||
|
<div class="roulette-table-row">
|
||||||
|
<div style="flex: 1"></div>
|
||||||
|
<div id="HIGH_LOW_BET#LOW" class="roulette-table-1to1" onclick="placeChip('HIGH_LOW_BET', 'LOW')">1:18</div>
|
||||||
|
<div id="EVEN_ODD_BET#EVEN" class="roulette-table-1to1" onclick="placeChip('EVEN_ODD_BET', 'EVEN')">EVEN</div>
|
||||||
|
<div id="RED_BLACK_BET#RED" class="roulette-table-1to1" onclick="placeChip('RED_BLACK_BET', 'RED')" style="background-color: red">RED</div>
|
||||||
|
<div id="RED_BLACK_BET#BLACK" class="roulette-table-1to1" onclick="placeChip('RED_BLACK_BET', 'BLACK')" style="background-color: black">BLACK</div>
|
||||||
|
<div id="EVEN_ODD_BET#ODD" class="roulette-table-1to1" onclick="placeChip('EVEN_ODD_BET', 'ODD')">ODD</div>
|
||||||
|
<div id="HIGH_LOW_BET#HIGH" class="roulette-table-1to1" onclick="placeChip('HIGH_LOW_BET', 'HIGH')">19:36</div>
|
||||||
|
<div style="flex: 1"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
table.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatFlatBets(bets) {
|
||||||
|
let flatBets = [];
|
||||||
|
|
||||||
|
for (const betCollection of Object.values(bets)) {
|
||||||
|
flatBets = flatBets.concat(betCollection)
|
||||||
|
}
|
||||||
|
|
||||||
|
return flatBets;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNormalizedBets(bets) {
|
||||||
|
const normalizedBets = {
|
||||||
|
gamblers: [],
|
||||||
|
gamblersByName: {}
|
||||||
|
};
|
||||||
|
const flatBets = formatFlatBets(bets);
|
||||||
|
|
||||||
|
for (const bet of flatBets) {
|
||||||
|
if (!normalizedBets.gamblers.includes(bet.gambler_username)) {
|
||||||
|
normalizedBets.gamblers.push(bet.gambler_username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!normalizedBets.gamblersByName[bet.gambler_username]) {
|
||||||
|
normalizedBets.gamblersByName[bet.gambler_username] = {
|
||||||
|
name: bet.gambler_username,
|
||||||
|
avatar: bet.gambler_profile_url,
|
||||||
|
profile: `/@${bet.gambler_username}`,
|
||||||
|
wagerTotal: {
|
||||||
|
coins: 0,
|
||||||
|
marseybux: 0
|
||||||
|
},
|
||||||
|
wagers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = normalizedBets.gamblersByName[bet.gambler_username];
|
||||||
|
|
||||||
|
entry.wagerTotal[bet.wager.currency] += bet.wager.amount;
|
||||||
|
|
||||||
|
const existingWager = entry.wagers.find(wager => wager.bet === bet.bet && wager.which === bet.which);
|
||||||
|
|
||||||
|
if (existingWager) {
|
||||||
|
existingWager.amounts[bet.wager.currency] += bet.wager.amount;
|
||||||
|
} else {
|
||||||
|
const newEntry = {
|
||||||
|
bet: bet.bet,
|
||||||
|
which: bet.which,
|
||||||
|
amounts: {
|
||||||
|
coins: 0,
|
||||||
|
marseybux: 0
|
||||||
|
},
|
||||||
|
};
|
||||||
|
newEntry.amounts[bet.wager.currency] += bet.wager.amount;
|
||||||
|
|
||||||
|
entry.wagers.push(newEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedBets;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPokerChip(avatar) {
|
||||||
|
return `
|
||||||
|
<div class="roulette-poker-chip">
|
||||||
|
<img src="/i/pokerchip.webp" width="40" height="40">
|
||||||
|
<img src="${avatar}" width="40" height="40">
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRouletteBets(bets) {
|
||||||
|
const betArea = document.getElementById("roulette-bets");
|
||||||
|
const flatBets = formatFlatBets(bets);
|
||||||
|
const normalizedBets = formatNormalizedBets(bets);
|
||||||
|
const coinImgHtml = `
|
||||||
|
<img
|
||||||
|
src="/i/rDrama/coins.webp?v=3009"
|
||||||
|
alt="coin"
|
||||||
|
width="32"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="bottom"
|
||||||
|
title=""
|
||||||
|
aria-label="Coin"
|
||||||
|
data-bs-original-title="Coin">
|
||||||
|
`;
|
||||||
|
const marseybuxImgHtml = `
|
||||||
|
<img
|
||||||
|
src="/i/marseybux.webp?v=2000"
|
||||||
|
alt="marseybux"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="bottom"
|
||||||
|
title=""
|
||||||
|
aria-label="Marseybux"
|
||||||
|
width="32" class="mr-1 ml-1"
|
||||||
|
data-bs-original-title="Marseybux">
|
||||||
|
`;
|
||||||
|
const { participants, coin, marseybux } = flatBets.reduce((prev, next) => {
|
||||||
|
if (!prev.participants.includes(next.gambler_username)) {
|
||||||
|
prev.participants.push(next.gambler_username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next.wager.currency == 'coins') {
|
||||||
|
prev.coin += next.wager.amount;
|
||||||
|
} else {
|
||||||
|
prev.marseybux += next.wager.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
}, { participants: [], coin: 0, marseybux: 0 });
|
||||||
|
const coinText = `${coin} ${coinImgHtml}`;
|
||||||
|
const marseybuxText = `${marseybux} ${marseybuxImgHtml}`;
|
||||||
|
const playerText = participants.length > 1 ? `${participants.length} players are` : `1 player is`;
|
||||||
|
const totalText = coin && marseybux ? `${coinText} and ${marseybuxText}` : coin ? coinText : marseybuxText;
|
||||||
|
const fullTotalText = participants.length === 0 ? "No one has placed a bet" : `${playerText} betting a total of ${totalText}`;
|
||||||
|
|
||||||
|
let betHtml = `
|
||||||
|
<small class="roulette-total-bets">${fullTotalText}</small>
|
||||||
|
<hr>
|
||||||
|
`;
|
||||||
|
|
||||||
|
for (player of normalizedBets.gamblers) {
|
||||||
|
const { name, avatar, wagerTotal, wagers } = normalizedBets.gamblersByName[player];
|
||||||
|
|
||||||
|
betHtml += `<div class="roulette-bet-summary">`;
|
||||||
|
// Heading
|
||||||
|
betHtml += ` <div class="roulette-bet-summary--heading">`;
|
||||||
|
betHtml += buildPokerChip(avatar);
|
||||||
|
const coinText = wagerTotal.coins > 0 ? `${wagerTotal.coins} ${coinImgHtml}` : "";
|
||||||
|
const procoinText = wagerTotal.marseybux > 0 ? `${wagerTotal.marseybux} ${marseybuxImgHtml}` : "";
|
||||||
|
const bettingText = coinText && procoinText ? `${coinText} and ${procoinText}` : coinText || procoinText;
|
||||||
|
betHtml += `<p>${name} is betting ${bettingText}:</p>`;
|
||||||
|
betHtml += ` </div>`;
|
||||||
|
|
||||||
|
// Individual bets
|
||||||
|
betHtml += `<ul class="roulette-bet-summary--list">`;
|
||||||
|
for (const individualBet of wagers) {
|
||||||
|
const coinText = individualBet.amounts.coins > 0 ? `${individualBet.amounts.coins} ${coinImgHtml}` : "";
|
||||||
|
const procoinText = individualBet.amounts.marseybux > 0 ? `${individualBet.amounts.marseybux} ${marseybuxImgHtml}` : "";
|
||||||
|
const straightUpWhich = (individualBet.which == 37) ? "00" : individualBet.which;
|
||||||
|
const details = {
|
||||||
|
STRAIGHT_UP_BET: `that the number will be ${straightUpWhich}`,
|
||||||
|
LINE_BET: `that the number will be within line ${individualBet.which}`,
|
||||||
|
COLUMN_BET: `that the number will be within column ${individualBet.which}`,
|
||||||
|
DOZEN_BET: `that the number will be within dozen ${individualBet.which}`,
|
||||||
|
EVEN_ODD_BET: `that the number will be ${individualBet.which.toLowerCase()}`,
|
||||||
|
RED_BLACK_BET: `that the color of the number will be ${individualBet.which.toLowerCase()}`,
|
||||||
|
HIGH_LOW_BET: `that the number will be ${individualBet.which === "HIGH" ? "higher than 18" : "lower than 19"}`
|
||||||
|
}
|
||||||
|
const betText = coinText && procoinText ? `${coinText} and ${procoinText}` : coinText || procoinText;
|
||||||
|
|
||||||
|
betHtml += `<li>${betText} ${details[individualBet.bet]}</li>`;
|
||||||
|
}
|
||||||
|
betHtml += `</ul>`;
|
||||||
|
betHtml += `</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
betArea.innerHTML = betHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeChip(bet, which) {
|
||||||
|
const { amount, currency: safeCurrency, localCurrency: currency } = getWager();
|
||||||
|
const whichNice = which == 37 ? "00" : which;
|
||||||
|
const texts = {
|
||||||
|
STRAIGHT_UP_BET: `Bet ${amount} ${currency} on ${whichNice}?\nYou could win ${amount * 35} ${currency}.`,
|
||||||
|
LINE_BET: `Bet ${amount} ${currency} on line ${which}?\nYou could win ${amount * 5} ${currency}.`,
|
||||||
|
COLUMN_BET: `Bet ${amount} ${currency} column ${which}?\nYou could win ${amount * 2} ${currency}.`,
|
||||||
|
DOZEN_BET: `Bet ${amount} ${currency} dozen ${which}?\nYou could win ${amount * 2} ${currency}.`,
|
||||||
|
EVEN_ODD_BET: `Bet ${amount} ${currency} that the number will be ${which.toLowerCase()}?\nYou could win ${amount} ${currency}.`,
|
||||||
|
RED_BLACK_BET: `Bet ${amount} ${currency} that the number will be ${which.toLowerCase()}?\nYou could win ${amount} ${currency}.`,
|
||||||
|
HIGH_LOW_BET: `Bet ${amount} ${currency} that the number will be ${which === "HIGH" ? "higher than 18" : "lower than 19"}?\nYou could win ${amount} ${currency}.`,
|
||||||
|
}
|
||||||
|
const text = texts[bet] || "";
|
||||||
|
const confirmed = window.confirm(text);
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("post", "/casino/roulette/place-bet");
|
||||||
|
xhr.setRequestHeader('xhr', 'xhr');
|
||||||
|
xhr.onload = handleRouletteResponse.bind(null, xhr);
|
||||||
|
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
form.append("bet", bet);
|
||||||
|
form.append("which", which);
|
||||||
|
form.append("wager", amount);
|
||||||
|
form.append("currency", safeCurrency);
|
||||||
|
|
||||||
|
xhr.send(form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addChipsToTable(bets) {
|
||||||
|
const flatBets = formatFlatBets(bets);
|
||||||
|
|
||||||
|
for (const bet of flatBets) {
|
||||||
|
const tableElement = document.getElementById(`${bet.bet}#${bet.which}`);
|
||||||
|
tableElement.style.position = 'relative';
|
||||||
|
const count = tableElement.dataset.count ? parseInt(tableElement.dataset.count) + 1 : 1;
|
||||||
|
tableElement.dataset.count = count;
|
||||||
|
|
||||||
|
const chip = buildPokerChip(bet.gambler_profile_url)
|
||||||
|
tableElement.innerHTML = `${tableElement.innerHTML}<div style="position: absolute; bottom: ${count + 2}px; left: -${count + 2}px; transform: scale(0.5);">${chip}</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestRouletteBets() {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("get", "/casino/roulette/bets");
|
||||||
|
xhr.setRequestHeader('xhr', 'xhr');
|
||||||
|
xhr.onload = handleRouletteResponse.bind(null, xhr);
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRouletteResponse(xhr) {
|
||||||
|
let response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = JSON.parse(xhr.response);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const succeeded =
|
||||||
|
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
||||||
|
|
||||||
|
if (succeeded) {
|
||||||
|
buildRouletteBets(response.bets);
|
||||||
|
addChipsToTable(response.bets);
|
||||||
|
updatePlayerCurrencies(response.gambler);
|
||||||
|
updateResult("Rolls occur every five minutes", "success");
|
||||||
|
} else {
|
||||||
|
updateResult("Unable to place that bet.", "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
document.readyState === "complete" ||
|
||||||
|
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
||||||
|
) {
|
||||||
|
initializeGame();
|
||||||
|
} else {
|
||||||
|
document.addEventListener("load", initializeGame);
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
function pullSlots() {
|
||||||
|
const { amount, currency } = getWager();
|
||||||
|
|
||||||
|
console.log({amount, currency})
|
||||||
|
|
||||||
|
disableWager();
|
||||||
|
clearResult();
|
||||||
|
document.getElementById("casinoSlotsPull").disabled = true;
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("post", "/casino/slots");
|
||||||
|
xhr.setRequestHeader('xhr', 'xhr');
|
||||||
|
xhr.onload = handleSlotsResponse.bind(null, xhr);
|
||||||
|
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("formkey", formkey());
|
||||||
|
form.append("wager", amount);
|
||||||
|
form.append("currency", currency);
|
||||||
|
|
||||||
|
xhr.send(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSlotsResponse(xhr) {
|
||||||
|
let response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = JSON.parse(xhr.response);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const succeeded =
|
||||||
|
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
||||||
|
|
||||||
|
if (succeeded) {
|
||||||
|
const { game_state, gambler } = response;
|
||||||
|
const state = JSON.parse(game_state);
|
||||||
|
const reels = Array.from(document.querySelectorAll(".slots_reel"));
|
||||||
|
const symbols = state.symbols.split(",");
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
reels[i].innerHTML = symbols[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
let className;
|
||||||
|
|
||||||
|
if (state.text.includes("Jackpot")) {
|
||||||
|
className = "warning";
|
||||||
|
} else if (state.text.includes("Won")) {
|
||||||
|
className = "success";
|
||||||
|
} else if (state.text.includes("Lost")) {
|
||||||
|
className = "danger";
|
||||||
|
} else {
|
||||||
|
className = "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
updateResult(state.text, className);
|
||||||
|
updatePlayerCurrencies(gambler);
|
||||||
|
reloadFeed()
|
||||||
|
} else {
|
||||||
|
updateResult(response.error, "danger");
|
||||||
|
console.error(response.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
enableWager();
|
||||||
|
document.getElementById("casinoSlotsPull").disabled = false;
|
||||||
|
}
|
|
@ -1,232 +1,7 @@
|
||||||
{% extends "casino/game_screen.html" %}
|
{% extends "casino/game_screen.html" %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script nonce="{{g.nonce}}">
|
<script defer src="{{'js/blackjack_screen.js' | asset}}"></script>
|
||||||
function makeBlackjackRequest(action) {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("post", `/casino/twentyone/${action}`);
|
|
||||||
xhr.setRequestHeader('xhr', 'xhr');
|
|
||||||
xhr.onload = handleBlackjackResponse.bind(null, xhr);
|
|
||||||
xhr.blackjackAction = action;
|
|
||||||
return xhr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleBlackjackResponse(xhr) {
|
|
||||||
let status;
|
|
||||||
try {
|
|
||||||
const response = JSON.parse(xhr.response);
|
|
||||||
const succeeded = xhr.status >= 200 &&
|
|
||||||
xhr.status < 300 &&
|
|
||||||
response &&
|
|
||||||
!response.error;
|
|
||||||
|
|
||||||
clearResult();
|
|
||||||
status = xhr.status;
|
|
||||||
|
|
||||||
if (status == 429) {
|
|
||||||
throw new Error(response["details"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (succeeded) {
|
|
||||||
updateBlackjackTable(response.state);
|
|
||||||
updateFeed(response.feed);
|
|
||||||
updatePlayerCurrencies(response.gambler);
|
|
||||||
} else {
|
|
||||||
console.error("Error: ", response.error);
|
|
||||||
throw new Error("Error")
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const results = {
|
|
||||||
deal: "Unable to deal a new hand. Is one in progress?",
|
|
||||||
hit: "Unable to hit.",
|
|
||||||
stay: "Unable to stay.",
|
|
||||||
"double-down": "Unable to double down.",
|
|
||||||
"buy-insurance": "Unable to buy insurance."
|
|
||||||
};
|
|
||||||
result = results[xhr.blackjackAction];
|
|
||||||
|
|
||||||
if (status == 429) {
|
|
||||||
result = error.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateResult(result, "danger");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBlackjackActions(state) {
|
|
||||||
const actions = Array.from(document.querySelectorAll('.twentyone-btn'));
|
|
||||||
|
|
||||||
// Hide all actions.
|
|
||||||
actions.forEach(action => action.style.display = 'none');
|
|
||||||
|
|
||||||
if (state) {
|
|
||||||
// Show the correct ones.
|
|
||||||
state.actions.forEach(action => document.getElementById(`twentyone-${action}`).style.display = 'inline-block');
|
|
||||||
} else {
|
|
||||||
const dealButton = document.getElementById(`twentyone-DEAL`);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const dealButton = document.getElementById(`twentyone-DEAL`);
|
|
||||||
})
|
|
||||||
|
|
||||||
if (dealButton) {
|
|
||||||
dealButton.style.display = 'inline-block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBlackjackTable(state) {
|
|
||||||
const table = document.getElementById('blackjack-table');
|
|
||||||
const charactersToRanks = {
|
|
||||||
X: "10"
|
|
||||||
};
|
|
||||||
const charactersToSuits = {
|
|
||||||
S: "♠️",
|
|
||||||
H: "♥️",
|
|
||||||
C: "♣️",
|
|
||||||
D: "♦️",
|
|
||||||
};
|
|
||||||
const makeCardset = (from, who, value) => `
|
|
||||||
<div class="blackjack-cardset">
|
|
||||||
<div class="blackjack-cardset-value">
|
|
||||||
${value === -1 ? `${who} went bust` : `${who} has ${value}`}
|
|
||||||
</div>
|
|
||||||
${from
|
|
||||||
.filter(card => card !== "?")
|
|
||||||
.map(([rankCharacter, suitCharacter]) => {
|
|
||||||
const rank = charactersToRanks[rankCharacter] || rankCharacter;
|
|
||||||
const suit = charactersToSuits[suitCharacter] || suitCharacter;
|
|
||||||
return buildPlayingCard(rank, suit);
|
|
||||||
})
|
|
||||||
.join('')}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
const dealerCards = makeCardset(state.dealer, 'Dealer', state.dealer_value);
|
|
||||||
const playerCards = makeCardset(state.player, 'Player', state.player_value);
|
|
||||||
|
|
||||||
updateBlackjackActions(state);
|
|
||||||
|
|
||||||
table.innerHTML = `
|
|
||||||
<div style="position: relative;">
|
|
||||||
${dealerCards}
|
|
||||||
</div>
|
|
||||||
${playerCards}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const currency = state.wager.currency === 'coins' ? 'coins' : 'marseybux';
|
|
||||||
|
|
||||||
switch (state.status) {
|
|
||||||
case 'BLACKJACK':
|
|
||||||
updateResult(`Blackjack: Received ${state.payout} ${currency}`, "warning");
|
|
||||||
break;
|
|
||||||
case 'WON':
|
|
||||||
updateResult(`Won: Received ${state.payout} ${currency}`, "success");
|
|
||||||
break;
|
|
||||||
case 'PUSHED':
|
|
||||||
updateResult(`Pushed: Received ${state.wager.amount} ${currency}`, "success");
|
|
||||||
break;
|
|
||||||
case 'LOST':
|
|
||||||
updateResult(`Lost ${state.wager.amount} ${currency}`, "danger");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCardsetBackgrounds(state);
|
|
||||||
|
|
||||||
if (state.status === 'PLAYING') {
|
|
||||||
updateResult(`${state.wager.amount} ${currency} are at stake`, "success");
|
|
||||||
} else {
|
|
||||||
enableWager();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCardsetBackgrounds(state) {
|
|
||||||
const cardsets = Array.from(document.querySelectorAll('.blackjack-cardset'));
|
|
||||||
|
|
||||||
for (const cardset of cardsets) {
|
|
||||||
['PLAYING', 'LOST', 'PUSHED', 'WON', 'BLACKJACK'].forEach(status => cardset.classList.remove(`blackjack-cardset__${status}`));
|
|
||||||
cardset.classList.add(`blackjack-cardset__${state.status}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deal() {
|
|
||||||
const request = makeBlackjackRequest('deal');
|
|
||||||
const { amount, currency } = getWager();
|
|
||||||
const form = new FormData();
|
|
||||||
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
form.append("wager", amount);
|
|
||||||
form.append("currency", currency);
|
|
||||||
|
|
||||||
request.send(form);
|
|
||||||
|
|
||||||
clearResult();
|
|
||||||
disableWager();
|
|
||||||
drawFromDeck();
|
|
||||||
}
|
|
||||||
|
|
||||||
function hit() {
|
|
||||||
const request = makeBlackjackRequest('hit');
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
request.send(form);
|
|
||||||
|
|
||||||
drawFromDeck();
|
|
||||||
}
|
|
||||||
|
|
||||||
function stay() {
|
|
||||||
const request = makeBlackjackRequest('stay');
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
request.send(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doubleDown() {
|
|
||||||
const request = makeBlackjackRequest('double-down');
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
request.send(form);
|
|
||||||
|
|
||||||
drawFromDeck();
|
|
||||||
}
|
|
||||||
|
|
||||||
function buyInsurance() {
|
|
||||||
const request = makeBlackjackRequest('buy-insurance');
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
request.send(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildBlackjackDeck() {
|
|
||||||
document.getElementById('blackjack-table-deck').innerHTML = `
|
|
||||||
<div style="position: absolute; top: 150px; left: -100px;">
|
|
||||||
${buildPlayingCardDeck()}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeBlackjack() {
|
|
||||||
buildBlackjackDeck();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const passed = document.getElementById('blackjack-table').dataset.state;
|
|
||||||
const state = JSON.parse(passed);
|
|
||||||
updateBlackjackTable(state);
|
|
||||||
} catch (error) {
|
|
||||||
updateBlackjackActions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
document.readyState === "complete" ||
|
|
||||||
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
|
||||||
) {
|
|
||||||
initializeBlackjack();
|
|
||||||
} else {
|
|
||||||
document.addEventListener("load", initializeBlackjack);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block screen %}
|
{% block screen %}
|
||||||
|
|
|
@ -27,209 +27,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script nonce="{{g.nonce}}">
|
<script defer src="{{'js/game_screen.js' | asset}}"></script>
|
||||||
/**
|
|
||||||
* This script block contains generic helper function usable across casino games:
|
|
||||||
* - Wagers
|
|
||||||
* - Feed
|
|
||||||
* - Leaderboard
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (
|
|
||||||
document.readyState === "complete" ||
|
|
||||||
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
|
||||||
) {
|
|
||||||
initializeGame();
|
|
||||||
} else {
|
|
||||||
document.addEventListener("load", initializeGame);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeGame() {
|
|
||||||
updateFeed();
|
|
||||||
updateLeaderboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePlayerCurrencies(updated) {
|
|
||||||
if (updated.coins) {
|
|
||||||
document.getElementById("user-coins-amount").innerText = updated.coins;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updated.marseybux) {
|
|
||||||
document.getElementById("user-bux-amount").innerText = updated.marseybux;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWager() {
|
|
||||||
const amount = document.getElementById("wagerAmount").value;
|
|
||||||
const currency = document.querySelector(
|
|
||||||
'input[name="wagerCurrency"]:checked'
|
|
||||||
).value;
|
|
||||||
const genericCurrency = currency == 'marseybux' ? 'marseybux' : 'coins';
|
|
||||||
|
|
||||||
return { amount, currency: genericCurrency, localCurrency: currency };
|
|
||||||
}
|
|
||||||
|
|
||||||
function disableWager() {
|
|
||||||
document.getElementById("wagerAmount").disabled = true;
|
|
||||||
document.getElementById("wagerCoins").disabled = true;
|
|
||||||
document.getElementById("wagerMarseybux").disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function enableWager() {
|
|
||||||
document.getElementById("wagerAmount").disabled = false;
|
|
||||||
document.getElementById("wagerCoins").disabled = false;
|
|
||||||
document.getElementById("wagerMarseybux").disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateResult(text, className) {
|
|
||||||
clearResult();
|
|
||||||
const result = document.getElementById("casinoGameResult");
|
|
||||||
result.style.visibility = "visible";
|
|
||||||
result.innerText = text;
|
|
||||||
result.classList.add(`alert-${className}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearResult() {
|
|
||||||
const result = document.getElementById("casinoGameResult");
|
|
||||||
result.style.visibility = "hidden";
|
|
||||||
result.innerText = "N/A";
|
|
||||||
result.classList.remove("alert-success", "alert-danger", "alert-warning");
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFeed(newFeed) {
|
|
||||||
let feed;
|
|
||||||
|
|
||||||
if (newFeed) {
|
|
||||||
feed = newFeed;
|
|
||||||
} else {
|
|
||||||
const gameFeed = document.getElementById("casinoGameFeed");
|
|
||||||
feed = gameFeed.dataset.feed;
|
|
||||||
feed = JSON.parse(feed);
|
|
||||||
gameFeed.dataset.feed = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const feedHtml = feed
|
|
||||||
.map(
|
|
||||||
(entry) =>
|
|
||||||
`
|
|
||||||
<li
|
|
||||||
style="display: flex; align-items: center; justify-content: space-between;"
|
|
||||||
class="${entry.won_or_lost === "won" ? "text-success" : "text-danger"}">
|
|
||||||
<div>
|
|
||||||
<a href="/@${entry.user}">@${entry.user}</a> ${entry.won_or_lost} ${entry.amount
|
|
||||||
} ${entry.currency}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
.join("");
|
|
||||||
|
|
||||||
document.getElementById("casinoGameFeedList").innerHTML = feedHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadFeed() {
|
|
||||||
const game = document.getElementById('casino-game-wrapper').dataset.game;
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("get", `/casino/${game}/feed`);
|
|
||||||
xhr.setRequestHeader('xhr', 'xhr');
|
|
||||||
xhr.onload = handleFeedResponse.bind(null, xhr);
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFeedResponse(xhr) {
|
|
||||||
let response;
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = JSON.parse(xhr.response);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const succeeded =
|
|
||||||
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
|
||||||
|
|
||||||
if (succeeded) {
|
|
||||||
document.getElementById("casinoGameFeed").dataset.feed = JSON.stringify(response.feed);
|
|
||||||
updateFeed();
|
|
||||||
} else {
|
|
||||||
console.error("error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLeaderboard() {
|
|
||||||
const leaderboardContainer = document.getElementById("gameLeaderboard");
|
|
||||||
const leaderboardData = JSON.parse(leaderboardContainer.dataset.leaderboard);
|
|
||||||
const [biggestWinnerAllTime, biggestWinner24h, biggestLoser24h, biggestLoserAllTime] = [
|
|
||||||
'biggestWinnerAllTime', 'biggestWinner24h', 'biggestLoser24h', 'biggestLoserAllTime'
|
|
||||||
].map(id => document.getElementById(id));
|
|
||||||
const formatLocalCurrencyName = currency => ({ coins: 'coins', marseybux: 'marseybux' })[currency];
|
|
||||||
|
|
||||||
biggestWinnerAllTime.innerHTML = `
|
|
||||||
<a href="/@${leaderboardData.all_time.biggest_win.user}">${leaderboardData.all_time.biggest_win.user}</a> <br><small>${leaderboardData.all_time.biggest_win.amount} ${formatLocalCurrencyName(leaderboardData.all_time.biggest_win.currency)}</small>
|
|
||||||
`;
|
|
||||||
|
|
||||||
biggestWinner24h.innerHTML = `
|
|
||||||
<a href="/@${leaderboardData.last_24h.biggest_win.user}">${leaderboardData.last_24h.biggest_win.user}</a> <br> <small>${leaderboardData.last_24h.biggest_win.amount} ${formatLocalCurrencyName(leaderboardData.last_24h.biggest_win.currency)}</small>
|
|
||||||
`;
|
|
||||||
|
|
||||||
biggestLoser24h.innerHTML = `
|
|
||||||
<a href="/@${leaderboardData.last_24h.biggest_loss.user}">${leaderboardData.last_24h.biggest_loss.user}</a> <br> <small>${leaderboardData.last_24h.biggest_loss.amount} ${formatLocalCurrencyName(leaderboardData.last_24h.biggest_loss.currency)}</small>
|
|
||||||
`;
|
|
||||||
|
|
||||||
biggestLoserAllTime.innerHTML = `
|
|
||||||
<a href="/@${leaderboardData.all_time.biggest_loss.user}">${leaderboardData.all_time.biggest_loss.user}</a> <br> <small>${leaderboardData.all_time.biggest_loss.amount} ${formatLocalCurrencyName(leaderboardData.all_time.biggest_loss.currency)}</small>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandomInt(min, max) {
|
|
||||||
min = Math.ceil(min);
|
|
||||||
max = Math.floor(max);
|
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandomCardAngle() {
|
|
||||||
const skew = 10
|
|
||||||
return getRandomInt(-skew, skew);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildPlayingCard(rank, suit) {
|
|
||||||
return `
|
|
||||||
<div
|
|
||||||
style="transform: scale(0.7) rotateZ(${getRandomCardAngle()}deg)"
|
|
||||||
class="playing-card playing-card_${["♥️", "♦️"].includes(suit) ? 'red' : 'black'}">
|
|
||||||
<div class="playing-card_small playing-card_topright">${rank}${suit}</div>
|
|
||||||
<div class="playing-card_large">${rank}${suit}</div>
|
|
||||||
<div class="playing-card_small playing-card_bottomleft">${rank}${suit}</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildPlayingCardDeck(size = 14) {
|
|
||||||
const cards = Array.from({ length: size }, (_, index) => `
|
|
||||||
<div
|
|
||||||
style="bottom: ${index}px; left: ${-index}px"
|
|
||||||
class="flipped-playing-card"></div>
|
|
||||||
`).join('\n');
|
|
||||||
|
|
||||||
return `
|
|
||||||
<div id="playingCardDeck" class="playing-card-deck">
|
|
||||||
${cards}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawFromDeck() {
|
|
||||||
try {
|
|
||||||
const [topCard] = Array.from(document.querySelectorAll("#playingCardDeck > *")).reverse();
|
|
||||||
|
|
||||||
topCard.classList.add('drawing-a-card');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
topCard.classList.remove('drawing-a-card');
|
|
||||||
}, 600);
|
|
||||||
} catch { }
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% block script %} {% endblock %}
|
{% block script %} {% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -1,395 +1,7 @@
|
||||||
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
|
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script nonce="{{g.nonce}}">
|
<script defer src="{{'js/roulette_screen.js' | asset}}"></script>
|
||||||
if (
|
|
||||||
document.readyState === "complete" ||
|
|
||||||
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
|
||||||
) {
|
|
||||||
initializeGame();
|
|
||||||
} else {
|
|
||||||
document.addEventListener("load", initializeGame);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kiss my ass if you're judgin'
|
|
||||||
const CELL_TO_NUMBER_LOOKUP = {
|
|
||||||
1: 3,
|
|
||||||
2: 6,
|
|
||||||
3: 9,
|
|
||||||
4: 12,
|
|
||||||
5: 15,
|
|
||||||
6: 18,
|
|
||||||
7: 21,
|
|
||||||
8: 24,
|
|
||||||
9: 27,
|
|
||||||
10: 30,
|
|
||||||
11: 33,
|
|
||||||
12: 36,
|
|
||||||
13: 2,
|
|
||||||
14: 5,
|
|
||||||
15: 8,
|
|
||||||
16: 11,
|
|
||||||
17: 14,
|
|
||||||
18: 17,
|
|
||||||
19: 20,
|
|
||||||
20: 23,
|
|
||||||
21: 26,
|
|
||||||
22: 29,
|
|
||||||
23: 32,
|
|
||||||
24: 35,
|
|
||||||
25: 1,
|
|
||||||
26: 4,
|
|
||||||
27: 7,
|
|
||||||
28: 10,
|
|
||||||
29: 13,
|
|
||||||
30: 16,
|
|
||||||
31: 19,
|
|
||||||
32: 22,
|
|
||||||
33: 25,
|
|
||||||
34: 28,
|
|
||||||
35: 31,
|
|
||||||
36: 34
|
|
||||||
};
|
|
||||||
|
|
||||||
function initializeGame() {
|
|
||||||
buildRouletteTable();
|
|
||||||
updateResult("Rolls occur every five minutes", "success");
|
|
||||||
requestRouletteBets();
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildRouletteTable() {
|
|
||||||
const table = document.getElementById('roulette-table');
|
|
||||||
const reds = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
|
|
||||||
|
|
||||||
let html = "";
|
|
||||||
|
|
||||||
// Lines
|
|
||||||
html += `
|
|
||||||
<div class="roulette-table-row">
|
|
||||||
<div style="flex: 1"></div>
|
|
||||||
<div id="LINE_BET#1" onclick="placeChip('LINE_BET', '1')" class="roulette-table-1to1">Line 1</div>
|
|
||||||
<div id="LINE_BET#2" onclick="placeChip('LINE_BET', '2')" class="roulette-table-1to1">Line 2</div>
|
|
||||||
<div id="LINE_BET#3" onclick="placeChip('LINE_BET', '3')" class="roulette-table-1to1">Line 3</div>
|
|
||||||
<div id="LINE_BET#4" onclick="placeChip('LINE_BET', '4')" class="roulette-table-1to1">Line 4</div>
|
|
||||||
<div id="LINE_BET#5" onclick="placeChip('LINE_BET', '5')" class="roulette-table-1to1">Line 5</div>
|
|
||||||
<div id="LINE_BET#6" onclick="placeChip('LINE_BET', '6')" class="roulette-table-1to1">Line 6</div>
|
|
||||||
<div style="flex: 1"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// First Column
|
|
||||||
html += "<div class=\"roulette-table-row\">";
|
|
||||||
html += `<div id="STRAIGHT_UP_BET#37" onclick="placeChip('STRAIGHT_UP_BET', '37')" class="roulette-table-number roulette-table-number__green">00</div>`
|
|
||||||
for (let i = 1; i < 13; i++) {
|
|
||||||
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
|
||||||
const isRed = reds.includes(correctNumber);
|
|
||||||
|
|
||||||
html += `<div
|
|
||||||
id="STRAIGHT_UP_BET#${correctNumber}"
|
|
||||||
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
|
||||||
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
|
||||||
${correctNumber}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
html += `<div id="COLUMN_BET#3" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '3')">Col 3</div>`;
|
|
||||||
html += "</div>";
|
|
||||||
|
|
||||||
// Second Column
|
|
||||||
html += "<div class=\"roulette-table-row\">";
|
|
||||||
html += `<div id="roulette-spacer-left-middle" class="roulette-table-number roulette-table-number__green"></div>`
|
|
||||||
for (let i = 13; i < 25; i++) {
|
|
||||||
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
|
||||||
const isRed = reds.includes(correctNumber);
|
|
||||||
|
|
||||||
html += `<div
|
|
||||||
id="STRAIGHT_UP_BET#${correctNumber}"
|
|
||||||
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
|
||||||
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
|
||||||
${correctNumber}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
html += `<div id="COLUMN_BET#2" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '2')">Col 2</div>`;
|
|
||||||
html += "</div>";
|
|
||||||
|
|
||||||
// Third Column
|
|
||||||
html += "<div class=\"roulette-table-row\">";
|
|
||||||
html += `<div id="STRAIGHT_UP_BET#0" onclick="placeChip('STRAIGHT_UP_BET', '0')" class="roulette-table-number roulette-table-number__green">0</div>`
|
|
||||||
for (let i = 25; i < 37; i++) {
|
|
||||||
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
|
||||||
const isRed = reds.includes(correctNumber);
|
|
||||||
|
|
||||||
html += `<div
|
|
||||||
id="STRAIGHT_UP_BET#${correctNumber}"
|
|
||||||
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
|
||||||
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
|
||||||
${correctNumber}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
html += `<div id="COLUMN_BET#1" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '1')">Col 1</div>`;
|
|
||||||
html += "</div>";
|
|
||||||
|
|
||||||
// Line Bets and 1:1 Bets
|
|
||||||
html += `
|
|
||||||
<div class="roulette-table-row">
|
|
||||||
<div style="flex: 1"></div>
|
|
||||||
<div id="DOZEN_BET#1" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '1')">1st12</div>
|
|
||||||
<div id="DOZEN_BET#2" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '2')">2nd12</div>
|
|
||||||
<div id="DOZEN_BET#3" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '3')">3rd12</div>
|
|
||||||
<div style="flex: 1"></div>
|
|
||||||
</div>
|
|
||||||
<div class="roulette-table-row">
|
|
||||||
<div style="flex: 1"></div>
|
|
||||||
<div id="HIGH_LOW_BET#LOW" class="roulette-table-1to1" onclick="placeChip('HIGH_LOW_BET', 'LOW')">1:18</div>
|
|
||||||
<div id="EVEN_ODD_BET#EVEN" class="roulette-table-1to1" onclick="placeChip('EVEN_ODD_BET', 'EVEN')">EVEN</div>
|
|
||||||
<div id="RED_BLACK_BET#RED" class="roulette-table-1to1" onclick="placeChip('RED_BLACK_BET', 'RED')" style="background-color: red">RED</div>
|
|
||||||
<div id="RED_BLACK_BET#BLACK" class="roulette-table-1to1" onclick="placeChip('RED_BLACK_BET', 'BLACK')" style="background-color: black">BLACK</div>
|
|
||||||
<div id="EVEN_ODD_BET#ODD" class="roulette-table-1to1" onclick="placeChip('EVEN_ODD_BET', 'ODD')">ODD</div>
|
|
||||||
<div id="HIGH_LOW_BET#HIGH" class="roulette-table-1to1" onclick="placeChip('HIGH_LOW_BET', 'HIGH')">19:36</div>
|
|
||||||
<div style="flex: 1"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
table.innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatFlatBets(bets) {
|
|
||||||
let flatBets = [];
|
|
||||||
|
|
||||||
for (const betCollection of Object.values(bets)) {
|
|
||||||
flatBets = flatBets.concat(betCollection)
|
|
||||||
}
|
|
||||||
|
|
||||||
return flatBets;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatNormalizedBets(bets) {
|
|
||||||
const normalizedBets = {
|
|
||||||
gamblers: [],
|
|
||||||
gamblersByName: {}
|
|
||||||
};
|
|
||||||
const flatBets = formatFlatBets(bets);
|
|
||||||
|
|
||||||
for (const bet of flatBets) {
|
|
||||||
if (!normalizedBets.gamblers.includes(bet.gambler_username)) {
|
|
||||||
normalizedBets.gamblers.push(bet.gambler_username);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!normalizedBets.gamblersByName[bet.gambler_username]) {
|
|
||||||
normalizedBets.gamblersByName[bet.gambler_username] = {
|
|
||||||
name: bet.gambler_username,
|
|
||||||
avatar: bet.gambler_profile_url,
|
|
||||||
profile: `/@${bet.gambler_username}`,
|
|
||||||
wagerTotal: {
|
|
||||||
coins: 0,
|
|
||||||
marseybux: 0
|
|
||||||
},
|
|
||||||
wagers: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const entry = normalizedBets.gamblersByName[bet.gambler_username];
|
|
||||||
|
|
||||||
entry.wagerTotal[bet.wager.currency] += bet.wager.amount;
|
|
||||||
|
|
||||||
const existingWager = entry.wagers.find(wager => wager.bet === bet.bet && wager.which === bet.which);
|
|
||||||
|
|
||||||
if (existingWager) {
|
|
||||||
existingWager.amounts[bet.wager.currency] += bet.wager.amount;
|
|
||||||
} else {
|
|
||||||
const newEntry = {
|
|
||||||
bet: bet.bet,
|
|
||||||
which: bet.which,
|
|
||||||
amounts: {
|
|
||||||
coins: 0,
|
|
||||||
marseybux: 0
|
|
||||||
},
|
|
||||||
};
|
|
||||||
newEntry.amounts[bet.wager.currency] += bet.wager.amount;
|
|
||||||
|
|
||||||
entry.wagers.push(newEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizedBets;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildPokerChip(avatar) {
|
|
||||||
return `
|
|
||||||
<div class="roulette-poker-chip">
|
|
||||||
<img src="/i/pokerchip.webp" width="40" height="40">
|
|
||||||
<img src="${avatar}" width="40" height="40">
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildRouletteBets(bets) {
|
|
||||||
const betArea = document.getElementById("roulette-bets");
|
|
||||||
const flatBets = formatFlatBets(bets);
|
|
||||||
const normalizedBets = formatNormalizedBets(bets);
|
|
||||||
const coinImgHtml = `
|
|
||||||
<img
|
|
||||||
src="/i/rDrama/coins.webp?v=3009"
|
|
||||||
alt="coin"
|
|
||||||
width="32"
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-placement="bottom"
|
|
||||||
title=""
|
|
||||||
aria-label="Coin"
|
|
||||||
data-bs-original-title="Coin">
|
|
||||||
`;
|
|
||||||
const marseybuxImgHtml = `
|
|
||||||
<img
|
|
||||||
src="/i/marseybux.webp?v=2000"
|
|
||||||
alt="marseybux"
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-placement="bottom"
|
|
||||||
title=""
|
|
||||||
aria-label="Marseybux"
|
|
||||||
width="32" class="mr-1 ml-1"
|
|
||||||
data-bs-original-title="Marseybux">
|
|
||||||
`;
|
|
||||||
const { participants, coin, marseybux } = flatBets.reduce((prev, next) => {
|
|
||||||
if (!prev.participants.includes(next.gambler_username)) {
|
|
||||||
prev.participants.push(next.gambler_username);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next.wager.currency == 'coins') {
|
|
||||||
prev.coin += next.wager.amount;
|
|
||||||
} else {
|
|
||||||
prev.marseybux += next.wager.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prev;
|
|
||||||
}, { participants: [], coin: 0, marseybux: 0 });
|
|
||||||
const coinText = `${coin} ${coinImgHtml}`;
|
|
||||||
const marseybuxText = `${marseybux} ${marseybuxImgHtml}`;
|
|
||||||
const playerText = participants.length > 1 ? `${participants.length} players are` : `1 player is`;
|
|
||||||
const totalText = coin && marseybux ? `${coinText} and ${marseybuxText}` : coin ? coinText : marseybuxText;
|
|
||||||
const fullTotalText = participants.length === 0 ? "No one has placed a bet" : `${playerText} betting a total of ${totalText}`;
|
|
||||||
|
|
||||||
let betHtml = `
|
|
||||||
<small class="roulette-total-bets">${fullTotalText}</small>
|
|
||||||
<hr>
|
|
||||||
`;
|
|
||||||
|
|
||||||
for (player of normalizedBets.gamblers) {
|
|
||||||
const { name, avatar, wagerTotal, wagers } = normalizedBets.gamblersByName[player];
|
|
||||||
|
|
||||||
betHtml += `<div class="roulette-bet-summary">`;
|
|
||||||
// Heading
|
|
||||||
betHtml += ` <div class="roulette-bet-summary--heading">`;
|
|
||||||
betHtml += buildPokerChip(avatar);
|
|
||||||
const coinText = wagerTotal.coins > 0 ? `${wagerTotal.coins} ${coinImgHtml}` : "";
|
|
||||||
const procoinText = wagerTotal.marseybux > 0 ? `${wagerTotal.marseybux} ${marseybuxImgHtml}` : "";
|
|
||||||
const bettingText = coinText && procoinText ? `${coinText} and ${procoinText}` : coinText || procoinText;
|
|
||||||
betHtml += `<p>${name} is betting ${bettingText}:</p>`;
|
|
||||||
betHtml += ` </div>`;
|
|
||||||
|
|
||||||
// Individual bets
|
|
||||||
betHtml += `<ul class="roulette-bet-summary--list">`;
|
|
||||||
for (const individualBet of wagers) {
|
|
||||||
const coinText = individualBet.amounts.coins > 0 ? `${individualBet.amounts.coins} ${coinImgHtml}` : "";
|
|
||||||
const procoinText = individualBet.amounts.marseybux > 0 ? `${individualBet.amounts.marseybux} ${marseybuxImgHtml}` : "";
|
|
||||||
const straightUpWhich = (individualBet.which == 37) ? "00" : individualBet.which;
|
|
||||||
const details = {
|
|
||||||
STRAIGHT_UP_BET: `that the number will be ${straightUpWhich}`,
|
|
||||||
LINE_BET: `that the number will be within line ${individualBet.which}`,
|
|
||||||
COLUMN_BET: `that the number will be within column ${individualBet.which}`,
|
|
||||||
DOZEN_BET: `that the number will be within dozen ${individualBet.which}`,
|
|
||||||
EVEN_ODD_BET: `that the number will be ${individualBet.which.toLowerCase()}`,
|
|
||||||
RED_BLACK_BET: `that the color of the number will be ${individualBet.which.toLowerCase()}`,
|
|
||||||
HIGH_LOW_BET: `that the number will be ${individualBet.which === "HIGH" ? "higher than 18" : "lower than 19"}`
|
|
||||||
}
|
|
||||||
const betText = coinText && procoinText ? `${coinText} and ${procoinText}` : coinText || procoinText;
|
|
||||||
|
|
||||||
betHtml += `<li>${betText} ${details[individualBet.bet]}</li>`;
|
|
||||||
}
|
|
||||||
betHtml += `</ul>`;
|
|
||||||
betHtml += `</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
betArea.innerHTML = betHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
function placeChip(bet, which) {
|
|
||||||
const { amount, currency: safeCurrency, localCurrency: currency } = getWager();
|
|
||||||
const whichNice = which == 37 ? "00" : which;
|
|
||||||
const texts = {
|
|
||||||
STRAIGHT_UP_BET: `Bet ${amount} ${currency} on ${whichNice}?\nYou could win ${amount * 35} ${currency}.`,
|
|
||||||
LINE_BET: `Bet ${amount} ${currency} on line ${which}?\nYou could win ${amount * 5} ${currency}.`,
|
|
||||||
COLUMN_BET: `Bet ${amount} ${currency} column ${which}?\nYou could win ${amount * 2} ${currency}.`,
|
|
||||||
DOZEN_BET: `Bet ${amount} ${currency} dozen ${which}?\nYou could win ${amount * 2} ${currency}.`,
|
|
||||||
EVEN_ODD_BET: `Bet ${amount} ${currency} that the number will be ${which.toLowerCase()}?\nYou could win ${amount} ${currency}.`,
|
|
||||||
RED_BLACK_BET: `Bet ${amount} ${currency} that the number will be ${which.toLowerCase()}?\nYou could win ${amount} ${currency}.`,
|
|
||||||
HIGH_LOW_BET: `Bet ${amount} ${currency} that the number will be ${which === "HIGH" ? "higher than 18" : "lower than 19"}?\nYou could win ${amount} ${currency}.`,
|
|
||||||
}
|
|
||||||
const text = texts[bet] || "";
|
|
||||||
const confirmed = window.confirm(text);
|
|
||||||
|
|
||||||
if (confirmed) {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("post", "/casino/roulette/place-bet");
|
|
||||||
xhr.setRequestHeader('xhr', 'xhr');
|
|
||||||
xhr.onload = handleRouletteResponse.bind(null, xhr);
|
|
||||||
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
form.append("bet", bet);
|
|
||||||
form.append("which", which);
|
|
||||||
form.append("wager", amount);
|
|
||||||
form.append("currency", safeCurrency);
|
|
||||||
|
|
||||||
xhr.send(form);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addChipsToTable(bets) {
|
|
||||||
const flatBets = formatFlatBets(bets);
|
|
||||||
|
|
||||||
for (const bet of flatBets) {
|
|
||||||
const tableElement = document.getElementById(`${bet.bet}#${bet.which}`);
|
|
||||||
tableElement.style.position = 'relative';
|
|
||||||
const count = tableElement.dataset.count ? parseInt(tableElement.dataset.count) + 1 : 1;
|
|
||||||
tableElement.dataset.count = count;
|
|
||||||
|
|
||||||
const chip = buildPokerChip(bet.gambler_profile_url)
|
|
||||||
tableElement.innerHTML = `${tableElement.innerHTML}<div style="position: absolute; bottom: ${count + 2}px; left: -${count + 2}px; transform: scale(0.5);">${chip}</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestRouletteBets() {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("get", "/casino/roulette/bets");
|
|
||||||
xhr.setRequestHeader('xhr', 'xhr');
|
|
||||||
xhr.onload = handleRouletteResponse.bind(null, xhr);
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleRouletteResponse(xhr) {
|
|
||||||
let response;
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = JSON.parse(xhr.response);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const succeeded =
|
|
||||||
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
|
||||||
|
|
||||||
if (succeeded) {
|
|
||||||
buildRouletteBets(response.bets);
|
|
||||||
addChipsToTable(response.bets);
|
|
||||||
updatePlayerCurrencies(response.gambler);
|
|
||||||
updateResult("Rolls occur every five minutes", "success");
|
|
||||||
} else {
|
|
||||||
updateResult("Unable to place that bet.", "danger");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block screen %}
|
{% block screen %}
|
||||||
|
|
|
@ -1,75 +1,7 @@
|
||||||
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
|
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script nonce="{{g.nonce}}">
|
<script defer src="{{'js/slots_screen.js' | asset}}"></script>
|
||||||
function pullSlots() {
|
|
||||||
const { amount, currency } = getWager();
|
|
||||||
|
|
||||||
console.log({amount, currency})
|
|
||||||
|
|
||||||
disableWager();
|
|
||||||
clearResult();
|
|
||||||
document.getElementById("casinoSlotsPull").disabled = true;
|
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("post", "/casino/slots");
|
|
||||||
xhr.setRequestHeader('xhr', 'xhr');
|
|
||||||
xhr.onload = handleSlotsResponse.bind(null, xhr);
|
|
||||||
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("formkey", formkey());
|
|
||||||
form.append("wager", amount);
|
|
||||||
form.append("currency", currency);
|
|
||||||
|
|
||||||
xhr.send(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSlotsResponse(xhr) {
|
|
||||||
let response;
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = JSON.parse(xhr.response);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const succeeded =
|
|
||||||
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
|
||||||
|
|
||||||
if (succeeded) {
|
|
||||||
const { game_state, gambler } = response;
|
|
||||||
const state = JSON.parse(game_state);
|
|
||||||
const reels = Array.from(document.querySelectorAll(".slots_reel"));
|
|
||||||
const symbols = state.symbols.split(",");
|
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
reels[i].innerHTML = symbols[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
let className;
|
|
||||||
|
|
||||||
if (state.text.includes("Jackpot")) {
|
|
||||||
className = "warning";
|
|
||||||
} else if (state.text.includes("Won")) {
|
|
||||||
className = "success";
|
|
||||||
} else if (state.text.includes("Lost")) {
|
|
||||||
className = "danger";
|
|
||||||
} else {
|
|
||||||
className = "success";
|
|
||||||
}
|
|
||||||
|
|
||||||
updateResult(state.text, className);
|
|
||||||
updatePlayerCurrencies(gambler);
|
|
||||||
reloadFeed()
|
|
||||||
} else {
|
|
||||||
updateResult(response.error, "danger");
|
|
||||||
console.error(response.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
enableWager();
|
|
||||||
document.getElementById("casinoSlotsPull").disabled = false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block screen %}
|
{% block screen %}
|
||||||
|
|
Loading…
Reference in New Issue