forked from rDrama/rDrama
Restructure blackjack to only use a single endpoint and better handle "game end" logic
parent
6ae4459063
commit
b1674355c0
|
@ -82,6 +82,8 @@ function handleSlotsResponse(xhr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blackjack
|
// Blackjack
|
||||||
|
|
||||||
|
// Checking existing status onload.
|
||||||
// When the casino loads, look up the "blackjack status" of a player to either start a new game or continue an existing game.
|
// When the casino loads, look up the "blackjack status" of a player to either start a new game or continue an existing game.
|
||||||
if (
|
if (
|
||||||
document.readyState === "complete" ||
|
document.readyState === "complete" ||
|
||||||
|
@ -114,12 +116,16 @@ function handleBlackjackStatusResponse(xhr) {
|
||||||
if (succeeded) {
|
if (succeeded) {
|
||||||
if (response.active) {
|
if (response.active) {
|
||||||
updateBlackjack(response.game_state);
|
updateBlackjack(response.game_state);
|
||||||
|
} else {
|
||||||
|
updateBlackjackActions(null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("error");
|
console.error("error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DOM Manipulation
|
||||||
|
|
||||||
// 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.
|
// 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) {
|
function updateBlackjack(state) {
|
||||||
const { player, dealer, status } = state;
|
const { player, dealer, status } = state;
|
||||||
|
@ -232,7 +238,7 @@ function updateBlackjackActions(state) {
|
||||||
|
|
||||||
clearBlackjackActions();
|
clearBlackjackActions();
|
||||||
|
|
||||||
if (state.status === "active") {
|
if (state && state.status === "active") {
|
||||||
document.getElementById("casinoBlackjackWager").style.display = "none";
|
document.getElementById("casinoBlackjackWager").style.display = "none";
|
||||||
|
|
||||||
const actionLookup = {
|
const actionLookup = {
|
||||||
|
@ -258,8 +264,7 @@ function updateBlackjackActions(state) {
|
||||||
actionWrapper.innerHTML = actions.join("\n");
|
actionWrapper.innerHTML = actions.join("\n");
|
||||||
} else {
|
} else {
|
||||||
// Game is over, deal a new game.
|
// Game is over, deal a new game.
|
||||||
document.getElementById("casinoBlackjackWager").style.display = "flex";
|
showWagerWidget();
|
||||||
document.getElementById("casinoBlackjackBet").disabled = false;
|
|
||||||
|
|
||||||
const deal = buildBlackjackAction(
|
const deal = buildBlackjackAction(
|
||||||
"casinoBlackjackDeal",
|
"casinoBlackjackDeal",
|
||||||
|
@ -272,30 +277,20 @@ function updateBlackjackActions(state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dealBlackjack() {
|
function hideWagerWidget() {
|
||||||
const wager = document.getElementById("casinoBlackjackBet").value;
|
|
||||||
const currency = document.querySelector(
|
|
||||||
'input[name="casinoBlackjackCurrency"]:checked'
|
|
||||||
).value;
|
|
||||||
|
|
||||||
document.getElementById("casinoBlackjackBet").disabled = true;
|
document.getElementById("casinoBlackjackBet").disabled = true;
|
||||||
document.getElementById("casinoBlackjackDeal").disabled = true;
|
document.getElementById("casinoBlackjackDeal").disabled = true;
|
||||||
document.getElementById("casinoBlackjackWager").style.display = "none";
|
document.getElementById("casinoBlackjackWager").style.display = "none";
|
||||||
document.getElementById("casinoBlackjackResult").style.visibility = "hidden";
|
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) {
|
function showWagerWidget() {
|
||||||
|
document.getElementById("casinoBlackjackWager").style.display = "flex";
|
||||||
|
document.getElementById("casinoBlackjackBet").disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions, Requests & Responses
|
||||||
|
function takeBlackjackAction(action, args = {}) {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open("post", "/casino/blackjack/action");
|
xhr.open("post", "/casino/blackjack/action");
|
||||||
xhr.onload = handleBlackjackResponse.bind(null, xhr);
|
xhr.onload = handleBlackjackResponse.bind(null, xhr);
|
||||||
|
@ -304,9 +299,20 @@ function takeBlackjackAction(action) {
|
||||||
form.append("formkey", formkey());
|
form.append("formkey", formkey());
|
||||||
form.append("action", action);
|
form.append("action", action);
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(args)) {
|
||||||
|
form.append(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
xhr.send(form);
|
xhr.send(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dealBlackjack = () => {
|
||||||
|
const wager = document.getElementById("casinoBlackjackBet").value;
|
||||||
|
const currency = document.querySelector('input[name="casinoBlackjackCurrency"]:checked').value;
|
||||||
|
|
||||||
|
hideWagerWidget();
|
||||||
|
takeBlackjackAction("deal", { currency, wager });
|
||||||
|
}
|
||||||
const hitBlackjack = takeBlackjackAction.bind(null, "hit");
|
const hitBlackjack = takeBlackjackAction.bind(null, "hit");
|
||||||
const stayBlackjack = takeBlackjackAction.bind(null, "stay");
|
const stayBlackjack = takeBlackjackAction.bind(null, "stay");
|
||||||
const doubleBlackjack = takeBlackjackAction.bind(null, "double_down");
|
const doubleBlackjack = takeBlackjackAction.bind(null, "double_down");
|
||||||
|
@ -324,7 +330,7 @@ function handleBlackjackResponse(xhr) {
|
||||||
const succeeded =
|
const succeeded =
|
||||||
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
||||||
const blackjackResult = document.getElementById("casinoBlackjackResult");
|
const blackjackResult = document.getElementById("casinoBlackjackResult");
|
||||||
blackjackResult.classList.remove("text-success", "text-danger");
|
blackjackResult.classList.remove("text-success", "text-danger", "text-warning");
|
||||||
|
|
||||||
if (succeeded) {
|
if (succeeded) {
|
||||||
if (response.game_state) {
|
if (response.game_state) {
|
||||||
|
|
|
@ -54,15 +54,13 @@ def get_active_game(gambler):
|
||||||
Casino_Game.user_id == gambler.id).one_or_none()
|
Casino_Game.user_id == gambler.id).one_or_none()
|
||||||
|
|
||||||
if game:
|
if game:
|
||||||
return game, json.loads(game.game_state)
|
game_state = json.loads(game.game_state)
|
||||||
|
return game, game_state, get_safe_game_state(game_state)
|
||||||
else:
|
else:
|
||||||
return None, None
|
return None, None, None
|
||||||
|
|
||||||
|
|
||||||
def get_safe_game_state(gambler):
|
def get_safe_game_state(game_state):
|
||||||
game, game_state = get_active_game(gambler)
|
|
||||||
|
|
||||||
if game:
|
|
||||||
return {
|
return {
|
||||||
"player": game_state['player'],
|
"player": game_state['player'],
|
||||||
"dealer": [game_state['dealer'][0], "?"],
|
"dealer": [game_state['dealer'][0], "?"],
|
||||||
|
@ -71,15 +69,15 @@ def get_safe_game_state(gambler):
|
||||||
"doubled_down": game_state['doubled_down'],
|
"doubled_down": game_state['doubled_down'],
|
||||||
"status": game_state['status']
|
"status": game_state['status']
|
||||||
}
|
}
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def apply_blackjack_result(gambler):
|
def apply_blackjack_result(gambler):
|
||||||
game, game_state = get_active_game(gambler)
|
game, game_state, _ = get_active_game(gambler)
|
||||||
|
|
||||||
if game and game.active:
|
if game:
|
||||||
result = game_state['status']
|
result = game_state['status']
|
||||||
|
|
||||||
if result == 'push' or result == 'insured_loss':
|
if result == 'push' or result == 'insured_loss':
|
||||||
reward = game.wager
|
reward = game.wager
|
||||||
elif result == 'won':
|
elif result == 'won':
|
||||||
|
@ -95,53 +93,58 @@ def apply_blackjack_result(gambler):
|
||||||
gambler.winnings += reward
|
gambler.winnings += reward
|
||||||
game.winnings += reward
|
game.winnings += reward
|
||||||
|
|
||||||
if result not in ('push','blackjack'):
|
|
||||||
game.active = False
|
game.active = False
|
||||||
g.db.add(game)
|
g.db.add(game)
|
||||||
|
|
||||||
|
# region Actions
|
||||||
|
def gambler_dealt(gambler, currency, wager):
|
||||||
|
existing_game, _, _ = get_active_game(gambler)
|
||||||
|
|
||||||
def deal_blackjack_game(gambler, wager_value, currency):
|
if not existing_game:
|
||||||
over_min = wager_value >= minimum_bet
|
over_min = wager >= minimum_bet
|
||||||
under_max = wager_value <= maximum_bet
|
under_max = wager <= maximum_bet
|
||||||
using_dramacoin = currency == "dramacoin"
|
using_dramacoin = currency == "dramacoin"
|
||||||
using_marseybux = not using_dramacoin
|
using_marseybux = not using_dramacoin
|
||||||
has_proper_funds = (using_dramacoin and gambler.coins >= wager_value) or (
|
has_proper_funds = (using_dramacoin and gambler.coins >= wager) or (
|
||||||
using_marseybux and gambler.procoins >= wager_value)
|
using_marseybux and gambler.procoins >= wager)
|
||||||
currency_prop = "coins" if using_dramacoin else "procoins"
|
currency_prop = "coins" if using_dramacoin else "procoins"
|
||||||
currency_value = getattr(gambler, currency_prop, 0)
|
currency_value = getattr(gambler, currency_prop, 0)
|
||||||
|
|
||||||
if (over_min and under_max and has_proper_funds):
|
if (over_min and under_max and has_proper_funds):
|
||||||
build_game(gambler, currency_prop, wager_value)
|
# Start the game.
|
||||||
|
build_game(gambler, currency_prop, wager)
|
||||||
game, game_state = get_active_game(gambler)
|
game, game_state, safe_state = get_active_game(gambler)
|
||||||
player_value = get_hand_value(game_state['player'])
|
player_value = get_hand_value(game_state['player'])
|
||||||
dealer_value = get_hand_value(game_state['dealer'])
|
dealer_value = get_hand_value(game_state['dealer'])
|
||||||
|
|
||||||
# Charge the gambler for the game, reduce their winnings, and start the game.
|
# Charge the gambler for the game, reduce their winnings.
|
||||||
setattr(gambler, currency_prop, currency_value - wager_value)
|
setattr(gambler, currency_prop, currency_value - wager)
|
||||||
gambler.winnings -= wager_value
|
gambler.winnings -= wager
|
||||||
game.winnings -= wager_value
|
game.winnings -= wager
|
||||||
|
|
||||||
# if player_value == 21 and dealer_value == 21:
|
# In two cases, the game is instantly over.
|
||||||
# game_state["status"] = 'push'
|
instantly_over = False
|
||||||
# save_game_state(game, game_state)
|
if player_value == 21 and dealer_value == 21:
|
||||||
# apply_blackjack_result(gambler)
|
instantly_over = True
|
||||||
# elif player_value == 21:
|
game_state["status"] = 'push'
|
||||||
# game_state["status"] = 'blackjack'
|
save_game_state(game, game_state)
|
||||||
# save_game_state(game, game_state)
|
apply_blackjack_result(gambler)
|
||||||
# apply_blackjack_result(gambler)
|
elif player_value == 21:
|
||||||
|
instantly_over = True
|
||||||
|
game_state["status"] = 'blackjack'
|
||||||
|
save_game_state(game, game_state)
|
||||||
|
apply_blackjack_result(gambler)
|
||||||
|
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
||||||
return True
|
if instantly_over:
|
||||||
|
return True, game_state
|
||||||
else:
|
else:
|
||||||
return False
|
return True, safe_state
|
||||||
|
|
||||||
# region Actions
|
|
||||||
|
|
||||||
|
|
||||||
def gambler_hit(gambler):
|
def gambler_hit(gambler):
|
||||||
game, game_state = get_active_game(gambler)
|
game, game_state, safe_state = get_active_game(gambler)
|
||||||
|
|
||||||
if game:
|
if game:
|
||||||
player = game_state['player']
|
player = game_state['player']
|
||||||
|
@ -167,13 +170,14 @@ def gambler_hit(gambler):
|
||||||
forced_stay_success, forced_stay_state = gambler_stayed(gambler)
|
forced_stay_success, forced_stay_state = gambler_stayed(gambler)
|
||||||
return forced_stay_success, forced_stay_state
|
return forced_stay_success, forced_stay_state
|
||||||
else:
|
else:
|
||||||
return True, game_state
|
_, _, safe_state = get_active_game(gambler)
|
||||||
|
return True, safe_state
|
||||||
else:
|
else:
|
||||||
return False, game_state
|
return False, safe_state
|
||||||
|
|
||||||
|
|
||||||
def gambler_stayed(gambler):
|
def gambler_stayed(gambler):
|
||||||
game, game_state = get_active_game(gambler)
|
game, game_state, safe_state = get_active_game(gambler)
|
||||||
|
|
||||||
if game:
|
if game:
|
||||||
player = game_state['player']
|
player = game_state['player']
|
||||||
|
@ -206,11 +210,11 @@ def gambler_stayed(gambler):
|
||||||
|
|
||||||
return True, game_state
|
return True, game_state
|
||||||
else:
|
else:
|
||||||
return False, game_state
|
return False, safe_state
|
||||||
|
|
||||||
|
|
||||||
def gambler_doubled_down(gambler):
|
def gambler_doubled_down(gambler):
|
||||||
game, game_state = get_active_game(gambler)
|
game, game_state, safe_state = get_active_game(gambler)
|
||||||
|
|
||||||
if game and not game_state['doubled_down']:
|
if game and not game_state['doubled_down']:
|
||||||
currency_value = getattr(gambler, game.currency, 0)
|
currency_value = getattr(gambler, game.currency, 0)
|
||||||
|
@ -229,14 +233,13 @@ def gambler_doubled_down(gambler):
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
||||||
last_hit_success, last_hit_state = gambler_hit(gambler)
|
last_hit_success, last_hit_state = gambler_hit(gambler)
|
||||||
|
|
||||||
return last_hit_success, last_hit_state
|
return last_hit_success, last_hit_state
|
||||||
else:
|
else:
|
||||||
return False, game_state
|
return False, safe_state
|
||||||
|
|
||||||
|
|
||||||
def gambler_purchased_insurance(gambler):
|
def gambler_purchased_insurance(gambler):
|
||||||
game, game_state = get_active_game(gambler)
|
game, game_state, safe_state = get_active_game(gambler)
|
||||||
|
|
||||||
if game and not game_state['insurance']:
|
if game and not game_state['insurance']:
|
||||||
insurance_cost = game.wager / 2
|
insurance_cost = game.wager / 2
|
||||||
|
@ -253,9 +256,10 @@ def gambler_purchased_insurance(gambler):
|
||||||
game_state['actions'] = determine_actions(game_state)
|
game_state['actions'] = determine_actions(game_state)
|
||||||
save_game_state(game, game_state)
|
save_game_state(game, game_state)
|
||||||
|
|
||||||
return True, game_state
|
_, _, safe_state = get_active_game(gambler)
|
||||||
|
return True, safe_state
|
||||||
else:
|
else:
|
||||||
return False, game_state
|
return False, safe_state
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
|
@ -46,47 +46,12 @@ def pull_slots(v):
|
||||||
@limiter.limit("3/second;30/minute;600/hour;12000/day")
|
@limiter.limit("3/second;30/minute;600/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def get_player_blackjack_status(v):
|
def get_player_blackjack_status(v):
|
||||||
game, game_state = get_active_game(v)
|
game, _, safe_state = get_active_game(v)
|
||||||
|
|
||||||
if game and game.active:
|
if game:
|
||||||
safe_state = get_safe_game_state(v)
|
|
||||||
return { "active": True, "game_state": safe_state }
|
return { "active": True, "game_state": safe_state }
|
||||||
else:
|
else:
|
||||||
return {"active": False, "game_state": game_state}
|
return { "active": False }
|
||||||
|
|
||||||
|
|
||||||
@app.post("/casino/blackjack")
|
|
||||||
@limiter.limit("3/second;30/minute;600/hour;12000/day")
|
|
||||||
@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)
|
|
||||||
if safe_state['status'] in ('push','blackjack'):
|
|
||||||
game.active = False
|
|
||||||
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")
|
@app.post("/casino/blackjack/action")
|
||||||
|
@ -101,7 +66,24 @@ def player_took_blackjack_action(v):
|
||||||
was_successful = False
|
was_successful = False
|
||||||
state = None
|
state = None
|
||||||
|
|
||||||
if action == 'hit':
|
if action == 'deal':
|
||||||
|
try:
|
||||||
|
currency = request.values.get("currency")
|
||||||
|
wager = int(request.values.get("wager"))
|
||||||
|
except:
|
||||||
|
return { "error": "Missing either currency or wager values." }
|
||||||
|
|
||||||
|
existing_game, _, _ = get_active_game(v)
|
||||||
|
|
||||||
|
if (currency == "dramacoin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
|
||||||
|
return {"error": f"Not enough {currency} to make that bet."}
|
||||||
|
elif existing_game:
|
||||||
|
return { "error": "Cannot start a new game while an existing game persists." }
|
||||||
|
else:
|
||||||
|
success, game_state = gambler_dealt(v, currency, wager)
|
||||||
|
was_successful = success
|
||||||
|
state = game_state
|
||||||
|
elif action == 'hit':
|
||||||
success, game_state = gambler_hit(v)
|
success, game_state = gambler_hit(v)
|
||||||
was_successful = success
|
was_successful = success
|
||||||
state = game_state
|
state = game_state
|
||||||
|
@ -119,6 +101,10 @@ def player_took_blackjack_action(v):
|
||||||
state = game_state
|
state = game_state
|
||||||
|
|
||||||
if was_successful:
|
if was_successful:
|
||||||
return {"active": True, "game_state": state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
|
return {
|
||||||
|
"active": True,
|
||||||
|
"game_state": state,
|
||||||
|
"gambler": { "coins": v.coins, "procoins": v.procoins }
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
return {"active": False, "game_state": None}
|
return { "active": False }
|
||||||
|
|
|
@ -32,6 +32,10 @@ def leaderboard_thread():
|
||||||
for user in users8:
|
for user in users8:
|
||||||
users9.append((user.id, votes3[user.id]))
|
users9.append((user.id, votes3[user.id]))
|
||||||
users9 = sorted(users9, key=lambda x: x[1], reverse=True)
|
users9 = sorted(users9, key=lambda x: x[1], reverse=True)
|
||||||
|
|
||||||
|
if (len(users9) < 2):
|
||||||
|
return
|
||||||
|
|
||||||
users9_1, users9_2 = zip(*users9[:25])
|
users9_1, users9_2 = zip(*users9[:25])
|
||||||
|
|
||||||
votes1 = db.query(Vote.user_id, func.count(Vote.user_id)).filter(Vote.vote_type==1).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
|
votes1 = db.query(Vote.user_id, func.count(Vote.user_id)).filter(Vote.vote_type==1).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
|
||||||
|
|
|
@ -234,15 +234,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="casinoBlackjackActions" class="casino-blackjack-actions">
|
<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>
|
||||||
|
|
Loading…
Reference in New Issue