Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
b91af2c
fixed issue with cmdMute where it would fail with certain arguments.
noittaM Feb 15, 2024
a6b51be
Merge branch 'LevBernstein:main' into main
noittaM May 7, 2024
f4a06fc
Merge branch 'LevBernstein:main' into main
noittaM Jul 14, 2024
f226045
Made the changes clearer and more concise.
noittaM Jul 14, 2024
74977dc
made PEP8 compliant
noittaM Jul 14, 2024
f2abc9d
indent comments with spaces rather than tabs
noittaM Jul 14, 2024
751de6c
Merge remote-tracking branch 'upstream/main'
Sep 29, 2025
efebb57
Merge branch 'LevBernstein:main' into main
noittaM Nov 14, 2025
304bfdf
Added new class BlackjackPlayer
Nov 15, 2025
ea23b40
Updated class BlackjackGame to allow for multiplayer games
Nov 15, 2025
37d7f8d
Updated function active_game()
Nov 15, 2025
3de420d
Made function make_bet() and move some logic from blackjack() to it
Nov 15, 2025
dad006a
Added missing message for a path in BlackjackGame.stay()
Nov 15, 2025
3e20738
Moved duplicate messages into InvalidBetMsg
Nov 16, 2025
906194b
Fixed runtime error: UnboundLocalError in make_bet()
Nov 16, 2025
f466213
Updated cmd_deal() and cmd_stay() to handle multiplayer games
Nov 16, 2025
64c5a40
Added new command !bet to place a bet for your current bj round
Nov 16, 2025
62e9e19
Added missing reporting in cmd_bet()
Nov 16, 2025
602ba5a
Improved reporting in check_bust()
Nov 16, 2025
a6eea54
Renamed function active_game() to player_in_game()
Nov 16, 2025
d37674d
Changed type of BlackjackPlayer.bet from int | str -> int
Nov 16, 2025
058ecf3
Changed command to start a multiplayer blackjack game 'bj new' -> 'ta…
Nov 17, 2025
bfaa1a1
Added a field 'match_started' to class BlackjackGame
Nov 17, 2025
f127a88
Added new method add_player() to class BlackjackGame
Nov 17, 2025
6a6fe70
Added new command 'jointable'
Nov 17, 2025
d4f5b5a
Update BlackjackPlayer.done where appropriate
Nov 18, 2025
3182801
Renamed field in BlackjackGame: match_started -> started
Nov 18, 2025
c5a65c5
Added method BlackjackGame.ready_to_start()
Nov 18, 2025
9723c9f
Added field BlackjackGame.turn_idx and method BlackjackGame.is_turn()
Nov 18, 2025
9aaaa6b
Renamed method in BlackjackGame: starting_hand() -> start_game()
Nov 18, 2025
1b890c8
Added new command tablestart to start a multiplayer blackjack game
Nov 18, 2025
c074bda
Implemented turns, and multiplayer blackjack games now end properly
Nov 18, 2025
6464f57
Better reporting in cmd_join()
Nov 18, 2025
e755db2
Disallowed joining games started with 'blackjack' command
Nov 18, 2025
a43ba45
Moved match initialization of BlackjackGame from __init__() to start_…
Nov 19, 2025
196ee3c
Added method BlackjackGame.end_round()
Nov 19, 2025
0d56b7e
Removed field BlackjackPlayer.done
Nov 20, 2025
8dce1eb
Made class DealReportParams to separate reporting from logic
Nov 21, 2025
9e617cc
Added missing return type annotations
Nov 21, 2025
4ac99a3
Use DealReportParams
Nov 21, 2025
dfe2e81
Update BlackjackGame.end_round() and it's usages
Nov 21, 2025
1bf1ba4
Fixed reporting in DealReportParams.make_report()
Nov 21, 2025
587bcec
Updated function BlackjackGame.advance_turn()
Nov 21, 2025
9fcd0cb
Fixed issue in function make_bet()
Nov 21, 2025
591ac71
Removed reporting code from BlackjackGame.stay_current_player()
Nov 21, 2025
22ea2fa
Fixed tests
Nov 21, 2025
058a03d
Added method BlackjackGame.round_over()
Nov 23, 2025
f5cf476
Updated method BlackjackGame.advance_turn()
Nov 23, 2025
1b2777f
Updated method BlackjackGame.end_round()
Nov 23, 2025
6a51973
Made cmd_stay() and cmd_deal() only end multiplayer round when it's over
Nov 23, 2025
20de903
Improved reporting in BlackjackGame.end_round()
Nov 23, 2025
9ae96a5
Now calling write_money() and BlackjackGame.advance_turn() for all pl…
Nov 23, 2025
d904cdc
Created new function can_make_bet()
Nov 24, 2025
dc7af2a
Use can_make_bet() in cmd_bet() to ensure bet validity
Nov 24, 2025
23aed54
Implemented new function bucks.money_in_bank()
Nov 26, 2025
76043f8
Moved checking of comma in username to top level functions Bot.cmd_xx()
Nov 26, 2025
4a56470
Added missing .format()s
Nov 27, 2025
9f7c9cd
Made bucks.reset() return 'str' instead of 'nextcord.Embed'
Nov 27, 2025
4a16302
Fixed bug where match wouldn't end if player blackjacked in singleplayer
Nov 27, 2025
da39e6b
Refactored bucks.blackjack()
Nov 27, 2025
e88fd18
You can no longer reset while in a blackjack game
Nov 28, 2025
0d0a4bc
You can now only '!bet' while in a multiplayer bj game that's not sta…
Nov 28, 2025
8d29da5
Made new command, '!tableleave'
Nov 28, 2025
5ec458a
Improvements to the game's card pool.
Nov 29, 2025
26a542e
Added TODO
Nov 29, 2025
8d4975b
Unified command names
Nov 29, 2025
aa86f61
Updated tests to work with new code.
Nov 29, 2025
e25fd31
Made write_money always return what the user has in their bank after
Dec 1, 2025
002e116
Updated test_blackjack_deal_top_card_pops_top_card()
Dec 1, 2025
c1c3985
Reversed some of the changes to the cardpool
Dec 1, 2025
5c5133b
Making formatters happy: Volume 1
Dec 4, 2025
c5af1cd
Very messy commit.
Dec 4, 2025
14e038a
Fixed tests.
Dec 4, 2025
a79a434
fixed more tests
Dec 6, 2025
943cb55
Fixed issue where you could !bj while not having enough bucks
Dec 8, 2025
5b7c2ab
Improved reporting.
Dec 8, 2025
98cfbf4
Moved win and lose messages to a variable.
Dec 14, 2025
62b10b1
Fixed tests
Dec 16, 2025
056dd28
Reset turn_idx when match is started
Dec 18, 2025
a52ed95
Use bucks.write_money() immediately instead of managing BlackjackPlay…
Dec 18, 2025
307aab9
Fixed bug with BlackjackGame._force_end_round().
Dec 19, 2025
af92971
Better reporting when player blackjacks in singleplayer
Dec 19, 2025
dd228a9
Removed extra write_money call
Dec 29, 2025
e109ec3
Better documentation: Volume 1
Dec 29, 2025
05b94ad
Improved reporting
Dec 29, 2025
1ad5fc1
Removed DealReportsParams bucause I sure ain't refactoring around it
Dec 30, 2025
5a864d0
Stopped using BlackjackGame.message in BlackjackGame._end_round()
Dec 30, 2025
14ed961
Fixed test
Dec 30, 2025
4589abc
Fixed issue with test_blackjack.
Dec 31, 2025
e19db28
Better documentation: Volume 2
Dec 31, 2025
ebf923b
Fixed spelling mistakes
Dec 31, 2025
9921e95
Added test bb_test.py::test_add_player_get_player_and_ready_to_start
Jan 5, 2026
3f5b589
Removed unused code in test_add_player_get_player_and_ready_to_start
Jan 5, 2026
85e73dd
Added new test test_is_turn_and_advance_turn_skips_perfect_players
Jan 5, 2026
9424bb5
Added new test test_dealer_draw_stops_at_dealer_soft_goal
Jan 5, 2026
58c5062
Fixed issue with BlackjackGame.is_turn()
Jan 5, 2026
c8ddfe3
Fixed issue with test_cmd_deal where it would fail if dealer blackjacked
Jan 5, 2026
94a8020
Test coverage stuff
Jan 5, 2026
5030d0d
Removed unused function arg in test_dealer_draw_stops_at_dealer_soft_…
Jan 9, 2026
9fef43f
Added a todo, and fixed mypy typing error
Jan 10, 2026
d7e935a
Fixed mypy typing errors
Jan 10, 2026
57d48be
Moved game help message to a variable and slightly changed reporting
Jan 10, 2026
6a69bc9
Fixed issues with BlackjackGame._start_game_regular()
Jan 10, 2026
72372e1
Typo
Jan 10, 2026
459ceaf
Improved reporting
Jan 15, 2026
ebc099d
Added tests
Jan 15, 2026
41bf39e
Making formatters happy: Volume 2 & Better documentation: Volume 3
Jan 15, 2026
a6c84d1
Made test_blackjack and test_blackjack_starting_hand more deterministic
Jan 16, 2026
c861403
Fixed reporting bug when an unregistered user does '!balance'
Jan 18, 2026
8eefe12
Better reporting
Jan 18, 2026
0907c11
Making formatters happy: Volume 3 (Final)
Jan 18, 2026
f60e72c
Updated resources/
Jan 18, 2026
c73ec96
Merge branch 'LevBernstein:main' into main
Jan 18, 2026
07b2abd
Disallowed leaving/joining while a 'round' is ongoing
Jan 18, 2026
84a05de
Making formatters happy: Volume 4 (postlude)
Jan 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 208 additions & 34 deletions Bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,29 +327,121 @@ async def on_thread_update(
async def cmd_flip(ctx: misc.BotContext, bet: str = "10") -> int:
if misc.ctx_created_thread(ctx):
return -1
report = (
bucks.FinMsg.format(ctx.author.mention)
if bucks.active_game(BlackjackGames, ctx.author)
else bucks.flip(ctx.author, bet.lower())
)
if "," in ctx.author.name:
report = bucks.CommaWarn.format(ctx.author.mention)
else:
report = (
bucks.FinMsg.format(ctx.author.mention)
if bucks.player_in_game(BlackjackGames, ctx.author)
else bucks.flip(ctx.author, bet.lower())
)
await ctx.send(embed=misc.bb_embed("Beardless Bot Coin Flip", report))
return 1


# NOTE: duplicate code
@BeardlessBot.command(name="blackjack", aliases=("bj",))
async def cmd_blackjack(ctx: misc.BotContext, bet: str = "10") -> int:
if misc.ctx_created_thread(ctx):
return -1
if bucks.active_game(BlackjackGames, ctx.author):
if "," in ctx.author.name:
report = bucks.CommaWarn.format(ctx.author.mention)
elif bucks.player_in_game(BlackjackGames, ctx.author):
report = bucks.FinMsg.format(ctx.author.mention)
else:
can_bet, bet_report = bucks.can_make_bet(ctx.author, bet)
if not can_bet:
assert bet_report is not None
report = bet_report
else:
report, game = bucks.blackjack(ctx.author, bet)
if game and not game.round_over():
BlackjackGames.append(game)
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1


@BeardlessBot.command(name="tableleave")
async def cmd_tableleave(ctx: misc.BotContext) -> int:
if misc.ctx_created_thread(ctx):
return -1
if result := bucks.player_in_game(BlackjackGames, ctx.author):
game, player = result
if not game.multiplayer:
report = (
"You can't exit a singlelpayer Blackjack Game"
f"{ctx.author.mention}\n"
)
elif game.started:
report = "Cannot leave mid-round. Please wait for the round to end."
elif len(game.players) == 1:
BlackjackGames.remove(game)
report = "Game disbanded.\n"
elif player == game.owner:
assert game.owner == game.players[0]
game.players.remove(player)
game.owner = game.players[0]
report = (
f"You left. {game.owner.name.mention} "
"you are now the owner of the game.\n"
)
else:
game.players.remove(player)
report = "You left.\n"
else:
report = bucks.NoMultiplayerGameMsg.format(ctx.author.mention)
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1


# NOTE: duplicate code
@BeardlessBot.command(name="tablenew")
async def cmd_tablenew(ctx: misc.BotContext) -> int:
if misc.ctx_created_thread(ctx):
return -1
if "," in ctx.author.name:
report = bucks.CommaWarn.format(ctx.author.mention)
if bucks.player_in_game(BlackjackGames, ctx.author):
report = bucks.FinMsg.format(ctx.author.mention)
else:
report, game = bucks.blackjack(ctx.author, bet)
report, game = bucks.blackjack(ctx.author, None)
if game:
BlackjackGames.append(game)
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1


@BeardlessBot.command(name="tablebet")
async def cmd_tablebet(ctx: misc.BotContext, bet: str = "10") -> int:
if misc.ctx_created_thread(ctx):
return -1
report: str | None
if "," in ctx.author.name:
report = bucks.CommaWarn.format(ctx.author.mention)
else:
report = bucks.NoMultiplayerGameMsg.format(ctx.author.mention)
if result := bucks.player_in_game(BlackjackGames, ctx.author):
game, player = result
if game.multiplayer:
if game.started:
report = "Cannot change bet mid-round."
else:
can_bet, report = bucks.can_make_bet(ctx.author, bet)
if can_bet:
report, bet_number = bucks.make_bet(
ctx.author,
game, bet,
)
report = (
"Your current bet is "
f"{bet_number}\n{ctx.author.mention}"
)
player.bet = bet_number
assert report is not None
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1


@BeardlessBot.command(name="deal", aliases=("hit",))
async def cmd_deal(ctx: misc.BotContext) -> int:
if misc.ctx_created_thread(ctx):
Expand All @@ -358,18 +450,85 @@ async def cmd_deal(ctx: misc.BotContext) -> int:
report = bucks.CommaWarn.format(ctx.author.mention)
else:
report = bucks.NoGameMsg.format(ctx.author.mention)
if game := bucks.active_game(BlackjackGames, ctx.author):
report = game.deal_to_player()
if game.check_bust() or game.perfect():
game.check_bust()
bucks.write_money(
ctx.author, game.bet, writing=True, adding=True,
)
BlackjackGames.remove(game)
if result := bucks.player_in_game(BlackjackGames, ctx.author):
game, player = result
if not game.started:
report = "Game has not started yet"
elif not game.is_turn(player):
report = f"It is not your turn {ctx.author.mention}"
else:
assert game.dealerUp is not None
report = game.deal_current_player()
if (
(player.check_bust() or player.perfect())
and not game.multiplayer
):
BlackjackGames.remove(game)
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1


@BeardlessBot.command(name="tablestart")
async def cmd_tablestart(ctx: misc.BotContext) -> int:
if misc.ctx_created_thread(ctx):
return -1
report = bucks.NoGameMsg.format(ctx.author.mention)
if result := bucks.player_in_game(BlackjackGames, ctx.author):
game, player = result
if game.owner is not player:
report = "You are not the owner of this table"
elif not game.ready_to_start():
report = "Not all players have made their bets"
else:
report = "Match started\n"
report += game.start_game()
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1


@BeardlessBot.command(name="tablejoin")
async def cmd_tablejoin(
ctx: misc.BotContext,
target: str | None = None,
) -> int:
if misc.ctx_created_thread(ctx) or not ctx.guild:
return -1
if "," in ctx.author.name:
report = bucks.CommaWarn.format(ctx.author.mention)
else:
if not (join_target := await misc.process_command_target(
ctx, target, BeardlessBot,
)):
return 0
if result := bucks.player_in_game(BlackjackGames, ctx.author):
report = bucks.FinMsg.format(ctx.author.mention)
elif result := bucks.player_in_game(BlackjackGames, join_target):
game, _ = result
if game.multiplayer:
if game.started:
game.add_player(ctx.author)
report = f"Joined {join_target.mention}'s blackjack game."
else:
report = (
f"Cannot join {join_target.mention}'s "
"blackjack game mid-round. "
"Please wait for the round to end."
)
else:
report = (
f"Can't join {join_target.mention}'s "
"singleplayer blackjack game."
)
else:
report = f"Player {join_target.mention} is not in a blackjack game"
await ctx.send(embed=misc.bb_embed("Beardless Bot Join", report))
# if channel := misc.get_log_channel(ctx.guild):
# await channel.send(embed=logs.log_mute(
# join_target, ctx.message, duration,
# ))
return 1


@BeardlessBot.command(name="stay", aliases=("stand",))
async def cmd_stay(ctx: misc.BotContext) -> int:
if misc.ctx_created_thread(ctx):
Expand All @@ -378,17 +537,16 @@ async def cmd_stay(ctx: misc.BotContext) -> int:
report = bucks.CommaWarn.format(ctx.author.mention)
else:
report = bucks.NoGameMsg.format(ctx.author.mention)
if game := bucks.active_game(BlackjackGames, ctx.author):
result = game.stay()
report = game.message
if result and game.bet:
written, bonus = bucks.write_money(
ctx.author, game.bet, writing=True, adding=True,
)
if written == bucks.MoneyFlags.CommaInUsername:
assert isinstance(bonus, str)
report = bonus
BlackjackGames.remove(game)
if result := bucks.player_in_game(BlackjackGames, ctx.author):
game, player = result
if not game.started:
report = "Game has not started yet"
elif not game.is_turn(player):
report = f"It is not your turn {ctx.author.mention}"
else:
report = game.stay_current_player()
if not game.multiplayer:
BlackjackGames.remove(game)
await ctx.send(embed=misc.bb_embed("Beardless Bot Blackjack", report))
return 1

Expand Down Expand Up @@ -434,9 +592,14 @@ async def cmd_balance(ctx: misc.BotContext, *, target: str = "") -> int:
async def cmd_leaderboard(ctx: misc.BotContext, *, target: str = "") -> int:
if misc.ctx_created_thread(ctx):
return -1
await ctx.send(
embed=bucks.leaderboard(misc.get_target(ctx, target), ctx.message),
)
if "," in ctx.author.name:
embed = misc.bb_embed(
"BeardlessBot Comma Warn",
bucks.CommaWarn.format(ctx.author.mention),
)
else:
embed = bucks.leaderboard(misc.get_target(ctx, target), ctx.message)
await ctx.send(embed=embed)
return 1


Expand Down Expand Up @@ -469,7 +632,21 @@ async def cmd_reset(ctx: misc.BotContext) -> int:
"""
if misc.ctx_created_thread(ctx):
return -1
await ctx.send(embed=bucks.reset(ctx.author))
if "," in ctx.author.name:
report = bucks.CommaWarn.format(ctx.author.mention)
else:
game = None
if result := bucks.player_in_game(BlackjackGames, ctx.author):
game, player = result
if game is None:
report = bucks.reset(ctx.author)
elif game.multiplayer and not game.started:
player.bet = 10 # TODO: move the default bet to a variable
report = bucks.reset(ctx.author)
report += " Your bet has also been reset to 10."
else:
report = bucks.FinMsg.format(ctx.author.mention)
await ctx.send(embed=misc.bb_embed("BeardlessBucks Reset", report))
return 1


Expand Down Expand Up @@ -845,17 +1022,14 @@ async def cmd_buy(
else:
if not role.color.value:
await role.edit(colour=nextcord.Colour(RoleColors[color]))
result, bonus = bucks.write_money(
result, _ = bucks.write_money(
ctx.author, -50000, writing=True, adding=True,
)
if result == bucks.MoneyFlags.BalanceChanged:
report = (
"Color " + role.mention + " purchased successfully, {}!"
)
await ctx.author.add_roles(role)
elif result == bucks.MoneyFlags.CommaInUsername:
assert isinstance(bonus, str)
report = bonus
elif result == bucks.MoneyFlags.Registered:
report = bucks.NewUserMsg
else:
Expand Down
Loading
Loading