forked from rDrama/rDrama
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 tablemaster
parent
e0d32c7105
commit
7d8cfe5576
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
|
@ -14,12 +14,13 @@ def get_game_feed(game):
|
|||
def format_game(game):
|
||||
user = g.db.query(User).filter(User.id == game.user_id).one()
|
||||
wonlost = 'lost' if game.winnings < 0 else 'won'
|
||||
relevant_currency = "dramacoin" if game.currency == "coins" else "marseybux"
|
||||
|
||||
return {
|
||||
"user": user.username,
|
||||
"won_or_lost": wonlost,
|
||||
"amount": abs(game.winnings),
|
||||
"currency": game.currency
|
||||
"currency": relevant_currency
|
||||
}
|
||||
|
||||
return list(map(format_game, games))
|
||||
|
@ -80,7 +81,3 @@ def get_game_leaderboard(game):
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_game_stats_for_player(player):
|
||||
pass
|
||||
|
|
|
@ -2,6 +2,7 @@ from files.cli import g, app, db_session
|
|||
import click
|
||||
from files.helpers.const import *
|
||||
from files.helpers.alerts import send_repeatable_notification
|
||||
from files.helpers.roulette import spin_roulette_wheel
|
||||
from files.helpers.get import *
|
||||
from files.helpers.actions import *
|
||||
from files.classes import *
|
||||
|
@ -28,6 +29,7 @@ def cron(every_5m, every_1h, every_1d, every_1mo):
|
|||
if every_5m:
|
||||
lottery.check_if_end_lottery_task()
|
||||
offsitementions.offsite_mentions_task()
|
||||
spin_roulette_wheel()
|
||||
|
||||
if every_1h:
|
||||
awards.award_timers_bots_task()
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
import json
|
||||
from random import randint
|
||||
from enum import Enum
|
||||
from files.helpers.alerts import *
|
||||
from files.classes.casino_game import Casino_Game
|
||||
from files.helpers.get import get_account
|
||||
from flask import g
|
||||
|
||||
|
||||
class RouletteAction(str, Enum):
|
||||
STRAIGHT_UP_BET = "STRAIGHT_UP_BET"
|
||||
LINE_BET = "LINE_BET"
|
||||
COLUMN_BET = "COLUMN_BET"
|
||||
DOZEN_BET = "DOZEN_BET"
|
||||
EVEN_ODD_BET = "EVEN_ODD_BET"
|
||||
RED_BLACK_BET = "RED_BLACK_BET"
|
||||
HIGH_LOW_BET = "HIGH_LOW_BET"
|
||||
|
||||
|
||||
class RouletteEvenOdd(str, Enum):
|
||||
EVEN = "EVEN"
|
||||
ODD = "ODD"
|
||||
|
||||
|
||||
class RouletteRedBlack(str, Enum):
|
||||
RED = "RED"
|
||||
BLACK = "BLACK"
|
||||
|
||||
|
||||
class RouletteHighLow(str, Enum):
|
||||
HIGH = "HIGH"
|
||||
LOW = "LOW"
|
||||
|
||||
|
||||
REDS = (1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36)
|
||||
BLACKS = (2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35)
|
||||
LINES = {
|
||||
1: (1, 2, 3, 4, 5, 6),
|
||||
2: (7, 8, 9, 10, 11, 12),
|
||||
3: (13, 14, 15, 16, 17, 18),
|
||||
4: (19, 20, 21, 22, 23, 24),
|
||||
5: (25, 26, 27, 28, 29, 30),
|
||||
6: (31, 32, 33, 34, 35, 36)
|
||||
}
|
||||
COLUMNS = {
|
||||
1: (1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34),
|
||||
2: (2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35),
|
||||
3: (3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36)
|
||||
}
|
||||
DOZENS = {
|
||||
1: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
|
||||
2: (13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24),
|
||||
3: (25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36)
|
||||
}
|
||||
PAYOUT_MULITPLIERS = {
|
||||
RouletteAction.STRAIGHT_UP_BET: 35,
|
||||
RouletteAction.LINE_BET: 5,
|
||||
RouletteAction.COLUMN_BET: 2,
|
||||
RouletteAction.DOZEN_BET: 2,
|
||||
RouletteAction.EVEN_ODD_BET: 1,
|
||||
RouletteAction.RED_BLACK_BET: 1,
|
||||
RouletteAction.HIGH_LOW_BET: 1,
|
||||
}
|
||||
|
||||
|
||||
def get_active_roulette_games():
|
||||
return g.db.query(Casino_Game).filter(
|
||||
Casino_Game.active == True,
|
||||
Casino_Game.kind == 'roulette'
|
||||
).all()
|
||||
|
||||
|
||||
def charge_gambler(gambler, amount, currency):
|
||||
currency_gambler_holds = getattr(gambler, currency)
|
||||
can_afford = currency_gambler_holds >= 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]
|
|
@ -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
|
||||
return actions
|
||||
|
|
|
@ -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/<game>")
|
||||
@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
|
|
@ -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',
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 @@
|
|||
</div>
|
||||
<div class="col">
|
||||
<div class="game_screen-title">
|
||||
<h5>Actions</h5>
|
||||
<h5>{% block actiontext %}Actions{% endblock %}</h5>
|
||||
<hr />
|
||||
</div>
|
||||
{% block actions %} {% endblock %}
|
||||
|
|
|
@ -0,0 +1,578 @@
|
|||
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script type="text/javascript">
|
||||
if (
|
||||
document.readyState === "complete" ||
|
||||
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
||||
) {
|
||||
initializeGame();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", initializeGame);
|
||||
}
|
||||
|
||||
// Kiss my ass if you're judgin'
|
||||
const CELL_TO_NUMBER_LOOKUP = {
|
||||
1: 3,
|
||||
2: 6,
|
||||
3: 9,
|
||||
4: 12,
|
||||
5: 15,
|
||||
6: 18,
|
||||
7: 21,
|
||||
8: 24,
|
||||
9: 27,
|
||||
10: 30,
|
||||
11: 33,
|
||||
12: 36,
|
||||
13: 2,
|
||||
14: 5,
|
||||
15: 8,
|
||||
16: 11,
|
||||
17: 14,
|
||||
18: 17,
|
||||
19: 20,
|
||||
20: 23,
|
||||
21: 26,
|
||||
22: 29,
|
||||
23: 32,
|
||||
24: 35,
|
||||
25: 1,
|
||||
26: 4,
|
||||
27: 7,
|
||||
28: 10,
|
||||
29: 13,
|
||||
30: 16,
|
||||
31: 19,
|
||||
32: 22,
|
||||
33: 25,
|
||||
34: 28,
|
||||
35: 31,
|
||||
36: 34
|
||||
};
|
||||
|
||||
function initializeGame() {
|
||||
buildRouletteTable();
|
||||
updateResult("Rolls occur every five minutes", "success");
|
||||
requestRouletteBets();
|
||||
}
|
||||
|
||||
function buildRouletteTable() {
|
||||
const table = document.getElementById('roulette-table');
|
||||
const reds = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
|
||||
|
||||
let html = "";
|
||||
|
||||
// Lines
|
||||
html += `
|
||||
<div class="roulette-table-row">
|
||||
<div id="LINE_BET#1" onclick="placeChip('LINE_BET', '1')" class="roulette-table-1to1">Line 1</div>
|
||||
<div id="LINE_BET#2" onclick="placeChip('LINE_BET', '2')" class="roulette-table-1to1">Line 2</div>
|
||||
<div id="LINE_BET#3" onclick="placeChip('LINE_BET', '3')" class="roulette-table-1to1">Line 3</div>
|
||||
<div id="LINE_BET#4" onclick="placeChip('LINE_BET', '4')" class="roulette-table-1to1">Line 4</div>
|
||||
<div id="LINE_BET#5" onclick="placeChip('LINE_BET', '5')" class="roulette-table-1to1">Line 5</div>
|
||||
<div id="LINE_BET#6" onclick="placeChip('LINE_BET', '6')" class="roulette-table-1to1">Line 6</div>
|
||||
<div style="flex: 1"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// First Column
|
||||
html += "<div class=\"roulette-table-row\">";
|
||||
for (let i = 1; i < 13; i++) {
|
||||
const isRed = reds.includes(i);
|
||||
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
||||
html += `<div
|
||||
id="STRAIGHT_UP_BET#${correctNumber}"
|
||||
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
||||
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
||||
${correctNumber}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
html += `<div id="COLUMN_BET#3" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '3')">Col 3</div>`;
|
||||
html += "</div>";
|
||||
|
||||
// Second Column
|
||||
html += "<div class=\"roulette-table-row\">";
|
||||
for (let i = 13; i < 25; i++) {
|
||||
const isRed = reds.includes(i);
|
||||
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
||||
html += `<div
|
||||
id="STRAIGHT_UP_BET#${correctNumber}"
|
||||
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
||||
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
||||
${correctNumber}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
html += `<div id="COLUMN_BET#2" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '2')">Col 2</div>`;
|
||||
html += "</div>";
|
||||
|
||||
// Third Column
|
||||
html += "<div class=\"roulette-table-row\">";
|
||||
for (let i = 25; i < 37; i++) {
|
||||
const isRed = reds.includes(i);
|
||||
const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
|
||||
html += `<div
|
||||
id="STRAIGHT_UP_BET#${correctNumber}"
|
||||
onclick="placeChip('STRAIGHT_UP_BET', '${correctNumber}')"
|
||||
class="roulette-table-number roulette-table-number__${isRed ? 'red' : 'black'}">
|
||||
${correctNumber}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
html += `<div id="COLUMN_BET#1" class="roulette-table-column" onclick="placeChip('COLUMN_BET', '1')">Col 1</div>`;
|
||||
html += "</div>";
|
||||
|
||||
// Line Bets and 1:1 Bets
|
||||
html += `
|
||||
<div class="roulette-table-row">
|
||||
<div id="DOZEN_BET#1" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '1')">1st12</div>
|
||||
<div id="DOZEN_BET#2" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '2')">2nd12</div>
|
||||
<div id="DOZEN_BET#3" class="roulette-table-line" onclick="placeChip('DOZEN_BET', '3')">3rd12</div>
|
||||
<div style="flex: 1"></div>
|
||||
</div>
|
||||
<div class="roulette-table-row">
|
||||
<div id="HIGH_LOW_BET#LOW" class="roulette-table-1to1" onclick="placeChip('HIGH_LOW_BET', 'LOW')">1:18</div>
|
||||
<div id="EVEN_ODD_BET#EVEN" class="roulette-table-1to1" onclick="placeChip('EVEN_ODD_BET', 'EVEN')">EVEN</div>
|
||||
<div id="RED_BLACK_BET#RED" class="roulette-table-1to1" onclick="placeChip('RED_BLACK_BET', 'RED')" style="background-color: red">RED</div>
|
||||
<div id="RED_BLACK_BET#BLACK" class="roulette-table-1to1" onclick="placeChip('RED_BLACK_BET', 'BLACK')" style="background-color: black">BLACK</div>
|
||||
<div id="EVEN_ODD_BET#ODD" class="roulette-table-1to1" onclick="placeChip('EVEN_ODD_BET', 'ODD')">ODD</div>
|
||||
<div id="HIGH_LOW_BET#HIGH" class="roulette-table-1to1" onclick="placeChip('HIGH_LOW_BET', 'HIGH')">19:36</div>
|
||||
<div style="flex: 1"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
table.innerHTML = html;
|
||||
}
|
||||
|
||||
function formatFlatBets(bets) {
|
||||
let flatBets = [];
|
||||
|
||||
for (const betCollection of Object.values(bets)) {
|
||||
flatBets = flatBets.concat(betCollection)
|
||||
}
|
||||
|
||||
return flatBets;
|
||||
}
|
||||
|
||||
function formatNormalizedBets(bets) {
|
||||
const normalizedBets = {
|
||||
gamblers: [],
|
||||
gamblersByName: {}
|
||||
};
|
||||
const flatBets = formatFlatBets(bets);
|
||||
|
||||
for (const bet of flatBets) {
|
||||
if (!normalizedBets.gamblers.includes(bet.gambler_username)) {
|
||||
normalizedBets.gamblers.push(bet.gambler_username);
|
||||
}
|
||||
|
||||
if (!normalizedBets.gamblersByName[bet.gambler_username]) {
|
||||
normalizedBets.gamblersByName[bet.gambler_username] = {
|
||||
name: bet.gambler_username,
|
||||
avatar: bet.gambler_profile_url,
|
||||
profile: `/@${bet.gambler_username}`,
|
||||
wagerTotal: {
|
||||
coins: 0,
|
||||
procoins: 0
|
||||
},
|
||||
wagers: []
|
||||
}
|
||||
}
|
||||
|
||||
const entry = normalizedBets.gamblersByName[bet.gambler_username];
|
||||
|
||||
entry.wagerTotal[bet.wager.currency] += bet.wager.amount;
|
||||
|
||||
const existingWager = entry.wagers.find(wager => wager.bet === bet.bet && wager.which === bet.which);
|
||||
|
||||
if (existingWager) {
|
||||
existingWager.amounts[bet.wager.currency] += bet.wager.amount;
|
||||
} else {
|
||||
const newEntry = {
|
||||
bet: bet.bet,
|
||||
which: bet.which,
|
||||
amounts: {
|
||||
coins: 0,
|
||||
procoins: 0
|
||||
},
|
||||
};
|
||||
newEntry.amounts[bet.wager.currency] += bet.wager.amount;
|
||||
|
||||
entry.wagers.push(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedBets;
|
||||
}
|
||||
|
||||
function buildPokerChip(avatar) {
|
||||
return `
|
||||
<div class="roulette-poker-chip">
|
||||
<img src="/i/pokerchip.webp" width="40" height="40" />
|
||||
<img src="${avatar}" width="40" height="40" />
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function buildRouletteBets(bets) {
|
||||
const betArea = document.getElementById("roulette-bets");
|
||||
const flatBets = formatFlatBets(bets);
|
||||
const normalizedBets = formatNormalizedBets(bets);
|
||||
const dramacoinImgHtml = `
|
||||
<img
|
||||
src="/i/rDrama/coins.webp?v=3009"
|
||||
alt="coin"
|
||||
width="32"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title=""
|
||||
aria-label="Dramacoin"
|
||||
data-bs-original-title="Dramacoin" />
|
||||
`;
|
||||
const marseybuxImgHtml = `
|
||||
<img
|
||||
src="/i/marseybux.webp?v=2000"
|
||||
alt="marseybux"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title=""
|
||||
aria-label="Marseybux"
|
||||
width="32" class="mr-1 ml-1"
|
||||
data-bs-original-title="Marseybux" />
|
||||
`;
|
||||
const { participants, dramacoin, marseybux } = flatBets.reduce((prev, next) => {
|
||||
if (!prev.participants.includes(next.gambler_username)) {
|
||||
prev.participants.push(next.gambler_username);
|
||||
}
|
||||
|
||||
if (next.wager.currency == 'coins') {
|
||||
prev.dramacoin += next.wager.amount;
|
||||
} else {
|
||||
prev.marseybux += next.wager.amount;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, { participants: [], dramacoin: 0, marseybux: 0 });
|
||||
const dramacoinText = `${dramacoin} ${dramacoinImgHtml}`;
|
||||
const marseybuxText = `${marseybux} ${marseybuxImgHtml}`;
|
||||
const playerText = participants.length > 1 ? `${participants.length} players are` : `1 player is`;
|
||||
const totalText = dramacoin && marseybux ? `${dramacoinText} and ${marseybuxText}` : dramacoin ? dramacoinText : marseybuxText;
|
||||
const fullTotalText = participants.length === 0 ? "No one has placed a bet" : `${playerText} betting a total of ${totalText}`;
|
||||
|
||||
let betHtml = `
|
||||
<small class="roulette-total-bets">${fullTotalText}</small>
|
||||
<hr />
|
||||
`;
|
||||
|
||||
for (player of normalizedBets.gamblers) {
|
||||
const { name, avatar, wagerTotal, wagers } = normalizedBets.gamblersByName[player];
|
||||
|
||||
betHtml += `<div class="roulette-bet-summary">`;
|
||||
// Heading
|
||||
betHtml += ` <div class="roulette-bet-summary--heading">`;
|
||||
betHtml += buildPokerChip(avatar);
|
||||
const coinText = wagerTotal.coins > 0 ? `${wagerTotal.coins} ${dramacoinImgHtml}` : "";
|
||||
const procoinText = wagerTotal.procoins > 0 ? `${wagerTotal.procoins} ${marseybuxImgHtml}` : "";
|
||||
const bettingText = coinText && procoinText ? `${coinText} and ${procoinText}` : coinText || procoinText;
|
||||
betHtml += `<p>${name} is betting ${bettingText}:</p>`;
|
||||
betHtml += ` </div>`;
|
||||
|
||||
// Individual bets
|
||||
betHtml += `<ul class="roulette-bet-summary--list">`;
|
||||
for (const individualBet of wagers) {
|
||||
const coinText = individualBet.amounts.coins > 0 ? `${individualBet.amounts.coins} ${dramacoinImgHtml}` : "";
|
||||
const procoinText = individualBet.amounts.procoins > 0 ? `${individualBet.amounts.procoins} ${marseybuxImgHtml}` : "";
|
||||
const details = {
|
||||
STRAIGHT_UP_BET: `that the number will be ${individualBet.which}`,
|
||||
LINE_BET: `that the number will be within line ${individualBet.which}`,
|
||||
COLUMN_BET: `that the number will be within column ${individualBet.which}`,
|
||||
DOZEN_BET: `that the number will be within dozen ${individualBet.which}`,
|
||||
EVEN_ODD_BET: `that the number will be ${individualBet.which.toLowerCase()}`,
|
||||
RED_BLACK_BET: `that the color of the number will be ${individualBet.which.toLowerCase()}`,
|
||||
HIGH_LOW_BET: `that the number will be ${individualBet.which === "HIGH" ? "higher than 18" : "lower than 19"}`
|
||||
}
|
||||
const betText = coinText && procoinText ? `${coinText} and ${procoinText}` : coinText || procoinText;
|
||||
|
||||
betHtml += `<li>${betText} ${details[individualBet.bet]}</li>`;
|
||||
}
|
||||
betHtml += `</ul>`;
|
||||
betHtml += `</div>`;
|
||||
}
|
||||
|
||||
betArea.innerHTML = betHtml;
|
||||
}
|
||||
|
||||
function placeChip(bet, which) {
|
||||
const { amount, currency: safeCurrency, localCurrency: currency } = getWager();
|
||||
const texts = {
|
||||
STRAIGHT_UP_BET: `Bet ${amount} ${currency} on ${which}?\nYou could win ${amount * 35} ${currency}.`,
|
||||
LINE_BET: `Bet ${amount} ${currency} on line ${which}?\nYou could win ${amount * 5} ${currency}.`,
|
||||
COLUMN_BET: `Bet ${amount} ${currency} column ${which}?\nYou could win ${amount * 2} ${currency}.`,
|
||||
DOZEN_BET: `Bet ${amount} ${currency} dozen ${which}?\nYou could win ${amount * 2} ${currency}.`,
|
||||
EVEN_ODD_BET: `Bet ${amount} ${currency} that the number will be ${which.toLowerCase()}?\nYou could win ${amount} ${currency}.`,
|
||||
RED_BLACK_BET: `Bet ${amount} ${currency} that the number will be ${which.toLowerCase()}?\nYou could win ${amount} ${currency}.`,
|
||||
HIGH_LOW_BET: `Bet ${amount} ${currency} that the number will be ${which === "HIGH" ? "higher than 18" : "lower than 19"}?\nYou could win ${amount} ${currency}.`,
|
||||
}
|
||||
const text = texts[bet] || "";
|
||||
const confirmed = window.confirm(text);
|
||||
|
||||
if (confirmed) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/casino/roulette/place-bet");
|
||||
xhr.onload = handleRouletteResponse.bind(null, xhr);
|
||||
|
||||
const form = new FormData();
|
||||
form.append("formkey", formkey());
|
||||
form.append("bet", bet);
|
||||
form.append("which", which);
|
||||
form.append("wager", amount);
|
||||
form.append("currency", safeCurrency);
|
||||
|
||||
xhr.send(form);
|
||||
}
|
||||
}
|
||||
|
||||
function addChipsToTable(bets) {
|
||||
const flatBets = formatFlatBets(bets);
|
||||
|
||||
for (const bet of flatBets) {
|
||||
const tableElement = document.getElementById(`${bet.bet}#${bet.which}`);
|
||||
tableElement.style.position = 'relative';
|
||||
const count = tableElement.dataset.count ? parseInt(tableElement.dataset.count) + 1 : 1;
|
||||
tableElement.dataset.count = count;
|
||||
|
||||
const chip = buildPokerChip(bet.gambler_profile_url)
|
||||
tableElement.innerHTML = `${tableElement.innerHTML}<div style="position: absolute; bottom: ${count + 2}px; left: -${count + 2}px; transform: scale(0.5);">${chip}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function requestRouletteBets() {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("get", "/casino/roulette/bets");
|
||||
xhr.onload = handleRouletteResponse.bind(null, xhr);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function handleRouletteResponse(xhr) {
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = JSON.parse(xhr.response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
const succeeded =
|
||||
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
|
||||
|
||||
if (succeeded) {
|
||||
buildRouletteBets(response.bets);
|
||||
addChipsToTable(response.bets);
|
||||
updatePlayerCurrencies(response.gambler);
|
||||
updateResult("Rolls occur every five minutes", "success");
|
||||
} else {
|
||||
updateResult("Unable to place that bet.", "danger");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block screen %}
|
||||
<style>
|
||||
.roulette-table-number {
|
||||
flex: 1;
|
||||
height: 60px;
|
||||
border: 1px solid white;
|
||||
background: green;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.roulette-table-number__black {
|
||||
background: black;
|
||||
}
|
||||
|
||||
.roulette-table-number__red {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.roulette-table-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.roulette-table-column {
|
||||
flex: 1;
|
||||
height: 60px;
|
||||
border: 1px solid white;
|
||||
background: green;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: bolder;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: sideways;
|
||||
}
|
||||
|
||||
.roulette-table-line,
|
||||
.roulette-table-1to1 {
|
||||
border: 1px solid white;
|
||||
background: green;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.roulette-table-line {
|
||||
flex: 4;
|
||||
}
|
||||
|
||||
.roulette-table-1to1 {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.roulette-poker-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.roulette-bet-summary--heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.roulette-bet-summary--heading p {
|
||||
margin: 0;
|
||||
margin-left: 1rem;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.roulette-bet-summary--list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.roulette-poker-chip img:last-child {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.roulette-total-bets {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="roulette-table">
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block actiontext %}
|
||||
Bets
|
||||
{% endblock %}
|
||||
|
||||
{% block actions %}
|
||||
<div id="roulette-bets">
|
||||
<div class="roulette-bet-summary">
|
||||
<div class="roulette-bet-summary--heading">
|
||||
<div class="roulette-poker-chip">
|
||||
<img src="/i/pokerchip.webp" width="40" height="40" />
|
||||
<img src="/e/marseycodecellove.webp" width="40" height="40" />
|
||||
</div>
|
||||
<p>111 is betting 4 and 4:
|
||||
</p>
|
||||
</div>
|
||||
<ul class="roulette-bet-summary--list">
|
||||
<li>2 <img src="/i/rDrama/coins.webp?v=3009" alt="coin" width="32" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom" title="" aria-label="Dramacoin" data-bs-original-title="Dramacoin"> that
|
||||
the number will be black.</li>
|
||||
<li>2 <img src="/i/rDrama/coins.webp?v=3009" alt="coin" width="32" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom" title="" aria-label="Dramacoin" data-bs-original-title="Dramacoin"> that
|
||||
the number will be even.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="game_screen-title">
|
||||
<h5>How to Bet</h5>
|
||||
<hr />
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bet</th>
|
||||
<th>Payout</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Straight Up</td>
|
||||
<td>35:1</td>
|
||||
<td>
|
||||
Click any single number. <br />
|
||||
You win if the roulette lands on that number.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Line</td>
|
||||
<td>5:1</td>
|
||||
<td>
|
||||
Click Line 1, Line 2 ... Line 6. <br />
|
||||
You win if the roulette lands on any of the six numbers beneath the line.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Column</td>
|
||||
<td>2:1</td>
|
||||
<td>
|
||||
Click Col 1, Col 2 or Col 3. <br />
|
||||
You win if the roulette lands on any of the 12 numbers to the left of the column.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dozen</td>
|
||||
<td>2:1</td>
|
||||
<td>
|
||||
Click 1st12, 2nd12 or 3rd12. <br />
|
||||
You win if the roulette lands on a number within 1-12, 13-24 or 25-36, respectively.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Even/Odd</td>
|
||||
<td>1:1</td>
|
||||
<td>
|
||||
Click EVEN or ODD. <br />
|
||||
You win if the roulette lands on a number that matches your choice.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Red/Black</td>
|
||||
<td>1:1</td>
|
||||
<td>
|
||||
Click RED or BLACK. <br />
|
||||
You win if the roulette lands on a number that is the same color as your choice.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>High/Low</td>
|
||||
<td>1:1</td>
|
||||
<td>
|
||||
Click 1:18 or 19:36. <br />
|
||||
You win if the roulette lands on a number within your selected range.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
|
@ -0,0 +1 @@
|
|||
ALTER TYPE casino_game_kind ADD VALUE 'roulette';
|
Loading…
Reference in New Issue