forked from MarseyWorld/MarseyWorld
Merge branch 'frost' of https://github.com/Aevann1/rDrama into frost
commit
41f9a128ac
|
@ -0,0 +1,138 @@
|
|||
.casino-games {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.casino-game {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Slots */
|
||||
#slots-block {
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.casino-slots-results {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.casino-slots-results .reel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 2px solid black;
|
||||
background-color: var(--gray);
|
||||
border: 1px solid var(--black);
|
||||
border-radius: 8px;
|
||||
font-size: 64px;
|
||||
}
|
||||
|
||||
.casino-slots-outcome {
|
||||
visibility: hidden;
|
||||
text-align: right;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
/* Blackjack */
|
||||
#blackjack-block {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.blackjack-table .hand .playing-card {
|
||||
width: 60px;
|
||||
height: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
.casino-blackjack-outcome {
|
||||
visibility: hidden;
|
||||
text-align: right;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.blackjack-table {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.blackjack-table .hand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.blackjack-table .hand .playing-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60px;
|
||||
height: 90px;
|
||||
border: 2px solid black;
|
||||
background-color: var(--gray);
|
||||
border: 1px solid var(--black);
|
||||
border-radius: 8px;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.blackjack-table .hand .playing-card.dealt {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.casino-blackjack-actions {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Lottery */
|
||||
.casino-lottery {
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
/* Blocks */
|
||||
.casino-block {
|
||||
padding: 1rem;
|
||||
border: 4px solid #361506;
|
||||
border-radius: 8px;
|
||||
background-color: #092711;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.casino-block-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 32px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 4px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.casino-block-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.casino-block-left {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.casino-block-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.casino-block-game {
|
||||
margin-right: 2rem;
|
||||
}
|
|
@ -5383,7 +5383,6 @@ audio, video {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.lottery-page--wrapper > div {
|
||||
|
@ -5987,6 +5986,7 @@ g {
|
|||
.fa-snowflake:before{content:"\f2dc"}
|
||||
.fa-sparkles:before{content:"\f890"}
|
||||
.fa-ticket:before{content:"\f145"}
|
||||
.fa-usd:before{content:"\f155"}
|
||||
.fa-spider:before{content:"\f717"}
|
||||
.fa-square:before{content:"\f0c8"}
|
||||
.fa-stocking:before{content:"\f7d5"}
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
// Shared
|
||||
function updatePlayerCoins(updated) {
|
||||
if (updated.coins) {
|
||||
document.getElementById('user-coins-amount').innerText = updated.coins;
|
||||
}
|
||||
|
||||
if (updated.procoins) {
|
||||
document.getElementById('user-bux-amount').innerText = updated.procoins;
|
||||
}
|
||||
}
|
||||
|
||||
// Slots
|
||||
function pullSlots() {
|
||||
const wager = document.getElementById("casinoSlotsBet").value;
|
||||
const currency = document.querySelector(
|
||||
'input[name="casinoSlotsCurrency"]:checked'
|
||||
).value;
|
||||
|
||||
document.getElementById("casinoSlotsBet").disabled = true;
|
||||
document.getElementById("casinoSlotsPull").disabled = true;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/casino/slots");
|
||||
xhr.onload = handleSlotsResponse.bind(null, xhr);
|
||||
|
||||
const form = new FormData();
|
||||
form.append("formkey", formkey());
|
||||
form.append("wager", wager);
|
||||
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;
|
||||
const slotsResult = document.getElementById("casinoSlotsResult");
|
||||
slotsResult.classList.remove("text-success", "text-danger");
|
||||
|
||||
if (succeeded) {
|
||||
const { game_state, gambler } = response;
|
||||
const state = JSON.parse(game_state);
|
||||
const reels = Array.from(document.querySelectorAll(".reel"));
|
||||
const symbols = state.symbols.split(",");
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
reels[i].innerHTML = symbols[i];
|
||||
}
|
||||
|
||||
slotsResult.style.visibility = "visible";
|
||||
slotsResult.innerText = state.text;
|
||||
|
||||
if (state.text.includes("Won")) {
|
||||
if (state.text.includes("Jackpot")) {
|
||||
slotsResult.classList.add("text-warning");
|
||||
} else {
|
||||
slotsResult.classList.add("text-success");
|
||||
}
|
||||
} else if (state.text.includes("Lost")) {
|
||||
slotsResult.classList.add("text-danger");
|
||||
}
|
||||
|
||||
updatePlayerCoins(gambler);
|
||||
} else {
|
||||
slotsResult.style.visibility = "visible";
|
||||
slotsResult.innerText = response.error;
|
||||
slotsResult.classList.add("text-danger");
|
||||
|
||||
console.error(response.error);
|
||||
}
|
||||
|
||||
document.getElementById("casinoSlotsBet").disabled = false;
|
||||
document.getElementById("casinoSlotsPull").disabled = false;
|
||||
}
|
||||
|
||||
// Blackjack
|
||||
// When the casino loads, look up the "blackjack status" of a player to either start a new game or continue an existing game.
|
||||
if (
|
||||
document.readyState === "complete" ||
|
||||
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
||||
) {
|
||||
checkBlackjackStatus();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", checkBlackjackStatus);
|
||||
}
|
||||
|
||||
function checkBlackjackStatus() {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("get", "/casino/blackjack");
|
||||
xhr.onload = handleBlackjackStatusResponse.bind(null, xhr);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function handleBlackjackStatusResponse(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) {
|
||||
if (response.active) {
|
||||
updateBlackjack(response.game_state);
|
||||
}
|
||||
} else {
|
||||
console.error("error");
|
||||
}
|
||||
}
|
||||
|
||||
// When starting a new game or taking an action in an existing one, a new state will be returned, and the DOM must be updated.
|
||||
function updateBlackjack(state) {
|
||||
const { player, dealer, status } = state;
|
||||
const lettersToSuits = {
|
||||
S: "♠️",
|
||||
H: "♥️",
|
||||
C: "♣️",
|
||||
D: "♦️",
|
||||
"?": "?",
|
||||
};
|
||||
const suitsToColors = {
|
||||
"♠️": "black",
|
||||
"♥️": "red",
|
||||
"♣️": "black",
|
||||
"♦️": "red",
|
||||
"?": "black",
|
||||
};
|
||||
|
||||
// Clear everything.
|
||||
Array.from(document.querySelectorAll(".playing-card")).forEach((card) => {
|
||||
card.innerText = "";
|
||||
card.style.color = "unset";
|
||||
card.classList.remove("dealt");
|
||||
});
|
||||
|
||||
// Show dealer cards.
|
||||
const dealerSlots = Array.from(
|
||||
document.querySelectorAll('.playing-card[data-who="dealer"]')
|
||||
);
|
||||
for (let i = 0; i < dealer.length; i++) {
|
||||
const slot = dealerSlots[i];
|
||||
|
||||
if (slot) {
|
||||
// Technically, the dealer can use more than 5 cards, though it's rare.
|
||||
// In that case, the result message is good enough.
|
||||
// Thanks, Carp. 🐠
|
||||
slot.classList.add("dealt");
|
||||
|
||||
if (i > 0 && status === "active") {
|
||||
break;
|
||||
}
|
||||
|
||||
const rank = dealer[i][0];
|
||||
const suit = lettersToSuits[dealer[i][1]];
|
||||
const card = rank + suit;
|
||||
slot.innerText = card;
|
||||
slot.style.color = suitsToColors[suit];
|
||||
}
|
||||
}
|
||||
|
||||
// Show player cards.
|
||||
const playerSlots = Array.from(
|
||||
document.querySelectorAll('.playing-card[data-who="player"]')
|
||||
);
|
||||
for (let i = 0; i < player.length; i++) {
|
||||
const slot = playerSlots[i];
|
||||
const rank = player[i][0];
|
||||
const suit = lettersToSuits[player[i][1]];
|
||||
const card = rank + suit;
|
||||
slot.innerText = card;
|
||||
slot.style.color = suitsToColors[suit];
|
||||
slot.classList.add("dealt");
|
||||
}
|
||||
|
||||
updateBlackjackActions(state);
|
||||
|
||||
if (status !== "active") {
|
||||
revealBlackjackResult(state);
|
||||
}
|
||||
}
|
||||
|
||||
function revealBlackjackResult(state) {
|
||||
const blackjackResult = document.getElementById("casinoBlackjackResult");
|
||||
const lookup = {
|
||||
bust: ["Bust. Didn't work out for you, did it?", "danger"],
|
||||
push: ["Pushed. This whole hand never happened.", "secondary"],
|
||||
insured_loss: ["Lost, but at least you had insurance.", "secondary"],
|
||||
lost: ["Lost. That was pathetic.", "danger"],
|
||||
won: ["Won. This time.", "success"],
|
||||
blackjack: ["Blackjack! Must be your lucky day.", "warning"],
|
||||
};
|
||||
const [resultText, resultClass] = lookup[state.status];
|
||||
|
||||
blackjackResult.style.visibility = "visible";
|
||||
blackjackResult.innerText = resultText;
|
||||
blackjackResult.classList.add(`text-${resultClass}`);
|
||||
}
|
||||
|
||||
function buildBlackjackAction(id, method, title, fullWidth = false) {
|
||||
return `
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-${
|
||||
fullWidth ? "primary" : "secondary"
|
||||
} lottery-page--action"
|
||||
id="${id}"
|
||||
onclick="${method}()"
|
||||
style="${fullWidth ? "width: 100%;" : ""}"
|
||||
>
|
||||
${title}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
function clearBlackjackActions() {
|
||||
const actionWrapper = document.getElementById("casinoBlackjackActions");
|
||||
actionWrapper.innerHTML = "";
|
||||
}
|
||||
|
||||
function updateBlackjackActions(state) {
|
||||
const actionWrapper = document.getElementById("casinoBlackjackActions");
|
||||
|
||||
clearBlackjackActions();
|
||||
|
||||
if (state.status === "active") {
|
||||
document.getElementById("casinoBlackjackWager").style.display = "none";
|
||||
|
||||
const actionLookup = {
|
||||
hit: buildBlackjackAction("casinoBlackjackHit", "hitBlackjack", "Hit"),
|
||||
stay: buildBlackjackAction(
|
||||
"casinoBlackjackStay",
|
||||
"stayBlackjack",
|
||||
"Stay"
|
||||
),
|
||||
double_down: buildBlackjackAction(
|
||||
"casinoBlackjackDouble",
|
||||
"doubleBlackjack",
|
||||
"Double Down"
|
||||
),
|
||||
insure: buildBlackjackAction(
|
||||
"casinoBlackjackInsure",
|
||||
"insureBlackjack",
|
||||
"Insure"
|
||||
),
|
||||
};
|
||||
const actions = state.actions.map((action) => actionLookup[action]);
|
||||
|
||||
actionWrapper.innerHTML = actions.join("\n");
|
||||
} else {
|
||||
// Game is over, deal a new game.
|
||||
document.getElementById("casinoBlackjackWager").style.display = "flex";
|
||||
|
||||
const deal = buildBlackjackAction(
|
||||
"casinoBlackjackDeal",
|
||||
"dealBlackjack",
|
||||
"Deal",
|
||||
true
|
||||
);
|
||||
|
||||
actionWrapper.innerHTML = deal;
|
||||
}
|
||||
}
|
||||
|
||||
function dealBlackjack() {
|
||||
const wager = document.getElementById("casinoBlackjackBet").value;
|
||||
const currency = document.querySelector(
|
||||
'input[name="casinoBlackjackCurrency"]:checked'
|
||||
).value;
|
||||
|
||||
document.getElementById("casinoBlackjackBet").disabled = true;
|
||||
document.getElementById("casinoBlackjackDeal").disabled = true;
|
||||
document.getElementById("casinoBlackjackWager").style.display = "none";
|
||||
document.getElementById("casinoBlackjackResult").style.visibility = "hidden";
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/casino/blackjack");
|
||||
xhr.onload = handleBlackjackResponse.bind(null, xhr);
|
||||
|
||||
const form = new FormData();
|
||||
form.append("formkey", formkey());
|
||||
form.append("wager", wager);
|
||||
form.append("currency", currency);
|
||||
|
||||
xhr.send(form);
|
||||
}
|
||||
|
||||
function takeBlackjackAction(action) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/casino/blackjack/action");
|
||||
xhr.onload = handleBlackjackResponse.bind(null, xhr);
|
||||
|
||||
const form = new FormData();
|
||||
form.append("formkey", formkey());
|
||||
form.append("action", action);
|
||||
|
||||
xhr.send(form);
|
||||
}
|
||||
|
||||
const hitBlackjack = takeBlackjackAction.bind(null, "hit");
|
||||
const stayBlackjack = takeBlackjackAction.bind(null, "stay");
|
||||
const doubleBlackjack = takeBlackjackAction.bind(null, "double_down");
|
||||
const insureBlackjack = takeBlackjackAction.bind(null, "insure");
|
||||
|
||||
function handleBlackjackResponse(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;
|
||||
const blackjackResult = document.getElementById("casinoBlackjackResult");
|
||||
blackjackResult.classList.remove("text-success", "text-danger");
|
||||
|
||||
if (succeeded) {
|
||||
if (response.game_state) {
|
||||
updateBlackjack(response.game_state);
|
||||
}
|
||||
|
||||
if (response.gambler) {
|
||||
updatePlayerCoins(response.gambler);
|
||||
}
|
||||
} else {
|
||||
blackjackResult.style.visibility = "visible";
|
||||
blackjackResult.innerText = response.error;
|
||||
blackjackResult.classList.add("text-danger");
|
||||
|
||||
console.error(response.error);
|
||||
}
|
||||
}
|
|
@ -23,4 +23,5 @@ from .views import *
|
|||
from .notifications import *
|
||||
from .follows import *
|
||||
from .lottery import *
|
||||
from .hats import *
|
||||
from .casino_game import *
|
||||
from .hats import *
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
from sqlalchemy import *
|
||||
from files.__main__ import Base
|
||||
from files.helpers.lazy import lazy
|
||||
from files.helpers.const import *
|
||||
import time
|
||||
|
||||
|
||||
class Casino_Game(Base):
|
||||
__tablename__ = "casino_games"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
created_utc = Column(Integer)
|
||||
active = Column(Boolean, default=True)
|
||||
currency = Column(String)
|
||||
wager = Column(Integer)
|
||||
winnings = Column(Integer)
|
||||
kind = Column(String)
|
||||
game_state = Column(JSON)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs:
|
||||
kwargs["created_utc"] = int(time.time())
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<CasinoGame(id={self.id})>"
|
|
@ -60,8 +60,6 @@ class Comment(Base):
|
|||
body = Column(String)
|
||||
body_html = Column(String)
|
||||
ban_reason = Column(String)
|
||||
slots_result = Column(String)
|
||||
blackjack_result = Column(String)
|
||||
wordle_result = Column(String)
|
||||
treasure_amount = Column(String)
|
||||
|
||||
|
@ -412,7 +410,7 @@ class Comment(Base):
|
|||
|
||||
if self.is_banned: return True
|
||||
|
||||
if (self.slots_result or self.blackjack_result or self.wordle_result) and (not self.body or len(self.body_html) <= 100) and 9 > self.level > 1: return True
|
||||
if (self.wordle_result) and (not self.body or len(self.body_html) <= 100) and 9 > self.level > 1: return True
|
||||
|
||||
if v and v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True
|
||||
|
||||
|
@ -448,73 +446,5 @@ class Comment(Base):
|
|||
elif wordle_status == 'lost':
|
||||
body += f"<strong class='ml-2'>Lost. The answer was: {wordle_answer}</strong>"
|
||||
|
||||
body += '</span>'
|
||||
return body
|
||||
|
||||
@lazy
|
||||
def blackjack_html(self, v):
|
||||
if not self.blackjack_result: return ''
|
||||
|
||||
split_result = self.blackjack_result.split('_')
|
||||
blackjack_status = split_result[3]
|
||||
player_hand = split_result[0].replace('X', '10')
|
||||
dealer_hand = split_result[1].split('/')[0] if blackjack_status == 'active' else split_result[1]
|
||||
dealer_hand = dealer_hand.replace('X', '10')
|
||||
wager = int(split_result[4])
|
||||
try: kind = split_result[5]
|
||||
except: kind = "coins"
|
||||
currency_kind = "Coins" if kind == "coins" else "Marseybux"
|
||||
|
||||
try: is_insured = split_result[6]
|
||||
except: is_insured = "0"
|
||||
|
||||
body = f"<span id='blackjack-{self.id}' class='ml-2'><em>{player_hand} vs. {dealer_hand}</em>"
|
||||
|
||||
if blackjack_status == 'active' and v and v.id == self.author_id:
|
||||
body += f'''
|
||||
<button
|
||||
class="action-{self.id} btn btn-success small"
|
||||
style="text-transform: uppercase; padding: 2px"
|
||||
onclick="handle_action('blackjack','{self.id}','hit')">
|
||||
Hit
|
||||
</button>
|
||||
<button
|
||||
class="action-{self.id} btn btn-danger small"
|
||||
style="text-transform: uppercase; padding: 2px"
|
||||
onclick="handle_action('blackjack','{self.id}','stay')">
|
||||
Stay
|
||||
</button>
|
||||
<button
|
||||
class="action-{self.id} btn btn-secondary small"
|
||||
style="text-transform: uppercase; padding: 2px"
|
||||
onclick="handle_action('blackjack','{self.id}','doubledown')">
|
||||
Double Down
|
||||
</button>
|
||||
'''
|
||||
|
||||
if dealer_hand[0][0] == 'A' and not is_insured == "1":
|
||||
body += f'''
|
||||
<button
|
||||
class="action-{self.id} btn btn-secondary small"
|
||||
style="text-transform: uppercase; padding: 2px"
|
||||
onclick="handle_action('blackjack','{self.id}','insurance')">
|
||||
Insure
|
||||
</button>
|
||||
'''
|
||||
|
||||
elif blackjack_status == 'push':
|
||||
body += f"<strong class='ml-2'>Pushed. Refunded {wager} {currency_kind}.</strong>"
|
||||
elif blackjack_status == 'bust':
|
||||
body += f"<strong class='ml-2'>Bust. Lost {wager} {currency_kind}.</strong>"
|
||||
elif blackjack_status == 'lost':
|
||||
body += f"<strong class='ml-2'>Lost {wager} {currency_kind}.</strong>"
|
||||
elif blackjack_status == 'won':
|
||||
body += f"<strong class='ml-2'>Won {wager} {currency_kind}.</strong>"
|
||||
elif blackjack_status == 'blackjack':
|
||||
body += f"<strong class='ml-2'>Blackjack! Won {floor(wager * 3/2)} {currency_kind}.</strong>"
|
||||
|
||||
if is_insured == "1":
|
||||
body += f" <em class='text-success'>Insured.</em>"
|
||||
|
||||
body += '</span>'
|
||||
return body
|
|
@ -167,9 +167,6 @@ def execute_snappy(post, v):
|
|||
snappy.comment_count += 1
|
||||
snappy.coins += 1
|
||||
g.db.add(snappy)
|
||||
|
||||
if body.startswith('!slots'):
|
||||
check_for_slots_command(body, snappy, c)
|
||||
|
||||
if FEATURES['PINS'] and (body.startswith(':#marseypin:') or body.startswith(':#marseypin2:')):
|
||||
post.stickied = "Snappy"
|
||||
|
|
|
@ -1,188 +1,297 @@
|
|||
import json
|
||||
from json.encoder import INFINITY
|
||||
import random
|
||||
from math import floor
|
||||
from files.helpers.const import *
|
||||
from files.classes.casino_game import Casino_Game
|
||||
from flask import g
|
||||
|
||||
deck_count = 4
|
||||
ranks = ("2", "3", "4", "5", "6", "7", "8", "9", "X", "J", "Q", "K", "A")
|
||||
suits = ("♠️", "♥️", "♣️", "♦️")
|
||||
coins_command_word = "!blackjack"
|
||||
marseybux_command_word = "!blackjackmb"
|
||||
suits = ("S", "H", "C", "D")
|
||||
minimum_bet = 100
|
||||
maximum_bet = INFINITY
|
||||
|
||||
|
||||
def build_game(gambler, currency_kind, wager):
|
||||
casino_game = Casino_Game()
|
||||
casino_game.user_id = gambler.id
|
||||
casino_game.currency = currency_kind
|
||||
casino_game.wager = wager
|
||||
casino_game.winnings = 0
|
||||
casino_game.kind = 'blackjack'
|
||||
casino_game.game_state = json.dumps(build_initial_state())
|
||||
g.db.add(casino_game)
|
||||
g.db.flush()
|
||||
|
||||
|
||||
def build_initial_state():
|
||||
player, dealer, deck = deal_initial_cards()
|
||||
state = {
|
||||
"player": player,
|
||||
"dealer": dealer,
|
||||
"deck": deck,
|
||||
"actions": [],
|
||||
"insurance": False,
|
||||
"doubled_down": False,
|
||||
"status": "active"
|
||||
}
|
||||
|
||||
state['actions'] = determine_actions(state)
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def save_game_state(game, new_state):
|
||||
game.game_state = json.dumps(new_state)
|
||||
g.db.add(game)
|
||||
|
||||
|
||||
def get_active_game(gambler):
|
||||
game = g.db.query(Casino_Game) \
|
||||
.filter(Casino_Game.active == True and
|
||||
Casino_Game.kind == 'blackjack' and
|
||||
Casino_Game.user_id == gambler.id).first()
|
||||
|
||||
if game:
|
||||
return game, json.loads(game.game_state)
|
||||
else:
|
||||
return None, None
|
||||
|
||||
|
||||
def get_safe_game_state(gambler):
|
||||
game, game_state = get_active_game(gambler)
|
||||
|
||||
if game:
|
||||
return {
|
||||
"player": game_state['player'],
|
||||
"dealer": [game_state['dealer'][0], "?"],
|
||||
"actions": game_state['actions'],
|
||||
"insurance": game_state['insurance'],
|
||||
"doubled_down": game_state['doubled_down'],
|
||||
"status": game_state['status']
|
||||
}
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def apply_blackjack_result(gambler):
|
||||
game, game_state = get_active_game(gambler)
|
||||
|
||||
if game and game.active:
|
||||
result = game_state['status']
|
||||
|
||||
if result == 'push' or result == 'insured_loss':
|
||||
reward = 0
|
||||
elif result == 'won':
|
||||
reward = game.wager
|
||||
elif result == 'blackjack':
|
||||
reward = floor(game.wager * 3/2)
|
||||
else:
|
||||
reward = -game.wager
|
||||
|
||||
gambler.winnings += reward
|
||||
|
||||
if (reward > -1):
|
||||
currency_value = int(getattr(gambler, game.currency, 0))
|
||||
setattr(gambler, game.currency,
|
||||
currency_value + game.wager + reward)
|
||||
|
||||
game.active = False
|
||||
game.winnings = reward
|
||||
g.db.add(game)
|
||||
|
||||
|
||||
def deal_blackjack_game(gambler, wager_value, currency):
|
||||
over_min = wager_value >= minimum_bet
|
||||
under_max = wager_value <= maximum_bet
|
||||
using_dramacoin = currency == "dramacoin"
|
||||
using_marseybux = not using_dramacoin
|
||||
has_proper_funds = (using_dramacoin and gambler.coins >= wager_value) or (
|
||||
using_marseybux and gambler.procoins >= wager_value)
|
||||
currency_prop = "coins" if using_dramacoin else "procoins"
|
||||
currency_value = getattr(gambler, currency_prop, 0)
|
||||
|
||||
if (over_min and under_max and has_proper_funds):
|
||||
# Charge the gambler for the game, reduce their winnings, and start the game.
|
||||
setattr(gambler, currency_prop, currency_value - wager_value)
|
||||
gambler.winnings -= wager_value
|
||||
|
||||
build_game(gambler, currency_prop, wager_value)
|
||||
|
||||
game, game_state = get_active_game(gambler)
|
||||
player_value = get_hand_value(game_state['player'])
|
||||
dealer_value = get_hand_value(game_state['dealer'])
|
||||
|
||||
if player_value == 21 and dealer_value == 21:
|
||||
game_state["status"] = 'push'
|
||||
save_game_state(game, game_state)
|
||||
apply_blackjack_result(gambler)
|
||||
elif player_value == 21:
|
||||
game_state["status"] = 'blackjack'
|
||||
save_game_state(game, game_state)
|
||||
apply_blackjack_result(gambler)
|
||||
|
||||
g.db.flush()
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# region Actions
|
||||
|
||||
|
||||
def gambler_hit(gambler):
|
||||
game, game_state = get_active_game(gambler.id)
|
||||
|
||||
if game:
|
||||
player = game_state['player']
|
||||
deck = game_state['deck']
|
||||
doubled_down = game_state['doubled_down']
|
||||
player.append(deck.pop(0))
|
||||
player_value = get_hand_value(player)
|
||||
went_bust = player_value == -1
|
||||
five_card_charlied = len(player) >= 5
|
||||
|
||||
if went_bust:
|
||||
game_state['status'] = 'bust'
|
||||
save_game_state(game, game_state)
|
||||
apply_blackjack_result(gambler)
|
||||
elif five_card_charlied:
|
||||
game_state['status'] = 'won'
|
||||
save_game_state(game, game_state)
|
||||
apply_blackjack_result(gambler)
|
||||
else:
|
||||
save_game_state(game, game_state)
|
||||
|
||||
if doubled_down or player_value == 21:
|
||||
forced_stay_success, forced_stay_state = gambler_stayed(gambler)
|
||||
return forced_stay_success, forced_stay_state
|
||||
else:
|
||||
return True, game_state
|
||||
else:
|
||||
return False, game_state
|
||||
|
||||
|
||||
def gambler_stayed(gambler):
|
||||
game, game_state = get_active_game(gambler.id)
|
||||
|
||||
if game:
|
||||
player = game_state['player']
|
||||
dealer = game_state['dealer']
|
||||
deck = game_state['deck']
|
||||
insured = game_state['insurance']
|
||||
|
||||
player_value = get_hand_value(player)
|
||||
dealer_value = get_hand_value(dealer)
|
||||
|
||||
if dealer_value == 21 and insured:
|
||||
game_state["status"] = 'insured_loss'
|
||||
save_game_state(game, game_state)
|
||||
apply_blackjack_result(gambler)
|
||||
else:
|
||||
while dealer_value < 17 and dealer_value != -1:
|
||||
next = deck.pop(0)
|
||||
dealer.append(next)
|
||||
dealer_value = get_hand_value(dealer)
|
||||
|
||||
if player_value > dealer_value or dealer_value == -1:
|
||||
game_state["status"] = 'won'
|
||||
elif dealer_value > player_value:
|
||||
game_state["status"] = 'lost'
|
||||
else:
|
||||
game_state["status"] = 'push'
|
||||
|
||||
save_game_state(game, game_state)
|
||||
apply_blackjack_result(gambler)
|
||||
|
||||
return True, game_state
|
||||
else:
|
||||
return False, game_state
|
||||
|
||||
|
||||
def gambler_doubled_down(gambler):
|
||||
game, game_state = get_active_game(gambler.id)
|
||||
|
||||
if game and not game_state['doubled_down']:
|
||||
currency_value = getattr(gambler, game.currency, 0)
|
||||
|
||||
if (currency_value < game.wager):
|
||||
return False
|
||||
|
||||
setattr(gambler, game.currency, currency_value - game.wager)
|
||||
game.wager *= 2
|
||||
game_state['doubled_down'] = True
|
||||
save_game_state(game, game_state)
|
||||
|
||||
g.db.flush()
|
||||
|
||||
last_hit_success, last_hit_state = gambler_hit(gambler)
|
||||
|
||||
return last_hit_success, last_hit_state
|
||||
else:
|
||||
return False, game_state
|
||||
|
||||
|
||||
def gambler_purchased_insurance(gambler):
|
||||
game, game_state = get_active_game(gambler.id)
|
||||
|
||||
if game and not game_state['insurance']:
|
||||
insurance_cost = game.wager / 2
|
||||
currency_value = getattr(gambler, game.currency, 0)
|
||||
|
||||
if (currency_value < insurance_cost):
|
||||
return False, game_state
|
||||
|
||||
setattr(gambler, game.currency, currency_value - insurance_cost)
|
||||
game_state['insurance'] = True
|
||||
game_state['actions'] = determine_actions(game_state)
|
||||
save_game_state(game, game_state)
|
||||
|
||||
return True, game_state
|
||||
else:
|
||||
return False, game_state
|
||||
|
||||
# endregion
|
||||
|
||||
# region Utilities
|
||||
|
||||
|
||||
def shuffle(x):
|
||||
random.shuffle(x)
|
||||
return x
|
||||
random.shuffle(x)
|
||||
return x
|
||||
|
||||
|
||||
def determine_actions(state):
|
||||
actions = ['hit', 'stay', 'double_down']
|
||||
|
||||
if (state['dealer'][0][0] == "A" and not state['insurance']):
|
||||
actions.append('insure')
|
||||
|
||||
return actions
|
||||
|
||||
|
||||
def deal_initial_cards():
|
||||
deck = shuffle([rank + suit for rank in ranks for suit in suits for _ in range(deck_count)])
|
||||
p1, d1, p2, d2, *rest_of_deck = deck
|
||||
return [p1, p2], [d1, d2], rest_of_deck
|
||||
deck = shuffle(
|
||||
[rank + suit for rank in ranks for suit in suits for _ in range(deck_count)])
|
||||
p1, d1, p2, d2, *rest_of_deck = deck
|
||||
return [p1, p2], [d1, d2], rest_of_deck
|
||||
|
||||
|
||||
def get_card_value(card):
|
||||
rank = card[0]
|
||||
return 0 if rank == "A" else min(ranks.index(rank) + 2, 10)
|
||||
rank = card[0]
|
||||
return 0 if rank == "A" else min(ranks.index(rank) + 2, 10)
|
||||
|
||||
|
||||
def get_hand_value(hand):
|
||||
without_aces = sum(map(get_card_value, hand))
|
||||
ace_count = sum("A" in c for c in hand)
|
||||
possibilities = []
|
||||
without_aces = sum(map(get_card_value, hand))
|
||||
ace_count = sum("A" in c for c in hand)
|
||||
possibilities = []
|
||||
|
||||
for i in range(ace_count + 1):
|
||||
value = without_aces + (ace_count - i) + i * 11
|
||||
possibilities.append(-1 if value > 21 else value)
|
||||
for i in range(ace_count + 1):
|
||||
value = without_aces + (ace_count - i) + i * 11
|
||||
possibilities.append(-1 if value > 21 else value)
|
||||
|
||||
return max(possibilities)
|
||||
return max(possibilities)
|
||||
|
||||
|
||||
def format_cards(hand):
|
||||
return map(lambda x: "".join(x), hand)
|
||||
|
||||
|
||||
def format_all(player_hand, dealer_hand, deck, status, wager, kind, is_insured=0):
|
||||
formatted_player_hand = format_cards(player_hand)
|
||||
formatted_dealer_hand = format_cards(dealer_hand)
|
||||
formatted_deck = format_cards(deck)
|
||||
|
||||
return f'{"/".join(formatted_player_hand)}_{"/".join(formatted_dealer_hand)}_{"/".join(formatted_deck)}_{status}_{wager}_{kind}_{str(is_insured)}'
|
||||
|
||||
|
||||
def check_for_blackjack_commands(in_text, from_user, from_comment):
|
||||
if not FEATURES['GAMBLING']: return
|
||||
|
||||
for command_word in (coins_command_word, marseybux_command_word):
|
||||
currency_prop = "coins" if command_word == coins_command_word else "procoins"
|
||||
currency_value = getattr(from_user, currency_prop, 0)
|
||||
|
||||
if command_word in in_text:
|
||||
for word in in_text.split():
|
||||
if command_word in word:
|
||||
try:
|
||||
wager = word[len(command_word):]
|
||||
wager_value = int(wager)
|
||||
except: break
|
||||
|
||||
if (wager_value < minimum_bet): break
|
||||
elif (wager_value > maximum_bet): break
|
||||
elif (wager_value <= currency_value):
|
||||
setattr(from_user, currency_prop, currency_value - wager_value)
|
||||
|
||||
player_hand, dealer_hand, rest_of_deck = deal_initial_cards()
|
||||
status = 'active'
|
||||
player_value = get_hand_value(player_hand)
|
||||
dealer_value = get_hand_value(dealer_hand)
|
||||
|
||||
if player_value == 21 and dealer_value == 21:
|
||||
status = 'push'
|
||||
apply_game_result(from_comment, wager, status, currency_prop)
|
||||
elif player_value == 21:
|
||||
status = 'blackjack'
|
||||
apply_game_result(from_comment, wager, status, currency_prop)
|
||||
|
||||
from_comment.blackjack_result = format_all(player_hand, dealer_hand, rest_of_deck, status, wager, currency_prop, 0)
|
||||
|
||||
def player_hit(from_comment, did_double_down=False):
|
||||
player_hand, dealer_hand, deck, status, wager, kind, is_insured = from_comment.blackjack_result.split("_")
|
||||
player_hand = player_hand.split("/")
|
||||
dealer_hand = dealer_hand.split("/")
|
||||
deck = deck.split("/")
|
||||
player_hand.append(deck.pop(0))
|
||||
player_value = get_hand_value(player_hand)
|
||||
|
||||
if player_value == -1:
|
||||
status = 'bust'
|
||||
apply_game_result(from_comment, wager, status, kind)
|
||||
elif len(player_hand) >= 5:
|
||||
status = 'won'
|
||||
apply_game_result(from_comment, wager, status, kind)
|
||||
|
||||
from_comment.blackjack_result = format_all(player_hand, dealer_hand, deck, status, wager, kind, int(is_insured))
|
||||
|
||||
if (did_double_down or player_value == 21) and status == 'active':
|
||||
player_stayed(from_comment)
|
||||
|
||||
def player_stayed(from_comment):
|
||||
player_hand, dealer_hand, deck, status, wager, kind, is_insured = from_comment.blackjack_result.split("_")
|
||||
player_hand = player_hand.split("/")
|
||||
player_value = get_hand_value(player_hand)
|
||||
dealer_hand = dealer_hand.split("/")
|
||||
dealer_value = get_hand_value(dealer_hand)
|
||||
deck = deck.split("/")
|
||||
|
||||
if dealer_value == 21 and is_insured == "1":
|
||||
currency_value = getattr(from_comment.author, kind, 0)
|
||||
setattr(from_comment.author, kind, currency_value + int(wager))
|
||||
else:
|
||||
while dealer_value < 17 and dealer_value != -1:
|
||||
next = deck.pop(0)
|
||||
dealer_hand.append(next)
|
||||
dealer_value = get_hand_value(dealer_hand)
|
||||
|
||||
if player_value > dealer_value or dealer_value == -1: status = 'won'
|
||||
elif dealer_value > player_value: status = 'lost'
|
||||
else: status = 'push'
|
||||
|
||||
from_comment.blackjack_result = format_all(player_hand, dealer_hand, deck, status, wager, kind, int(is_insured))
|
||||
|
||||
apply_game_result(from_comment, wager, status, kind)
|
||||
|
||||
def player_doubled_down(from_comment):
|
||||
# When doubling down, the player receives one additional card (a "hit") and their initial bet is doubled.
|
||||
player_hand, dealer_hand, deck, status, wager, kind, is_insured = from_comment.blackjack_result.split("_")
|
||||
wager_value = int(wager)
|
||||
currency_value = getattr(from_comment.author, kind, 0)
|
||||
|
||||
# Gotsta have enough coins
|
||||
if (currency_value < wager_value): return
|
||||
|
||||
# Double the initial wager
|
||||
setattr(from_comment.author, kind, currency_value - wager_value)
|
||||
wager_value *= 2
|
||||
|
||||
# Apply the changes to the stored hand.
|
||||
player_hand = player_hand.split("/")
|
||||
dealer_hand = dealer_hand.split("/")
|
||||
deck = deck.split("/")
|
||||
from_comment.blackjack_result = format_all(player_hand, dealer_hand, deck, status, str(wager_value), kind, int(is_insured))
|
||||
|
||||
player_hit(from_comment, True)
|
||||
|
||||
def player_bought_insurance(from_comment):
|
||||
# When buying insurance, the player pays a side bet equal to 1/2 the original bet.
|
||||
# In the event the dealer actually had a blackjack, they receive a 2:1 payout limiting the negative effect.
|
||||
player_hand, dealer_hand, deck, status, wager, kind, is_insured = from_comment.blackjack_result.split("_")
|
||||
wager_value = int(wager)
|
||||
insurance_cost = wager_value / 2
|
||||
currency_value = getattr(from_comment.author, kind, 0)
|
||||
|
||||
# Gotsta have enough coins
|
||||
if (currency_value < insurance_cost): return
|
||||
|
||||
# Charge for (and grant) insurance
|
||||
setattr(from_comment.author, kind, currency_value - insurance_cost)
|
||||
is_insured = 1
|
||||
|
||||
# Apply the changes to the stored hand.
|
||||
player_hand = player_hand.split("/")
|
||||
dealer_hand = dealer_hand.split("/")
|
||||
deck = deck.split("/")
|
||||
from_comment.blackjack_result = format_all(player_hand, dealer_hand, deck, status, str(wager_value), kind, int(is_insured))
|
||||
|
||||
def apply_game_result(from_comment, wager, result, kind):
|
||||
wager_value = int(wager)
|
||||
user = from_comment.author
|
||||
|
||||
if result == 'push': reward = 0
|
||||
elif result == 'won': reward = wager_value
|
||||
elif result == 'blackjack': reward = floor(wager_value * 3/2)
|
||||
else: reward = -wager_value
|
||||
|
||||
user.winnings += reward
|
||||
|
||||
if (reward > -1):
|
||||
currency_value = int(getattr(user, kind, 0))
|
||||
setattr(user, kind, currency_value + wager_value + reward)
|
||||
# endregion
|
||||
|
|
|
@ -206,7 +206,7 @@ POLL_THREAD = 0
|
|||
WELCOME_MSG = f"Welcome to {SITE_NAME}!"
|
||||
ROLES={}
|
||||
|
||||
LOTTERY_ENABLED = True
|
||||
CASINO_ENABLED = True
|
||||
LOTTERY_TICKET_COST = 12
|
||||
LOTTERY_SINK_RATE = 3
|
||||
LOTTERY_DURATION = 60 * 60 * 24 * 7
|
||||
|
|
|
@ -55,7 +55,7 @@ def inject_constants():
|
|||
"PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR,
|
||||
"COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES,
|
||||
"HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED,
|
||||
"LOTTERY_ENABLED":LOTTERY_ENABLED, "GUMROAD_LINK":GUMROAD_LINK,
|
||||
"CASINO_ENABLED":CASINO_ENABLED, "GUMROAD_LINK":GUMROAD_LINK,
|
||||
"DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION,
|
||||
"has_sidebar":has_sidebar, "has_logo":has_logo, "has_app":has_app,
|
||||
"FP":FP, "NOTIF_MODACTION_JL_MIN":NOTIF_MODACTION_JL_MIN, "cache":cache, "ONLINE_STR":ONLINE_STR, "patron":patron, "approved_embed_hosts":approved_embed_hosts, "dues":dues}
|
||||
|
|
|
@ -1,119 +1,124 @@
|
|||
import json
|
||||
from json.encoder import INFINITY
|
||||
import random
|
||||
from .const import *
|
||||
from files.classes.casino_game import Casino_Game
|
||||
from flask import g
|
||||
|
||||
command_word = "!slots"
|
||||
casino_word = "!slotsmb"
|
||||
if SITE_NAME == 'rDrama': minimum_bet = 100
|
||||
else: minimum_bet = 10
|
||||
if SITE_NAME == 'rDrama':
|
||||
minimum_bet = 100
|
||||
else:
|
||||
minimum_bet = 10
|
||||
maximum_bet = INFINITY
|
||||
payout_to_symbols = {
|
||||
2: ["👣", "🍀", "🌈", "⭐️"],
|
||||
3: ["🍎", "🔞", "⚛️", "☢️"],
|
||||
5: ["✡️", "⚔️", "🍆", "🍒"],
|
||||
12: ["🐱"]
|
||||
2: ["👣", "🍀", "🌈", "⭐️"],
|
||||
3: ["🍎", "🔞", "⚛️", "☢️"],
|
||||
5: ["✡️", "⚔️", "🍆", "🍒"],
|
||||
12: ["🐱"]
|
||||
}
|
||||
|
||||
def shuffle(stuff):
|
||||
random.shuffle(stuff)
|
||||
return stuff
|
||||
|
||||
def check_for_slots_command(in_text, from_user, from_comment):
|
||||
if not FEATURES['GAMBLING']: return
|
||||
def casino_slot_pull(gambler, wager_value, currency):
|
||||
over_min = wager_value >= minimum_bet
|
||||
under_max = wager_value <= maximum_bet
|
||||
using_dramacoin = currency == "dramacoin"
|
||||
using_marseybux = not using_dramacoin
|
||||
has_proper_funds = (using_dramacoin and gambler.coins >= wager_value) or (
|
||||
using_marseybux and gambler.procoins >= wager_value)
|
||||
currency_prop = "coins" if using_dramacoin else "procoins"
|
||||
currency_value = getattr(gambler, currency_prop, 0)
|
||||
|
||||
in_text = in_text.lower()
|
||||
if command_word in in_text:
|
||||
for word in in_text.split():
|
||||
if command_word in word:
|
||||
try:
|
||||
wager = word[len(command_word):]
|
||||
wager_value = int(wager)
|
||||
except: break
|
||||
if (over_min and under_max and has_proper_funds):
|
||||
setattr(gambler, currency_prop, currency_value - wager_value)
|
||||
gambler.winnings -= wager_value
|
||||
|
||||
if (wager_value < minimum_bet): break
|
||||
elif (wager_value > maximum_bet): break
|
||||
elif (wager_value > from_user.coins): break
|
||||
payout = determine_payout()
|
||||
reward = wager_value * payout
|
||||
|
||||
from_user.coins -= wager_value
|
||||
from_user.winnings -= wager_value
|
||||
currency_value = getattr(gambler, currency_prop, 0)
|
||||
setattr(gambler, currency_prop, currency_value + reward)
|
||||
gambler.winnings += reward
|
||||
|
||||
payout = determine_payout()
|
||||
symbols = build_symbols(payout)
|
||||
text = build_text(wager_value, payout, from_user, "Coins")
|
||||
reward = wager_value * payout
|
||||
symbols = build_symbols(payout)
|
||||
text = build_text(wager_value, payout, currency)
|
||||
|
||||
from_user.coins += reward
|
||||
from_user.winnings += reward
|
||||
game_state = {
|
||||
"symbols": symbols,
|
||||
"text": text
|
||||
}
|
||||
casino_game = Casino_Game()
|
||||
casino_game.active = False
|
||||
casino_game.user_id = gambler.id
|
||||
casino_game.currency = currency_prop
|
||||
casino_game.wager = wager_value
|
||||
casino_game.winnings = reward - wager_value
|
||||
casino_game.kind = 'slots'
|
||||
casino_game.game_state = json.dumps(game_state)
|
||||
g.db.add(casino_game)
|
||||
|
||||
from_comment.slots_result = f'{symbols} {text}'
|
||||
return True, casino_game.game_state
|
||||
else:
|
||||
return False, "{}"
|
||||
|
||||
if casino_word in in_text:
|
||||
for word in in_text.split():
|
||||
if casino_word in word:
|
||||
try:
|
||||
wager = word[len(casino_word):]
|
||||
wager_value = int(wager)
|
||||
except: break
|
||||
|
||||
if (wager_value < minimum_bet): break
|
||||
elif (wager_value > maximum_bet): break
|
||||
elif (wager_value > from_user.procoins): break
|
||||
def build_symbols(for_payout):
|
||||
all_symbols = []
|
||||
|
||||
from_user.procoins -= wager_value
|
||||
from_user.winnings -= wager_value
|
||||
for payout in payout_to_symbols:
|
||||
for symbol in payout_to_symbols[payout]:
|
||||
all_symbols.append(symbol)
|
||||
|
||||
payout = determine_payout()
|
||||
symbols = build_symbols(payout)
|
||||
text = build_text(wager_value, payout, from_user, "Marseybux")
|
||||
reward = wager_value * payout
|
||||
shuffle(all_symbols)
|
||||
|
||||
from_user.procoins += reward
|
||||
from_user.winnings += reward
|
||||
if for_payout == 0:
|
||||
return "".join([all_symbols[0], ",", all_symbols[1], ",", all_symbols[2]])
|
||||
elif for_payout == 1:
|
||||
indices = shuffle([0, 1, 2])
|
||||
symbol_set = ["", "", ""]
|
||||
match_a = indices[0]
|
||||
match_b = indices[1]
|
||||
nonmatch = indices[2]
|
||||
matching_symbol = all_symbols[0]
|
||||
other_symbol = all_symbols[1]
|
||||
symbol_set[match_a] = matching_symbol
|
||||
symbol_set[match_b] = matching_symbol
|
||||
symbol_set[nonmatch] = other_symbol
|
||||
|
||||
from_comment.slots_result = f'{symbols} {text}'
|
||||
return "".join([symbol_set[0], ",", symbol_set[1], ",", symbol_set[2]])
|
||||
else:
|
||||
relevantSymbols = shuffle(payout_to_symbols[for_payout])
|
||||
symbol = relevantSymbols[0]
|
||||
|
||||
return "".join([symbol, ",", symbol, ",", symbol])
|
||||
|
||||
|
||||
def build_text(wager_value, result, currency):
|
||||
if result == 0:
|
||||
return f'Lost {wager_value} {currency}'
|
||||
elif result == 1:
|
||||
return 'Broke Even'
|
||||
elif result == 12:
|
||||
return f'Jackpot! Won {wager_value * (result-1)} {currency}'
|
||||
else:
|
||||
return f'Won {wager_value * (result-1)} {currency}'
|
||||
|
||||
|
||||
def determine_payout():
|
||||
value = random.randint(1, 100)
|
||||
if value == 100: return 12
|
||||
elif value >= 96: return 5
|
||||
elif value >= 88: return 3
|
||||
elif value >= 72: return 2
|
||||
elif value >= 61: return 1
|
||||
else: return 0
|
||||
value = random.randint(1, 100)
|
||||
if value == 100:
|
||||
return 12
|
||||
elif value >= 96:
|
||||
return 5
|
||||
elif value >= 88:
|
||||
return 3
|
||||
elif value >= 72:
|
||||
return 2
|
||||
elif value >= 61:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def build_symbols(for_payout):
|
||||
all_symbols = []
|
||||
|
||||
for payout in payout_to_symbols:
|
||||
for symbol in payout_to_symbols[payout]:
|
||||
all_symbols.append(symbol)
|
||||
|
||||
shuffle(all_symbols)
|
||||
|
||||
if for_payout == 0:
|
||||
return "".join([all_symbols[0], all_symbols[1], all_symbols[2]])
|
||||
elif for_payout == 1:
|
||||
indices = shuffle([0, 1, 2])
|
||||
symbol_set = ["", "", ""]
|
||||
match_a = indices[0]
|
||||
match_b = indices[1]
|
||||
nonmatch = indices[2]
|
||||
matching_symbol = all_symbols[0]
|
||||
other_symbol = all_symbols[1]
|
||||
symbol_set[match_a] = matching_symbol
|
||||
symbol_set[match_b] = matching_symbol
|
||||
symbol_set[nonmatch] = other_symbol
|
||||
|
||||
return "".join(symbol_set)
|
||||
else:
|
||||
relevantSymbols = shuffle(payout_to_symbols[for_payout])
|
||||
symbol = relevantSymbols[0]
|
||||
|
||||
return "".join([symbol, symbol, symbol])
|
||||
|
||||
def build_text(wager_value, result, user, currency):
|
||||
if result == 0: return f'Lost {wager_value} {currency}'
|
||||
elif result == 1: return 'Broke Even'
|
||||
elif result == 12: return f'Jackpot! Won {wager_value * (result-1)} {currency}'
|
||||
else: return f'Won {wager_value * (result-1)} {currency}'
|
||||
def shuffle(stuff):
|
||||
random.shuffle(stuff)
|
||||
return stuff
|
||||
|
|
|
@ -14,7 +14,7 @@ def check_for_treasure(in_text, from_comment):
|
|||
|
||||
if not FEATURES['GAMBLING']: return
|
||||
|
||||
if '!slots' not in in_text and '!blackjack' not in in_text and '!wordle' not in in_text:
|
||||
if '!wordle' not in in_text:
|
||||
seed = randint(1, 1000)
|
||||
is_special = seed == 1000
|
||||
is_standard = seed >= 990
|
||||
|
|
|
@ -166,11 +166,11 @@ def admin_level_required(x):
|
|||
|
||||
return wrapper_maker
|
||||
|
||||
def lottery_required(f):
|
||||
def casino_required(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
v = get_logged_in_user()
|
||||
|
||||
if not LOTTERY_ENABLED: abort(404)
|
||||
if not CASINO_ENABLED: abort(404)
|
||||
|
||||
return make_response(f(v=v))
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ from .awards import *
|
|||
from .giphy import *
|
||||
from .subs import *
|
||||
from .lottery import *
|
||||
from .casino import *
|
||||
from .polls import *
|
||||
from .notifications import *
|
||||
from .hats import *
|
||||
from .hats import *
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
import json
|
||||
from files.__main__ import app
|
||||
from files.helpers.wrappers import *
|
||||
from files.helpers.alerts import *
|
||||
from files.helpers.get import *
|
||||
from files.helpers.const import *
|
||||
from files.helpers.wrappers import *
|
||||
from files.helpers.blackjack import *
|
||||
from files.helpers.slots import *
|
||||
from files.helpers.lottery import *
|
||||
|
||||
|
||||
@app.get("/casino")
|
||||
@auth_required
|
||||
def casino(v):
|
||||
participants = get_users_participating_in_lottery()
|
||||
return render_template("casino.html", v=v, participants=participants)
|
||||
|
||||
|
||||
@app.post("/casino/slots")
|
||||
@auth_required
|
||||
def pull_slots(v):
|
||||
try:
|
||||
wager = int(request.values.get("wager"))
|
||||
except:
|
||||
return {"error": "Invalid wager."}
|
||||
|
||||
try:
|
||||
currency = request.values.get("currency")
|
||||
except:
|
||||
return {"error": "Invalid currency (expected 'dramacoin' or 'marseybux')."}
|
||||
|
||||
if (currency == "dramacoin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
|
||||
return {"error": f"Not enough {currency} to make that bet."}
|
||||
|
||||
success, game_state = casino_slot_pull(v, wager, currency)
|
||||
|
||||
if success:
|
||||
return {"game_state": game_state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
|
||||
else:
|
||||
return {"error": "Wager must be more than 100 {currency}."}
|
||||
|
||||
|
||||
@app.get("/casino/blackjack")
|
||||
@auth_required
|
||||
def get_player_blackjack_status(v):
|
||||
game, game_state = get_active_game(v)
|
||||
|
||||
if game and game.active:
|
||||
safe_state = get_safe_game_state(v)
|
||||
return {"active": True, "game_state": safe_state}
|
||||
else:
|
||||
return {"active": False, "game_state": game_state}
|
||||
|
||||
|
||||
@app.post("/casino/blackjack")
|
||||
@auth_required
|
||||
def deal_blackjack(v):
|
||||
try:
|
||||
wager = int(request.values.get("wager"))
|
||||
except:
|
||||
return {"error": "Invalid wager."}
|
||||
|
||||
try:
|
||||
currency = request.values.get("currency")
|
||||
except:
|
||||
return {"error": "Invalid currency (expected 'dramacoin' or 'marseybux')."}
|
||||
|
||||
if (currency == "dramacoin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
|
||||
return {"error": f"Not enough {currency} to make that bet."}
|
||||
|
||||
success = deal_blackjack_game(v, wager, currency)
|
||||
|
||||
if success:
|
||||
game, game_state = get_active_game(v)
|
||||
|
||||
if game and game.active:
|
||||
safe_state = get_safe_game_state(v)
|
||||
return {"game_state": safe_state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
|
||||
else:
|
||||
return {"game_state": game_state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
|
||||
|
||||
else:
|
||||
return {"error": "Wager must be more than 100 {currency}."}
|
||||
|
||||
|
||||
@app.post("/casino/blackjack/action")
|
||||
@auth_required
|
||||
def player_took_blackjack_action(v):
|
||||
try:
|
||||
action = request.values.get("action")
|
||||
except:
|
||||
return {"error": "Invalid action."}
|
||||
|
||||
was_successful = False
|
||||
state = None
|
||||
|
||||
if action == 'hit':
|
||||
success, game_state = gambler_hit(v)
|
||||
was_successful = success
|
||||
state = game_state
|
||||
elif action == 'stay':
|
||||
success, game_state = gambler_stayed(v)
|
||||
was_successful = success
|
||||
state = game_state
|
||||
elif action == 'double_down':
|
||||
success, game_state = gambler_doubled_down(v)
|
||||
was_successful = success
|
||||
state = game_state
|
||||
elif action == 'insure':
|
||||
success, game_state = gambler_purchased_insurance(v)
|
||||
was_successful = success
|
||||
state = game_state
|
||||
|
||||
if was_successful:
|
||||
return {"active": True, "game_state": state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
|
||||
else:
|
||||
return {"active": False, "game_state": None}
|
|
@ -338,7 +338,7 @@ def comment(v):
|
|||
body_html = sanitize(body_for_sanitize, limit_pings=5)
|
||||
|
||||
|
||||
if parent_post.id not in ADMIGGERS and '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower():
|
||||
if parent_post.id not in ADMIGGERS and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower():
|
||||
existing = g.db.query(Comment.id).filter(Comment.author_id == v.id,
|
||||
Comment.deleted_utc == 0,
|
||||
Comment.parent_comment_id == parent_comment_id,
|
||||
|
@ -655,12 +655,7 @@ def comment(v):
|
|||
c.upvotes += 3
|
||||
g.db.add(c)
|
||||
|
||||
if not v.rehab:
|
||||
check_for_slots_command(body, v, c)
|
||||
|
||||
check_for_blackjack_commands(body, v, c)
|
||||
|
||||
if not c.slots_result and not c.blackjack_result and v.marseyawarded and parent_post.id not in ADMIGGERS and marseyaward_body_regex.search(body_html):
|
||||
if v.marseyawarded and parent_post.id not in ADMIGGERS and marseyaward_body_regex.search(body_html):
|
||||
return {"error":"You can only type marseys!"}, 403
|
||||
|
||||
check_for_treasure(body, c)
|
||||
|
@ -669,7 +664,7 @@ def comment(v):
|
|||
answer = random.choice(WORDLE_LIST)
|
||||
c.wordle_result = f'_active_{answer}'
|
||||
|
||||
if not c.slots_result and not c.blackjack_result and not c.wordle_result and not rts:
|
||||
if not c.wordle_result and not rts:
|
||||
parent_post.comment_count += 1
|
||||
g.db.add(parent_post)
|
||||
|
||||
|
@ -980,29 +975,6 @@ def unsave_comment(cid, v):
|
|||
|
||||
return {"message": "Comment unsaved!"}
|
||||
|
||||
@app.post("/blackjack/<cid>")
|
||||
@limiter.limit("1/second;30/minute;200/hour;2500/day")
|
||||
@limiter.limit("1/second;30/minute;200/hour;2500/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
|
||||
@auth_required
|
||||
def handle_blackjack_action(cid, v):
|
||||
comment = get_comment(cid)
|
||||
|
||||
if v.id != comment.author_id:
|
||||
abort(403)
|
||||
|
||||
if 'active' in comment.blackjack_result:
|
||||
try: action = request.values.get("thing").strip().lower()
|
||||
except: abort(400)
|
||||
|
||||
if action == 'hit': player_hit(comment)
|
||||
elif action == 'stay': player_stayed(comment)
|
||||
elif action == 'doubledown': player_doubled_down(comment)
|
||||
elif action == 'insurance': player_bought_insurance(comment)
|
||||
|
||||
g.db.add(comment)
|
||||
g.db.add(v)
|
||||
return {"response" : comment.blackjack_html(v)}
|
||||
|
||||
|
||||
def diff_words(answer, guess):
|
||||
"""
|
||||
|
|
|
@ -9,7 +9,7 @@ import requests
|
|||
|
||||
@app.post("/lottery/end")
|
||||
@admin_level_required(3)
|
||||
@lottery_required
|
||||
@casino_required
|
||||
def lottery_end(v):
|
||||
success, message = end_lottery_session()
|
||||
return {"message": message} if success else {"error": message}
|
||||
|
@ -17,7 +17,7 @@ def lottery_end(v):
|
|||
|
||||
@app.post("/lottery/start")
|
||||
@admin_level_required(3)
|
||||
@lottery_required
|
||||
@casino_required
|
||||
def lottery_start(v):
|
||||
start_new_lottery_session()
|
||||
return {"message": "Lottery started."}
|
||||
|
@ -26,7 +26,7 @@ def lottery_start(v):
|
|||
@app.post("/lottery/buy")
|
||||
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
||||
@auth_required
|
||||
@lottery_required
|
||||
@casino_required
|
||||
def lottery_buy(v):
|
||||
try: quantity = int(request.values.get("quantity"))
|
||||
except: return {"error": "Invalid ticket quantity."}
|
||||
|
@ -44,22 +44,15 @@ def lottery_buy(v):
|
|||
@app.get("/lottery/active")
|
||||
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
||||
@auth_required
|
||||
@lottery_required
|
||||
@casino_required
|
||||
def lottery_active(v):
|
||||
lottery, participants = get_active_lottery_stats()
|
||||
|
||||
return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
|
||||
|
||||
@app.get("/lottery")
|
||||
@auth_required
|
||||
@lottery_required
|
||||
def lottery(v):
|
||||
lottery_stats, participant_stats = get_active_lottery_stats()
|
||||
return render_template("lottery.html", v=v, lottery_stats=lottery_stats, participant_stats=participant_stats)
|
||||
|
||||
@app.get("/admin/lottery/participants")
|
||||
@admin_level_required(2)
|
||||
@lottery_required
|
||||
@casino_required
|
||||
def lottery_admin(v):
|
||||
participants = get_users_participating_in_lottery()
|
||||
return render_template("admin/lottery.html", v=v, participants=participants)
|
||||
|
|
|
@ -176,8 +176,8 @@ def post_id(pid, anything=None, v=None, sub=None):
|
|||
|
||||
comments = sort_comments(sort, comments)
|
||||
|
||||
first = [c[0] for c in comments.filter(or_(and_(Comment.slots_result == None, Comment.blackjack_result == None, Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()]
|
||||
second = [c[0] for c in comments.filter(or_(Comment.slots_result != None, Comment.blackjack_result != None, Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()]
|
||||
first = [c[0] for c in comments.filter(or_(and_(Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()]
|
||||
second = [c[0] for c in comments.filter(or_(Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()]
|
||||
comments = first + second
|
||||
else:
|
||||
pinned = g.db.query(Comment).filter(Comment.parent_submission == post.id, Comment.stickied != None).all()
|
||||
|
@ -186,8 +186,8 @@ def post_id(pid, anything=None, v=None, sub=None):
|
|||
|
||||
comments = sort_comments(sort, comments)
|
||||
|
||||
first = comments.filter(or_(and_(Comment.slots_result == None, Comment.blackjack_result == None, Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()
|
||||
second = comments.filter(or_(Comment.slots_result != None, Comment.blackjack_result != None, Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()
|
||||
first = comments.filter(or_(and_(Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()
|
||||
second = comments.filter(or_(Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()
|
||||
comments = first + second
|
||||
|
||||
offset = 0
|
||||
|
@ -302,16 +302,16 @@ def viewmore(v, pid, sort, offset):
|
|||
|
||||
comments = sort_comments(sort, comments)
|
||||
|
||||
first = [c[0] for c in comments.filter(or_(and_(Comment.slots_result == None, Comment.blackjack_result == None, Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()]
|
||||
second = [c[0] for c in comments.filter(or_(Comment.slots_result != None, Comment.blackjack_result != None, Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()]
|
||||
first = [c[0] for c in comments.filter(or_(and_(Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()]
|
||||
second = [c[0] for c in comments.filter(or_(Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()]
|
||||
comments = first + second
|
||||
else:
|
||||
comments = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.parent_submission == pid, Comment.level == 1, Comment.stickied == None, Comment.id.notin_(ids))
|
||||
|
||||
comments = sort_comments(sort, comments)
|
||||
|
||||
first = comments.filter(or_(and_(Comment.slots_result == None, Comment.blackjack_result == None, Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()
|
||||
second = comments.filter(or_(Comment.slots_result != None, Comment.blackjack_result != None, Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()
|
||||
first = comments.filter(or_(and_(Comment.wordle_result == None), func.length(Comment.body_html) > 100)).all()
|
||||
second = comments.filter(or_(Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()
|
||||
comments = first + second
|
||||
comments = comments[offset:]
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
</ul>
|
||||
{%- endif %}
|
||||
|
||||
{% if LOTTERY_ENABLED -%}
|
||||
{% if CASINO_ENABLED -%}
|
||||
<h4>Lottery</h4>
|
||||
<ul>
|
||||
<li><a href="/admin/lottery/participants">Participants</a></li>
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
{% extends "default.html" %} {% block content %}
|
||||
<link rel="stylesheet" href="/assets/css/casino.css?v=12" />
|
||||
<script src="/assets/js/casino.js?v=2002"></script>
|
||||
|
||||
<!-- New -->
|
||||
<div class="casino-games">
|
||||
<!-- Slots -->
|
||||
<div id="slots-block" class="casino-block">
|
||||
<div class="casino-block-title">
|
||||
Slots
|
||||
<hr style="flex: 1; margin-left: 1rem" />
|
||||
</div>
|
||||
<div class="casino-block-inner">
|
||||
<div class="casino-block-left">
|
||||
<!-- Game -->
|
||||
<div class="casino-block-game">
|
||||
<div>
|
||||
<div class="casino-slots-results" style="flex: 1">
|
||||
<div class="reel">
|
||||
<img src="/i/rDrama/coins.webp?v=3009" alt="coin" />
|
||||
</div>
|
||||
<div class="reel">
|
||||
<img src="/i/rDrama/coins.webp?v=3009" alt="coin" />
|
||||
</div>
|
||||
<div class="reel">
|
||||
<img src="/i/rDrama/coins.webp?v=3009" alt="coin" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="casino-slots-outcome" id="casinoSlotsResult">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bet -->
|
||||
<div class="casino-block-bet">
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys" style="margin-right: 1rem">
|
||||
<div>Enter Bet</div>
|
||||
<div>
|
||||
<input
|
||||
id="casinoSlotsBet"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
value="100"
|
||||
min="100"
|
||||
step="1"
|
||||
aria-label="Bet"
|
||||
name="casinoSlotsBet"
|
||||
type="number"
|
||||
style="flex: 1; max-width: 200px; text-align: right"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lottery-page--stat-values">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="casinoSlotsCurrency"
|
||||
id="casinoSlotsCurrencyDramacoin"
|
||||
value="dramacoin"
|
||||
checked
|
||||
/>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="casinoSlotsCurrencyDramacoin"
|
||||
>
|
||||
<img
|
||||
src="/i/rDrama/coins.webp?v=3009"
|
||||
alt="coin"
|
||||
width="40"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title="Dramacoin"
|
||||
aria-label="Dramacoin"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="casinoSlotsCurrency"
|
||||
id="casinoSlotsCurrencyMarseybux"
|
||||
value="marseybux"
|
||||
/>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="casinoSlotsCurrencyMarseybux"
|
||||
>
|
||||
<img
|
||||
src="/i/marseybux.webp?v=2000"
|
||||
alt="marseybux"
|
||||
width="40"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title="Marseybux"
|
||||
aria-label="Marseybux"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success lottery-page--action"
|
||||
id="casinoSlotsPull"
|
||||
style="width: 100%"
|
||||
onclick="pullSlots()"
|
||||
>
|
||||
Pull
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Blackjack -->
|
||||
<div id="blackjack-block" class="casino-block">
|
||||
<div class="casino-block-title">
|
||||
Blackjack
|
||||
<hr style="flex: 1; margin-left: 1rem" />
|
||||
</div>
|
||||
<div class="casino-block-inner">
|
||||
<div class="casino-block-left">
|
||||
<!-- Game -->
|
||||
<div class="casino-block-game">
|
||||
<div class="casino-game">
|
||||
<div style="flex: 1">
|
||||
<div class="blackjack-table">
|
||||
<div style="display: flex; align-items: center">
|
||||
<small style="margin-right: 0.5rem">Dealer</small>
|
||||
<hr style="flex: 1" />
|
||||
</div>
|
||||
<div class="hand" id="casinoBlackjackDealerHand">
|
||||
<div class="playing-card" data-who="dealer"></div>
|
||||
<div class="playing-card" data-who="dealer"></div>
|
||||
<div class="playing-card" data-who="dealer"></div>
|
||||
<div class="playing-card" data-who="dealer"></div>
|
||||
<div class="playing-card" data-who="dealer"></div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="hand" id="casinoBlackjackPlayerHand">
|
||||
<div class="playing-card" data-who="player"></div>
|
||||
<div class="playing-card" data-who="player"></div>
|
||||
<div class="playing-card" data-who="player"></div>
|
||||
<div class="playing-card" data-who="player"></div>
|
||||
<div class="playing-card" data-who="player"></div>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<hr style="flex: 1; margin-right: 0.5rem" />
|
||||
<small>Player</small>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="casinoBlackjackResult"
|
||||
class="casino-blackjack-outcome"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bet -->
|
||||
<div class="casino-block-bet">
|
||||
<div id="casinoBlackjackWager" class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys" style="margin-right: 1rem">
|
||||
<div>Enter Bet</div>
|
||||
<div>
|
||||
<input
|
||||
id="casinoBlackjackBet"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
value="100"
|
||||
min="100"
|
||||
step="1"
|
||||
aria-label="Bet"
|
||||
name="casinoBlackjackBet"
|
||||
type="number"
|
||||
style="flex: 1; max-width: 200px; text-align: right"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lottery-page--stat-values">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="casinoBlackjackCurrency"
|
||||
id="casinoBlackjackCurrencyDramacoin"
|
||||
value="dramacoin"
|
||||
checked
|
||||
/>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="casinoBlackjackCurrencyDramacoin"
|
||||
>
|
||||
<img
|
||||
src="/i/rDrama/coins.webp?v=3009"
|
||||
alt="coin"
|
||||
width="40"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title="Dramacoin"
|
||||
aria-label="Dramacoin"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="casinoBlackjackCurrency"
|
||||
id="casinoBlackjackCurrencyMarseybux"
|
||||
value="marseybux"
|
||||
/>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="casinoBlackjackCurrencyMarseybux"
|
||||
>
|
||||
<img
|
||||
src="/i/marseybux.webp?v=2000"
|
||||
alt="marseybux"
|
||||
width="40"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title="Marseybux"
|
||||
aria-label="Marseybux"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="casinoBlackjackActions" class="casino-blackjack-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success lottery-page--action"
|
||||
id="casinoBlackjackDeal"
|
||||
style="width: 100%"
|
||||
onclick="dealBlackjack()"
|
||||
>
|
||||
Deal
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="casino-lottery">{% include "lottery.html" %}</div>
|
||||
{% endblock %}
|
|
@ -208,14 +208,6 @@
|
|||
<em>Found {{c.treasure_amount}} Coins!</em>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if c.slots_result %}
|
||||
<em style="position: relative; top: 2px; margin-left: 0.5rem">{{c.slots_result}}</em>
|
||||
{% endif %}
|
||||
|
||||
{% if c.blackjack_result %}
|
||||
{{c.blackjack_html(v) | safe}}
|
||||
{% endif %}
|
||||
|
||||
{% if c.wordle_result %}
|
||||
{{c.wordle_html(v) | safe}}
|
||||
|
|
|
@ -606,28 +606,6 @@ line breaks
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if FEATURES['GAMBLING'] %}
|
||||
<tr>
|
||||
<td>!slots100</td>
|
||||
<td>Play slots using coins - minimum 100 coins</td>
|
||||
</tr>
|
||||
{% if FEATURES['PROCOINS'] %}
|
||||
<tr>
|
||||
<td>!slotsmb100</td>
|
||||
<td>Play slots using marseybux - minimum 100 marseybux</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>!blackjack100</td>
|
||||
<td>Play blackjack using coins - minimum 100 coins</td>
|
||||
</tr>
|
||||
{% if FEATURES['PROCOINS'] %}
|
||||
<tr>
|
||||
<td>!blackjackmb100</td>
|
||||
<td>Play blackjack using marseybux - minimum 100 marseybux</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if FEATURES['WORDLE'] %}
|
||||
<tr>
|
||||
<td>!wordle</td>
|
||||
|
|
|
@ -123,9 +123,9 @@
|
|||
|
||||
<a class="mobile-nav-icon d-md-none" href="/random_user"><i class="fas fa-music align-middle text-gray-500 black"></i></a>
|
||||
|
||||
{% if v and LOTTERY_ENABLED %}
|
||||
<a class="mobile-nav-icon d-md-none" href="/lottery">
|
||||
<i class="fas fa-ticket align-middle text-gray-500 black"></i>
|
||||
{% if v and CASINO_ENABLED %}
|
||||
<a class="mobile-nav-icon d-md-none" href="/casino">
|
||||
<i class="fas fa-usd align-middle text-gray-500 black"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
|
@ -179,9 +179,9 @@
|
|||
<a class="nav-link" href="/random_user" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Random User"><i class="fas fa-music"></i></a>
|
||||
</li>
|
||||
|
||||
{% if LOTTERY_ENABLED %}
|
||||
{% if CASINO_ENABLED %}
|
||||
<li class="nav-item d-flex align-items-center justify-content-center text-center mx-1">
|
||||
<a class="nav-link" href="/lottery" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Lottery"><i class="fas fa-ticket"></i></a>
|
||||
<a class="nav-link" href="/casino" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Casino"><i class="fas fa-usd"></i></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -1,191 +1,189 @@
|
|||
{% extends "default.html" %} {% block content %}
|
||||
<div>
|
||||
<div class="lottery-page--wrapper">
|
||||
<div class="lottery-page--image">
|
||||
<img src="/i/{{SITE_NAME}}/lottery.webp?v=2000" />
|
||||
<img
|
||||
id="lotteryTicketPulled"
|
||||
src="/i/{{SITE_NAME}}/lottery_active.webp?v=2000"
|
||||
style="display: none"
|
||||
/>
|
||||
</div>
|
||||
<div class="lottery-page--stats">
|
||||
{% if v.admin_level > 2 %}
|
||||
<div
|
||||
class="lottery-page--stat"
|
||||
style="position: relative; padding-top: 1rem; overflow: hidden"
|
||||
>
|
||||
<i
|
||||
class="fas fa-broom"
|
||||
style="
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
right: -4px;
|
||||
font-size: 50px;
|
||||
color: var(--gray-600);
|
||||
"
|
||||
>
|
||||
</i>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger"
|
||||
id="endLotterySession"
|
||||
style="display: none"
|
||||
onclick="endLotterySession()"
|
||||
>
|
||||
End Current Session
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success"
|
||||
id="startLotterySession"
|
||||
style="display: none"
|
||||
onclick="startLotterySession()"
|
||||
>
|
||||
Start New Session
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys">
|
||||
<div>Prize</div>
|
||||
<div>Time Left</div>
|
||||
<div>Tickets Sold</div>
|
||||
<div>Participants</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat-values">
|
||||
<div>
|
||||
<img
|
||||
id="prize-image"
|
||||
alt="coins"
|
||||
class="mr-1 ml-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
height="13"
|
||||
src="{{asset_siteimg('coins.webp')}}"
|
||||
aria-label="coins"
|
||||
title="coins"
|
||||
style="display: none; position: relative; top: -2px"
|
||||
/>
|
||||
<span id="prize">-</span>
|
||||
</div>
|
||||
<div id="timeLeft">-</div>
|
||||
<div id="ticketsSoldThisSession">-</div>
|
||||
<div id="participantsThisSession">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys">
|
||||
<div>Your Held Tickets</div>
|
||||
<div>Lifetime Held Tickets</div>
|
||||
<div>Lifetime Winnings</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat-values">
|
||||
<div id="ticketsHeldCurrent">-</div>
|
||||
<div id="ticketsHeldTotal">-</div>
|
||||
<div id="winnings">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lottery-page--image">
|
||||
<img src="/i/{{SITE_NAME}}/lottery.webp?v=2000" />
|
||||
<img
|
||||
id="lotteryTicketPulled"
|
||||
src="/i/{{SITE_NAME}}/lottery_active.webp?v=2000"
|
||||
style="display: none"
|
||||
/>
|
||||
</div>
|
||||
<div class="lottery-page--stats">
|
||||
{% if v.admin_level > 2 %}
|
||||
<div
|
||||
class="lottery-page--stat"
|
||||
style="position: relative; padding-top: 1rem; overflow: hidden"
|
||||
>
|
||||
<i
|
||||
class="fas fa-broom"
|
||||
style="
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
right: -4px;
|
||||
font-size: 50px;
|
||||
color: var(--gray-600);
|
||||
"
|
||||
>
|
||||
</i>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger"
|
||||
id="endLotterySession"
|
||||
style="display: none"
|
||||
onclick="endLotterySession()"
|
||||
>
|
||||
End Current Session
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success"
|
||||
id="startLotterySession"
|
||||
style="display: none"
|
||||
onclick="startLotterySession()"
|
||||
>
|
||||
Start New Session
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys">
|
||||
<div>Prize</div>
|
||||
<div>Time Left</div>
|
||||
<div>Tickets Sold</div>
|
||||
<div>Participants</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat-values">
|
||||
<div>
|
||||
<img
|
||||
id="prize-image"
|
||||
alt="coins"
|
||||
class="mr-1 ml-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
height="13"
|
||||
src="{{asset_siteimg('coins.webp')}}"
|
||||
aria-label="coins"
|
||||
title="coins"
|
||||
style="display: none; position: relative; top: -2px"
|
||||
/>
|
||||
<span id="prize">-</span>
|
||||
</div>
|
||||
<div id="timeLeft">-</div>
|
||||
<div id="ticketsSoldThisSession">-</div>
|
||||
<div id="participantsThisSession">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys">
|
||||
<div>Your Held Tickets</div>
|
||||
<div>Lifetime Held Tickets</div>
|
||||
<div>Lifetime Winnings</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat-values">
|
||||
<div id="ticketsHeldCurrent">-</div>
|
||||
<div id="ticketsHeldTotal">-</div>
|
||||
<div id="winnings">-</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys">
|
||||
<div>Purchase Quantity</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat-values">
|
||||
<div>
|
||||
<input
|
||||
id="ticketPurchaseQuantity"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
value="1"
|
||||
min="1"
|
||||
step="1"
|
||||
aria-label="Quantity"
|
||||
name="ticketPurchaseQuantity"
|
||||
type="number"
|
||||
style="flex: 1; max-width: 100px; text-align: center;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat">
|
||||
<div class="lottery-page--stat-keys">
|
||||
<div>Purchase Quantity</div>
|
||||
</div>
|
||||
<div class="lottery-page--stat-values">
|
||||
<div>
|
||||
<input
|
||||
id="ticketPurchaseQuantity"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
value="1"
|
||||
min="1"
|
||||
step="1"
|
||||
aria-label="Quantity"
|
||||
name="ticketPurchaseQuantity"
|
||||
type="number"
|
||||
style="flex: 1; max-width: 100px; text-align: center"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success lottery-page--action"
|
||||
id="purchaseTicket"
|
||||
onclick="purchaseLotteryTicket()"
|
||||
>
|
||||
Purchase <span id="totalQuantityOfTickets">1</span> for
|
||||
<img
|
||||
alt="coins"
|
||||
class="mr-1 ml-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
height="13"
|
||||
src="{{asset_siteimg('coins.webp')}}"
|
||||
aria-label="coins"
|
||||
title="coins"
|
||||
/>
|
||||
|
||||
<span id="totalCostOfTickets">12</span>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success lottery-page--action"
|
||||
id="purchaseTicket"
|
||||
onclick="purchaseLotteryTicket()"
|
||||
>
|
||||
Purchase <span id="totalQuantityOfTickets">1</span> for
|
||||
<img
|
||||
alt="coins"
|
||||
class="mr-1 ml-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
height="13"
|
||||
src="{{asset_siteimg('coins.webp')}}"
|
||||
aria-label="coins"
|
||||
title="coins"
|
||||
/>
|
||||
|
||||
<!-- Success -->
|
||||
<div
|
||||
class="toast"
|
||||
id="lottery-post-success"
|
||||
style="
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
margin: 0 auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: unset;
|
||||
z-index: 1000;
|
||||
height: auto !important;
|
||||
"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
data-bs-animation="true"
|
||||
data-bs-autohide="true"
|
||||
data-bs-delay="5000"
|
||||
>
|
||||
<div class="toast-body bg-success text-center text-white">
|
||||
<i class="fas fa-comment-alt-smile mr-2"></i
|
||||
><span id="lottery-post-success-text"></span>
|
||||
</div>
|
||||
</div>
|
||||
<span id="totalCostOfTickets">12</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
<div
|
||||
class="toast"
|
||||
id="lottery-post-error"
|
||||
style="
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
margin: 0 auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: unset;
|
||||
z-index: 1000;
|
||||
height: auto !important;
|
||||
"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
data-bs-animation="true"
|
||||
data-bs-autohide="true"
|
||||
data-bs-delay="5000"
|
||||
>
|
||||
<div class="toast-body bg-danger text-center text-white">
|
||||
<i class="fas fa-exclamation-circle mr-2"></i
|
||||
><span id="lottery-post-error-text"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Success -->
|
||||
<div
|
||||
class="toast"
|
||||
id="lottery-post-success"
|
||||
style="
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
margin: 0 auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: unset;
|
||||
z-index: 1000;
|
||||
height: auto !important;
|
||||
"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
data-bs-animation="true"
|
||||
data-bs-autohide="true"
|
||||
data-bs-delay="5000"
|
||||
>
|
||||
<div class="toast-body bg-success text-center text-white">
|
||||
<i class="fas fa-comment-alt-smile mr-2"></i
|
||||
><span id="lottery-post-success-text"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
<div
|
||||
class="toast"
|
||||
id="lottery-post-error"
|
||||
style="
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
margin: 0 auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: unset;
|
||||
z-index: 1000;
|
||||
height: auto !important;
|
||||
"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
data-bs-animation="true"
|
||||
data-bs-autohide="true"
|
||||
data-bs-delay="5000"
|
||||
>
|
||||
<div class="toast-body bg-danger text-center text-white">
|
||||
<i class="fas fa-exclamation-circle mr-2"></i
|
||||
><span id="lottery-post-error-text"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{asset('js/lottery.js')}}"></script>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{%-
|
||||
set CACHE_VER = {
|
||||
'css/main.css': 506,
|
||||
'css/main.css': 507,
|
||||
'css/catalog.css': 2,
|
||||
|
||||
'css/4chan.css': 61,
|
||||
|
|
|
@ -356,8 +356,6 @@ CREATE TABLE public.comments (
|
|||
top_comment_id integer,
|
||||
stickied_utc integer,
|
||||
ghost boolean DEFAULT false NOT NULL,
|
||||
slots_result character varying(36),
|
||||
blackjack_result character varying(860),
|
||||
treasure_amount character varying(10),
|
||||
wordle_result character varying(115)
|
||||
);
|
||||
|
|
|
@ -598,8 +598,6 @@ Ayoo, you're fat as fuck!
|
|||
{[para]}
|
||||
AVOCADO NIGGER!
|
||||
{[para]}
|
||||
!slots
|
||||
{[para]}
|
||||
You're poor, figure it out. Imagine being at the super market looking at the cost of nectors and shit. Fuck you, dude.
|
||||
{[para]}
|
||||
Want to go rape some fire hydrants?
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
CREATE TYPE casino_game_kind AS ENUM ('blackjack', 'slots');
|
||||
|
||||
CREATE TYPE casino_game_currency AS ENUM ('coins', 'procoins');
|
||||
|
||||
CREATE TABLE casino_games (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id integer NOT NULL REFERENCES users(id),
|
||||
created_utc integer NOT NULL,
|
||||
active boolean NOT NULL DEFAULT true,
|
||||
currency casino_game_currency NOT NULL,
|
||||
wager integer NOT NULL,
|
||||
winnings integer NOT NULL,
|
||||
kind casino_game_kind NOT NULL,
|
||||
game_state jsonb NOT NULL
|
||||
);
|
Loading…
Reference in New Issue