From 7d8cfe55766f70019d5900ba8bc44eb483e22660 Mon Sep 17 00:00:00 2001 From: outruncolors <78451621+outruncolors@users.noreply.github.com> Date: Mon, 12 Sep 2022 20:07:39 -0500 Subject: [PATCH] Add Roulette (#351) * Add roulette file * Rename variable to avoid name collission * Add basic route and create new template for game * More work on the roulette template * Initial connection of front-end roulette to back-end roulette * Add to cron job * Pass bets to the front end * Update front-end looks * Add stackable poker chips for bets * Minor last changes * Handle minimum bets * Add bet table --- files/assets/images/pokerchip.webp | Bin 0 -> 6702 bytes files/helpers/casino.py | 7 +- files/helpers/cron.py | 2 + files/helpers/roulette.py | 295 ++++++++++ files/helpers/twentyone.py | 7 +- files/routes/casino.py | 97 +++- files/templates/casino.html | 6 + files/templates/casino/blackjack_screen.html | 1 + files/templates/casino/game_screen.html | 5 +- files/templates/casino/roulette_screen.html | 578 +++++++++++++++++++ sql/20220911-add-roulette.sql | 1 + 11 files changed, 966 insertions(+), 33 deletions(-) create mode 100644 files/assets/images/pokerchip.webp create mode 100644 files/helpers/roulette.py create mode 100644 files/templates/casino/roulette_screen.html create mode 100644 sql/20220911-add-roulette.sql diff --git a/files/assets/images/pokerchip.webp b/files/assets/images/pokerchip.webp new file mode 100644 index 0000000000000000000000000000000000000000..3bb60677315063761e0f4c1d8052c6888c358648 GIT binary patch literal 6702 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 amount + + if not can_afford: + raise Exception("Gambler cannot afford charge.") + + setattr(gambler, currency, currency_gambler_holds - amount) + g.db.add(gambler) + + +def gambler_placed_roulette_bet(gambler, bet, which, amount, currency): + if not bet in ( + RouletteAction.STRAIGHT_UP_BET, + RouletteAction.LINE_BET, + RouletteAction.COLUMN_BET, + RouletteAction.DOZEN_BET, + RouletteAction.EVEN_ODD_BET, + RouletteAction.RED_BLACK_BET, + RouletteAction.HIGH_LOW_BET + ): + raise Exception( + f'Illegal bet {bet} passed to Roulette#gambler_placed_roulette_bet') + + active_games = get_active_roulette_games() + + if len(active_games) == 0: + parent_id = int(time.time()) + else: + parent_id = json.loads(active_games[0].game_state)['parent_id'] + + charge_gambler(gambler, amount, currency) + + game = Casino_Game() + game.user_id = gambler.id + game.currency = currency + game.wager = amount + game.winnings = 0 + game.kind = 'roulette' + game.game_state = json.dumps( + {"parent_id": parent_id, "bet": bet, "which": which}) + game.active = True + g.db.add(game) + g.db.commit() + + +def get_roulette_bets_and_betters(): + participants = [] + bets = { + RouletteAction.STRAIGHT_UP_BET: [], + RouletteAction.LINE_BET: [], + RouletteAction.COLUMN_BET: [], + RouletteAction.DOZEN_BET: [], + RouletteAction.EVEN_ODD_BET: [], + RouletteAction.RED_BLACK_BET: [], + RouletteAction.HIGH_LOW_BET: [], + } + active_games = get_active_roulette_games() + + for game in active_games: + if not game.user_id in participants: + participants.append(game.user_id) + + user = get_account(game.user_id) + game_state = json.loads(game.game_state) + bet = game_state['bet'] + bets[bet].append({ + 'game_id': game.id, + 'gambler': game.user_id, + 'gambler_username': user.username, + 'gambler_profile_url': user.profile_url, + 'bet': bet, + 'which': game_state['which'], + 'wager': { + 'amount': game.wager, + 'currency': game.currency + } + }) + + return participants, bets, active_games + + +def spin_roulette_wheel(): + participants, bets, active_games = get_roulette_bets_and_betters() + + if len(participants) > 0: + number = randint(0, 37) # 37 is 00 + winners, payouts, rewards_by_game_id = determine_roulette_winners( + number, bets) + + # Pay out to the winners and send a notification. + for user_id in winners: + gambler = get_account(user_id) + gambler_payout = payouts[user_id] + coin_winnings = gambler_payout['coins'] + procoin_winnings = gambler_payout['procoins'] + + setattr(gambler, 'coins', gambler.coins + coin_winnings) + setattr(gambler, 'procoins', gambler.procoins + procoin_winnings) + + g.db.add(gambler) + + # Notify the winners. + notification_text = f"Winning number: {number}\nCongratulations! One or more of your roulette bets paid off!\n" + + if coin_winnings > 0: + notification_text = notification_text + \ + f"* You received {coin_winnings} dramacoins.\n" + + if procoin_winnings > 0: + notification_text = notification_text + \ + f"* You received {procoin_winnings} marseybux.\n" + + send_repeatable_notification(user_id, notification_text) + + # Give condolences. + for participant in participants: + if not participant in winners: + send_repeatable_notification( + participant, f"Winning number: {number}\nSorry, none of your recent roulette bets paid off.") + + g.db.flush() + + # Adjust game winnings. + for game in active_games: + if rewards_by_game_id.get(game.id): + game.winnings = rewards_by_game_id[game.id] + else: + game.winnings = -game.wager + + game.active = False + g.db.add(game) + + +def determine_roulette_winners(number, bets): + winners = [] + payouts = {} + rewards_by_game_id = {} + + def add_to_winnings(bet): + game_id = int(bet['game_id']) + gambler_id = bet['gambler'] + wager_amount = bet['wager']['amount'] + bet_kind = bet['bet'] + reward = wager_amount * PAYOUT_MULITPLIERS[bet_kind] + payout = wager_amount + reward + currency = bet['wager']['currency'] + + if not gambler_id in winners: + winners.append(gambler_id) + + if not payouts.get(gambler_id): + payouts[gambler_id] = { + 'coins': 0, + 'procoins': 0 + } + + if not rewards_by_game_id.get(game_id): + rewards_by_game_id[game_id] = reward + + payouts[gambler_id][currency] += payout + + # Straight-Up Bet + for bet in bets[RouletteAction.STRAIGHT_UP_BET]: + if int(bet['which']) == number: + add_to_winnings(bet) + + # Line Bet + line = -1 + for i in range(1, 7): + if number in LINES[i]: + line = i + + for bet in bets[RouletteAction.LINE_BET]: + if int(bet['which']) == line: + add_to_winnings(bet) + + # Column Bet + column = -1 + for i in range(1, 4): + if number in COLUMNS[i]: + column = i + + for bet in bets[RouletteAction.COLUMN_BET]: + if int(bet['which']) == column: + add_to_winnings(bet) + + # Dozen Bet + dozen = -1 + for i in range(1, 4): + if number in DOZENS[i]: + dozen = i + + for bet in bets[RouletteAction.DOZEN_BET]: + if int(bet['which']) == dozen: + add_to_winnings(bet) + + # Even/Odd Bet + even_odd = RouletteEvenOdd.EVEN if number % 2 == 0 else RouletteEvenOdd.ODD + + for bet in bets[RouletteAction.EVEN_ODD_BET]: + if bet['which'] == even_odd: + add_to_winnings(bet) + + # Red/Black Bet + red_black = RouletteRedBlack.RED if number in REDS else RouletteRedBlack.BLACK + + for bet in bets[RouletteAction.RED_BLACK_BET]: + if bet['which'] == red_black: + add_to_winnings(bet) + + # High/Low Bet + high_low = RouletteHighLow.HIGH if number > 18 else RouletteHighLow.LOW + + for bet in bets[RouletteAction.HIGH_LOW_BET]: + if bet['which'] == high_low: + add_to_winnings(bet) + + return winners, payouts, rewards_by_game_id + + +def get_roulette_bets(): + return get_roulette_bets_and_betters()[1] diff --git a/files/helpers/twentyone.py b/files/helpers/twentyone.py index ca181506d..fc57abaad 100644 --- a/files/helpers/twentyone.py +++ b/files/helpers/twentyone.py @@ -1,8 +1,6 @@ import json -from locale import currency from math import floor import random -from functools import reduce from enum import Enum from files.classes.casino_game import Casino_Game from flask import g @@ -362,6 +360,7 @@ def get_value_of_hand(hand): return max(possibilities) + def get_available_actions(state): actions = [] @@ -371,8 +370,8 @@ def get_available_actions(state): if can_double_down(state): actions.append(BlackjackAction.DOUBLE_DOWN) - + if can_purchase_insurance(state): actions.append(BlackjackAction.BUY_INSURANCE) - return actions \ No newline at end of file + return actions diff --git a/files/routes/casino.py b/files/routes/casino.py index cec14ee71..bb367828a 100644 --- a/files/routes/casino.py +++ b/files/routes/casino.py @@ -8,32 +8,26 @@ from files.helpers.slots import * from files.helpers.lottery import * from files.helpers.casino import * from files.helpers.twentyone import * +from files.helpers.roulette import * @app.get("/casino") @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def casino(v): - if v.rehab: return render_template("casino/rehab.html", v=v) + if v.rehab: + return render_template("casino/rehab.html", v=v) + return render_template("casino.html", v=v) -@app.get("/lottershe") -@limiter.limit("100/minute;2000/hour;12000/day") -@auth_required -def lottershe(v): - if v.rehab: return render_template("casino/rehab.html", v=v) - participants = get_users_participating_in_lottery() - return render_template("lottery.html", v=v, participants=participants) - - - @app.get("/casino/") @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def casino_game_page(v, game): - if v.rehab: return render_template("casino/rehab.html", v=v) - + if v.rehab: + return render_template("casino/rehab.html", v=v) + feed = json.dumps(get_game_feed(game)) leaderboard = json.dumps(get_game_leaderboard(game)) @@ -50,15 +44,31 @@ def casino_game_page(v, game): @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def casino_game_feed(v, game): + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 + feed = get_game_feed(game) return {"feed": feed} +# Lottershe +@app.get("/lottershe") +@limiter.limit("100/minute;2000/hour;12000/day") +@auth_required +def lottershe(v): + if v.rehab: + return render_template("casino/rehab.html", v=v) + + participants = get_users_participating_in_lottery() + return render_template("lottery.html", v=v, participants=participants) + +# Slots @app.post("/casino/slots") @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def pull_slots(v): - if v.rehab: return {"error": "You are under Rehab award effect!"}, 400 + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 try: wager = int(request.values.get("wager")) @@ -81,11 +91,13 @@ def pull_slots(v): return {"error": f"Wager must be more than 5 {currency}."}, 400 +# 21 @app.post("/casino/twentyone/deal") @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def blackjack_deal_to_player(v): - if v.rehab: return {"error": "You are under Rehab award effect!"}, 400 + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 try: wager = int(request.values.get("wager")) @@ -94,17 +106,18 @@ def blackjack_deal_to_player(v): state = dispatch_action(v, BlackjackAction.DEAL) feed = get_game_feed('blackjack') - return {"success": True, "state": state, "feed": feed} + return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}} except Exception as e: - return {"error": str(e)} + return {"error": str(e)}, 400 @app.post("/casino/twentyone/hit") @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def blackjack_player_hit(v): - if v.rehab: return {"error": "You are under Rehab award effect!"}, 400 - + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 + try: state = dispatch_action(v, BlackjackAction.HIT) feed = get_game_feed('blackjack') @@ -117,7 +130,8 @@ def blackjack_player_hit(v): @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def blackjack_player_stay(v): - if v.rehab: return {"error": "You are under Rehab award effect!"}, 400 + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 try: state = dispatch_action(v, BlackjackAction.STAY) @@ -131,7 +145,8 @@ def blackjack_player_stay(v): @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def blackjack_player_doubled_down(v): - if v.rehab: return {"error": "You are under Rehab award effect!"}, 400 + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 try: state = dispatch_action(v, BlackjackAction.DOUBLE_DOWN) @@ -145,7 +160,8 @@ def blackjack_player_doubled_down(v): @limiter.limit("100/minute;2000/hour;12000/day") @auth_required def blackjack_player_bought_insurance(v): - if v.rehab: return {"error": "You are under Rehab award effect!"}, 400 + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 try: state = dispatch_action(v, BlackjackAction.BUY_INSURANCE) @@ -153,3 +169,40 @@ def blackjack_player_bought_insurance(v): return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}} except: return {"error": "Unable to buy insurance."}, 400 + +# Roulette +@app.get("/casino/roulette/bets") +@limiter.limit("100/minute;2000/hour;12000/day") +@auth_required +def roulette_get_bets(v): + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 + + bets = get_roulette_bets() + + return {"success": True, "bets": bets, "gambler": {"coins": v.coins, "procoins": v.procoins}} + + +@app.post("/casino/roulette/place-bet") +@limiter.limit("100/minute;2000/hour;12000/day") +@auth_required +def roulette_player_placed_bet(v): + if v.rehab: + return {"error": "You are under Rehab award effect!"}, 400 + + try: + bet = request.values.get("bet") + which = request.values.get("which") + amount = int(request.values.get("wager")) + currency = request.values.get("currency") + + if amount < 5: + return {"error": f"Minimum bet is 5 {currency}."} + + gambler_placed_roulette_bet(v, bet, which, amount, currency) + + bets = get_roulette_bets() + + return {"success": True, "bets": bets, "gambler": {"coins": v.coins, "procoins": v.procoins}} + except: + return {"error": "Unable to place a bet."}, 400 \ No newline at end of file diff --git a/files/templates/casino.html b/files/templates/casino.html index b0699e21b..27ab08de9 100644 --- a/files/templates/casino.html +++ b/files/templates/casino.html @@ -3,6 +3,12 @@ {# Title (~25char max), Description (~80char max), Icon (fa-foo-bar), Color (#ff0000), URL (/post/12345/) #} {%- set GAME_INDEX = [ + ( + 'Roulette', + 'Round and round the wheel of fate turns', + 'fa-circle', '#999', + '/casino/roulette', + ), ( 'Slots', 'Today\'s your lucky day', diff --git a/files/templates/casino/blackjack_screen.html b/files/templates/casino/blackjack_screen.html index 38776c086..d8389be54 100644 --- a/files/templates/casino/blackjack_screen.html +++ b/files/templates/casino/blackjack_screen.html @@ -23,6 +23,7 @@ if (succeeded) { updateBlackjackTable(response.state); updateFeed(response.feed); + updatePlayerCurrencies(response.gambler); } else { console.error("Error: ", response.error); throw new Error("Error") diff --git a/files/templates/casino/game_screen.html b/files/templates/casino/game_screen.html index 6362debc5..e51717407 100644 --- a/files/templates/casino/game_screen.html +++ b/files/templates/casino/game_screen.html @@ -66,7 +66,7 @@ ).value; const genericCurrency = currency == 'marseybux' ? 'procoins' : 'coins'; - return { amount, currency: genericCurrency }; + return { amount, currency: genericCurrency, localCurrency: currency }; } function disableWager() { @@ -82,6 +82,7 @@ } function updateResult(text, className) { + clearResult(); const result = document.getElementById("casinoGameResult"); result.style.visibility = "visible"; result.innerText = text; @@ -396,7 +397,7 @@
-
Actions
+
{% block actiontext %}Actions{% endblock %}

{% block actions %} {% endblock %} diff --git a/files/templates/casino/roulette_screen.html b/files/templates/casino/roulette_screen.html new file mode 100644 index 000000000..09bb0c299 --- /dev/null +++ b/files/templates/casino/roulette_screen.html @@ -0,0 +1,578 @@ +{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %} + +{% block script %} + +{% endblock %} + +{% block screen %} + + +
+
+{% endblock %} + +{% block actiontext %} +Bets +{% endblock %} + +{% block actions %} +
+
+
+
+ + +
+

111 is betting 4 and 4: +

+
+
    +
  • 2 coin that + the number will be black.
  • +
  • 2 coin that + the number will be even.
  • +
+
+
+ +
+
How to Bet
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BetPayoutDescription
Straight Up35:1 + Click any single number.
+ You win if the roulette lands on that number. +
Line5:1 + Click Line 1, Line 2 ... Line 6.
+ You win if the roulette lands on any of the six numbers beneath the line. +
Column2:1 + Click Col 1, Col 2 or Col 3.
+ You win if the roulette lands on any of the 12 numbers to the left of the column. +
Dozen2:1 + Click 1st12, 2nd12 or 3rd12.
+ You win if the roulette lands on a number within 1-12, 13-24 or 25-36, respectively. +
Even/Odd1:1 + Click EVEN or ODD.
+ You win if the roulette lands on a number that matches your choice. +
Red/Black1:1 + Click RED or BLACK.
+ You win if the roulette lands on a number that is the same color as your choice. +
High/Low1:1 + Click 1:18 or 19:36.
+ You win if the roulette lands on a number within your selected range. +
+{% endblock %} \ No newline at end of file diff --git a/sql/20220911-add-roulette.sql b/sql/20220911-add-roulette.sql new file mode 100644 index 000000000..154f61459 --- /dev/null +++ b/sql/20220911-add-roulette.sql @@ -0,0 +1 @@ +ALTER TYPE casino_game_kind ADD VALUE 'roulette'; \ No newline at end of file