Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
f5b0548
Initial plan
Copilot Jul 19, 2025
40551ec
Implement core casino system with database, service, and command infr…
Copilot Jul 19, 2025
5fe4d0d
Fix double down betting logic to only deduct additional bet amount
Copilot Jul 19, 2025
7b0b82e
Fix Insight.Database transaction parameter conflict by renaming Inser…
Copilot Jul 19, 2025
87d600d
Add comprehensive error handling and logging to casino blackjack inte…
Copilot Jul 19, 2025
7d3d752
Fix component interaction pattern matching for casino blackjack buttons
Copilot Jul 19, 2025
43580a6
✨ Update component interaction patterns for casino commands
Pierre-Demessence Jul 19, 2025
ae53982
Fix all interactions components
Pierre-Demessence Jul 20, 2025
514d611
Use DisplayName in leaderboard
Pierre-Demessence Jul 20, 2025
fe55a13
Added custom bet button
Pierre-Demessence Jul 20, 2025
9c3488c
✨ Enhance token history command with admin user support
Pierre-Demessence Jul 20, 2025
423ddbd
✨ Update betting embed for Blackjack game
Pierre-Demessence Jul 20, 2025
b6bfb76
🔧 Remove unnecessary defer for reset command
Pierre-Demessence Jul 20, 2025
55d1140
Fix formatting
Pierre-Demessence Jul 20, 2025
af31984
✨ Refactor transaction history display logic
Pierre-Demessence Jul 20, 2025
afdf471
✨ Update token history commands for improved access
Pierre-Demessence Jul 20, 2025
941caba
✨ Enhance logging for casino commands
Pierre-Demessence Jul 20, 2025
3a1e132
🔧 Remove logging statements from StartBlackjackGame and CompleteBlack…
Pierre-Demessence Jul 20, 2025
cace47c
✨ Clean up whitespace and improve code readability
Pierre-Demessence Jul 20, 2025
6702824
- 🔒 Disable "Double Down" button if user lacks sufficient tokens
Pierre-Demessence Jul 20, 2025
65b852b
✨ Refactor Blackjack game handling and improve logging
Pierre-Demessence Jul 20, 2025
d37f11f
✨ Enhance Blackjack game flow with auto-win feature
Pierre-Demessence Jul 20, 2025
fd9d50d
- ⏳ Adjust delay for dealer's turn to enhance user experience
Pierre-Demessence Jul 20, 2025
0cee6ab
✨ Refactor Blackjack game embed creation for improved readability
Pierre-Demessence Jul 20, 2025
947bd7d
✨ Update Blackjack game logic for auto-win scenario
Pierre-Demessence Jul 20, 2025
5e8e542
✨ Adjust delay for dealer's turn in Blackjack game from 2000ms to 100…
Pierre-Demessence Jul 20, 2025
5cfdbd8
✨ Update Blackjack game logic allow double down at any turn
Pierre-Demessence Jul 20, 2025
3831fd6
✨ Add detailed rules for Blackjack game
Pierre-Demessence Jul 20, 2025
e508327
Dealer gets two cards initially instead of just 1
Pierre-Demessence Jul 20, 2025
02581a6
✨ Enhance dealer turn experience in Blackjack game
Pierre-Demessence Jul 20, 2025
f44fc58
✨ Implement dealer soft 17 rule in Blackjack game
Pierre-Demessence Jul 20, 2025
18eba4a
✨ Refactor Blackjack game logic and introduce BlackjackService
Pierre-Demessence Jul 20, 2025
a0b79a6
🃏 Change title from "🃏 Blackjack Game" to "🃏 Blackjack - Your Turn" i…
Pierre-Demessence Jul 20, 2025
a51f935
✨ Update Blackjack game logic and token management
Pierre-Demessence Jul 20, 2025
0d00823
Refactor CasinoSlashModule: Remove blackjack commands and related met…
Pierre-Demessence Jul 20, 2025
8389f0e
✨ Implement daily token reward system
Pierre-Demessence Jul 20, 2025
7f3f928
✨ Refactor Blackjack game and introduce card system
Pierre-Demessence Jul 20, 2025
792eb4e
✨ Enhance Card and Deck classes to support Jokers
Pierre-Demessence Jul 20, 2025
437026f
✨ Refactor Blackjack game structure and introduce generic ActiveGame …
Pierre-Demessence Jul 20, 2025
1073636
✨ Update dealer card display in Blackjack game description
Pierre-Demessence Jul 20, 2025
ff002cc
✨ Remove asynchronous logging on service initialization in Blackjack …
Pierre-Demessence Jul 20, 2025
46b0842
Moved files
Pierre-Demessence Jul 20, 2025
ecf396f
Moved files again
Pierre-Demessence Jul 20, 2025
b6b4a5d
✨ Refactor transaction handling and introduce TransactionType enum
Pierre-Demessence Jul 20, 2025
f0d660d
✨ Enhance token transaction handling and details storage
Pierre-Demessence Jul 21, 2025
fbdcb79
🔍 Add current balance description in transaction history embed for be…
Pierre-Demessence Jul 21, 2025
cd74ee2
Refactored CasinoSlashModule.Blackjack and BlackjackService into Casi…
Pierre-Demessence Jul 26, 2025
56d2373
✨ Update .NET Core version in GitHub Actions workflow from 6.0.x to 8…
Pierre-Demessence Jul 26, 2025
430e109
✨ Fix: Shuffle the deck at the start of the Blackjack game
Pierre-Demessence Jul 26, 2025
5d00557
✨ Refactor: Simplify object initialization in Blackjack and Deck classes
Pierre-Demessence Jul 26, 2025
7886bd5
✨ Enhance: Improve error messaging for game session seat validation
Pierre-Demessence Jul 26, 2025
1f05fd2
✨ Enhance: Skip AI players when updating user tokens after game ends
Pierre-Demessence Jul 26, 2025
1d558d8
✨ Fix: Update current player selection logic to include blackjack check
Pierre-Demessence Jul 26, 2025
c741726
✨ Fix: Adjust player game result logic to prioritize player bust check
Pierre-Demessence Jul 26, 2025
dd9dbc1
Remove last bot instead of first bot
Pierre-Demessence Jul 26, 2025
fc463eb
✨ Enhance: Improve player and dealer action descriptions in game state
Pierre-Demessence Jul 26, 2025
5300f45
✨ Enhance: Add GameName property to IGameSession interface and use it…
Pierre-Demessence Jul 26, 2025
3352195
✨ Enhance: Implement JoinGame method in GameService and update JoinGa…
Pierre-Demessence Jul 26, 2025
abc85f4
✨ Change title format to "Game of" before the emoji and game name
Pierre-Demessence Jul 26, 2025
1fcb145
Merge branch 'master' into copilot/fix-339
Pierre-Demessence Jul 26, 2025
eed5e91
Refactor GameService to remove hardcoded Blackjack session creation
Copilot Jul 26, 2025
ef39000
Add Rock Paper Scissors casino game with 2-player support and 2-minut…
Copilot Jul 26, 2025
f8f7c6e
Add casino game statistics command showing wins/losses and profit ana…
Copilot Jul 26, 2025
870e508
Fix rules
Pierre-Demessence Jul 26, 2025
487bcb5
Reworked results so it's factorized
Pierre-Demessence Jul 26, 2025
f4dc81e
Added AI to RPS
Pierre-Demessence Jul 26, 2025
dcdf554
Removed obsolete comments
Pierre-Demessence Jul 26, 2025
3760ad7
✨ Refactor Blackjack and RockPaperScissors game session descriptions
Pierre-Demessence Jul 26, 2025
60bfcb8
✨ Update game finish logic for better state management
Pierre-Demessence Jul 26, 2025
2787e2d
✨ Simplify CurrentPlayer property and refactor GetPlayerGameResult logic
Pierre-Demessence Jul 26, 2025
affcecf
- 🎮 Implemented auto-start check when adding AI players
Pierre-Demessence Jul 26, 2025
d82d8e1
Reworked code that handle AIAction, DealerAction and FinishGame, so i…
Pierre-Demessence Jul 26, 2025
7d5deae
Reworked RPS choice showing
Pierre-Demessence Jul 26, 2025
8344329
✨ Update payout calculation to include total pot
Pierre-Demessence Jul 26, 2025
928690b
Don't show blackjack for Dealer since we don't handle it
Pierre-Demessence Jul 26, 2025
7dd0ede
Fix dealer and AI playing before game even start
Pierre-Demessence Jul 26, 2025
0b44233
Fixed statistics
Pierre-Demessence Jul 26, 2025
16243b2
Reworked stats a bit
Pierre-Demessence Jul 26, 2025
559d36d
✨ Update daily reward logic for new users
Pierre-Demessence Jul 26, 2025
d58617c
✨ Update token balance message with additional commands
Pierre-Demessence Jul 26, 2025
0574947
✨ Enhance daily reward notifications
Pierre-Demessence Jul 26, 2025
d334bb6
🃏 Implement Five Card Draw Poker game with private hands and card sel…
Copilot Jul 26, 2025
5be2aa3
Modified Show hand a bit
Pierre-Demessence Jul 26, 2025
2541414
✨ Add ButtonMetadata attribute for game actions
Pierre-Demessence Jul 26, 2025
0e78576
Fix text issue
Pierre-Demessence Jul 26, 2025
5ccec2f
Fix emoji for action buttons
Pierre-Demessence Jul 26, 2025
031a4e9
Added simple AI that doesn't Discard for poker
Pierre-Demessence Jul 26, 2025
0b4ee5d
Removed useless code
Pierre-Demessence Jul 26, 2025
b6ba261
Simplified getter
Pierre-Demessence Jul 26, 2025
a2d3b1f
Fix possible null errors
Pierre-Demessence Jul 26, 2025
8af7b6b
Reworked whole UI of Poker
Pierre-Demessence Jul 26, 2025
d05451f
✨ Sort player cards in descending order for better visibility for Poker
Pierre-Demessence Jul 26, 2025
cfc785a
Way faster bot action
Pierre-Demessence Jul 26, 2025
75980de
✨ Add "Add FULL AI" button and corresponding interaction
Pierre-Demessence Jul 26, 2025
32db210
✨ Improve hand evaluation and winner determination in Poker game
Pierre-Demessence Jul 26, 2025
ce5d0e7
✨ Enhance Poker player actions with button metadata labels
Pierre-Demessence Jul 26, 2025
50bfc6d
✨ Update game description to show selected cards for discard
Pierre-Demessence Jul 26, 2025
68cb856
✨ Upgrade Dockerfile to use .NET SDK and runtime version 8.0
Pierre-Demessence Jul 26, 2025
8f08477
AI buttons are enabled by DEBUG flag
Pierre-Demessence Jul 26, 2025
b80a097
Fix issue with buttons labels
Pierre-Demessence Jul 26, 2025
4d0f7bb
Cleaned code
Pierre-Demessence Jul 26, 2025
2eb5229
Removed deepsource
Pierre-Demessence Jul 26, 2025
ca2b62b
Removed deepsource.toml
Pierre-Demessence Jul 26, 2025
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
5 changes: 0 additions & 5 deletions .deepsource.toml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/Dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x

- name: Install dependencies
run: dotnet restore
Expand Down
5 changes: 3 additions & 2 deletions DiscordBot/DiscordBot.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>10</LangVersion>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Insight.Database" Version="8.0.5" />
Expand Down
4 changes: 4 additions & 0 deletions DiscordBot/Domain/Casino/AIAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public class AIAction
{
public Func<Task> Execute { get; set; }
}
83 changes: 83 additions & 0 deletions DiscordBot/Domain/Casino/CasinoUser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Newtonsoft.Json;

namespace DiscordBot.Domain;

public class CasinoUser
{
public int Id { get; set; }
public string UserID { get; set; }
public ulong Tokens { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public DateTime LastDailyReward { get; set; }
}

public class TokenTransaction
{
public int Id { get; set; }
public string UserID { get; set; }
public long Amount { get; set; } // Can be negative for spending
public TransactionType Type { get; set; } // Enum for transaction types

private Dictionary<string, string> _details;

[JsonIgnore]
public Dictionary<string, string> Details
{
get => _details;
set => _details = value;
}

// This property will be mapped to the database JSON column
public string DetailsJson
{
get => Details != null && Details.Any() ? JsonConvert.SerializeObject(Details) : null;
Comment thread
Pierre-Demessence marked this conversation as resolved.
set => Details = !string.IsNullOrEmpty(value) ? JsonConvert.DeserializeObject<Dictionary<string, string>>(value) : new Dictionary<string, string>();
}

public DateTime CreatedAt { get; set; }
}

public enum TransactionType
{
TokenInitialisation,
DailyReward,
Gift,
Game,
Admin,
}

public class GameStatistics
{
public string GameName { get; set; }
public int TotalGames { get; set; }
public int Wins { get; set; }
public int Losses { get; set; }
public double WinPercentage { get; set; }
public long TotalWinAmount { get; set; }
public long TotalLossAmount { get; set; }
public long NetProfit { get; set; }
public double AverageProfit { get; set; }
}

public static class CasinoProps
{
public const string CasinoTableName = "casino_users";
public const string TransactionTableName = "token_transactions";

// CasinoUser properties
public const string Id = nameof(CasinoUser.Id);
public const string UserID = nameof(CasinoUser.UserID);
public const string Tokens = nameof(CasinoUser.Tokens);
public const string CreatedAt = nameof(CasinoUser.CreatedAt);
public const string UpdatedAt = nameof(CasinoUser.UpdatedAt);
public const string LastDailyReward = nameof(CasinoUser.LastDailyReward);

// TokenTransaction properties
public const string TransactionId = nameof(TokenTransaction.Id);
public const string TransactionUserID = nameof(TokenTransaction.UserID);
public const string Amount = nameof(TokenTransaction.Amount);
public const string TransactionType = nameof(TokenTransaction.Type);
public const string Details = nameof(TokenTransaction.DetailsJson);
public const string TransactionCreatedAt = nameof(TokenTransaction.CreatedAt);
}
127 changes: 127 additions & 0 deletions DiscordBot/Domain/Casino/Discord/BlackjackDiscordGameSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using Discord.WebSocket;
using DiscordBot.Domain;

public class BlackjackDiscordGameSession : DiscordGameSession<Blackjack>
{
public BlackjackDiscordGameSession(Blackjack game, int maxSeats, DiscordSocketClient client, SocketUser user, IGuild guild)
: base(game, maxSeats, client, user, guild)
{ }

private new string GetCurrentPlayerName()
{
if (Game.CurrentPlayer == null) return "Dealer";
return GetPlayerName((DiscordGamePlayer)Game.CurrentPlayer);
}

private string GenerateTurnDescription()
{
var description = "";

description += $"**Hands:**\n";
foreach (var p in Players)
{
var playerBet = p.Bet;
var playerCards = string.Join(" ", Game.GameData[p].PlayerCards.Select(c => c.GetDisplayName()));
var playerHand = $"{playerCards} (Value: {Game.GetPlayerValue(p)})";
if (Game.IsPlayerBusted(p)) playerHand += $" **- BUSTED!**";
if (Game.IsPlayerBlackjack(p)) playerHand += " **- BLACKJACK!**";
if (Game.GameData[p].Actions.LastOrDefault() == BlackjackPlayerAction.Stand) playerHand += $" **- STANDING**";

var actions = "";
if (Game.GameData[p].Actions.Count > 0)
actions = string.Join(", ", Game.GameData[p].Actions.Select(a => a.ToString()));

description += GeneratePlayerHandDescription(p, playerHand, actions);
}

description += "\n";

var isDealerTurn = CurrentPlayer == null;
var dealerCards = isDealerTurn
? string.Join(" ", Game.DealerCards.Select(c => c.GetDisplayName()))
// Only show the first card's value until it's the dealer's turn
: $"{Game.DealerCards.First().GetDisplayName()} ?";

var dealerValue = isDealerTurn
? Game.GetDealerValue().ToString()
// Only show the first card's value until it's the dealer's turn
: $"{Game.DealerCards.First().Value}?";

description += $"* **Dealer**: {dealerCards} (Value: {dealerValue})";
if (Game.IsDealerBusted()) description += " **- BUSTED!**";
// if (Game.IsDealerBlackjack()) description += " **- BLACKJACK!**";
if (Game.DealerActions.LastOrDefault() == BlackjackPlayerAction.Stand) description += " **- STANDING**";

description += "\n";
// List dealer actions
if (Game.DealerActions.Count > 0)
description += $"-# {string.Join(", ", Game.DealerActions.Select(a => a.ToString()))}";
else
description += "\n";

description += "\n";

return description;
}

protected override Embed GenerateInProgressEmbed()
{
var description = GenerateTurnDescription();

return new EmbedBuilder()
.WithTitle($"Game of {Game.Emoji} {GameName}")
.WithDescription(description)
.AddField("CurrentPlayer", GetCurrentPlayerName(), true)
.Build();
}

protected override Embed GenerateFinishedEmbed()
{
var description = GenerateTurnDescription();
description += GenerateResultsDescription();

return new EmbedBuilder()
.WithTitle($"{Game.Emoji} {GameName} Finished")
.WithDescription(description)
.Build();
}

public override Embed GenerateRules()
{
return base.GenerateRules()
.ToEmbedBuilder()
.WithDescription("**Objective:** Get as close to 21 as possible without going over, while beating the dealer's hand.\nType `/casino blackjack` to start playing!")
.AddField("🎯 **Card Values**",
"• **Number cards (2-10):** Face value\n" +
"• **Face cards (J, Q, K):** 10 points\n" +
"• **Ace:** 11 or 1 (whichever is better)", false)
.AddField("🎮 **How to Play**",
"1. Place your bet using the betting buttons\n" +
"2. You and the dealer each get 2 cards\n" +
"3. Your cards are shown, dealer shows only 1 card\n" +
"4. Choose your action: **Hit**, **Stand**, or **Double Down**", false)
.AddField("🔥 **Actions**",
"• **Hit:** Take another card\n" +
"• **Stand:** Keep your current hand and pass the turn to the dealer\n" +
"• **Double Down:** Double your bet, take exactly 1 more card, then stand", false)
.AddField("🏆 **Winning Conditions**",
"• **Blackjack:** 21 with first 2 cards (Ace + 10-value card)\n" +
"• **Regular Win:** Your total is closer to 21 than dealer's\n" +
"• **Dealer Bust:** Dealer goes over 21\n" +
"• **Push/Tie:** Same total as dealer", false)
.AddField("💥 **Losing Conditions**",
"• **Bust:** Your total goes over 21\n" +
"• **Dealer Wins:** Dealer's total is closer to 21 than yours", false)
.AddField("💰 **Payouts**",
"• **Win/Dealer Bust:** 2x your bet\n" +
"• **Push/Tie:** Get your bet back\n" +
"• **Bust/Loss:** Lose your bet", false)
.AddField("⚡ **Special Rules**",
"• If you hit exactly 21 (not blackjack), the dealer automatically plays\n" +
"• Dealer hits until 17 or more, after which they stand\n" +
"• Dealer hits on a \"soft 17\" (17 with an Ace counted as 11)\n" +
"• Games expire after 5 minutes of inactivity", false)
.Build();
}

}
106 changes: 106 additions & 0 deletions DiscordBot/Domain/Casino/Discord/PokerDiscordGameSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using Discord.WebSocket;
using DiscordBot.Domain;

public class PokerDiscordGameSession : DiscordGameSession<Poker>
{
public PokerDiscordGameSession(Poker game, int maxSeats, DiscordSocketClient client, SocketUser user, IGuild guild)
: base(game, maxSeats, client, user, guild)
{ }

private string GenerateGameDescription()
{
var description = "**Five Card Draw Poker** - Each player gets 5 cards and can discard up to 5 cards once.\n\n";

description += "**Players:**\n";
foreach (var p in Players)
{
var playerData = Game.GameData[p];
var status = playerData.HasDiscarded ? "✅ Finished" : (Game.CurrentPlayer == p ? "🎯 Playing" : "⏳ Waiting");

if (State == GameState.Finished)
{
status = string.Join(" ", Game.GameData[p].PlayerCards.OrderByDescending(c => c).Select(c => c.GetDisplayName()));
var playerHand = Game.GameData[p].FinalHand;
if (playerHand != null)
{
status += $" - **{playerHand.Description}**";
}
}

description += GeneratePlayerHandDescription(p, status, "");
}

if (Game.CurrentPlayer != null)
{
description += $"\n**{GetCurrentPlayerName()} selected cards for discard:** \n";
var currentPlayerData = Game.GameData[Game.CurrentPlayer];
for (int i = 0; i < currentPlayerData.PlayerCards.Count; i++)
{
var isSelected = currentPlayerData.SelectedForDiscard[i];
description += $"{(isSelected ? "✅" : "❌")} 🃏 ";
}
description += "\n*Use the 'Show Hand' button to see your cards privately.*\n";
description += "*Select cards you want to discard, then click 'Confirm Discard'.*";
}

return description;
}

protected override Embed GenerateInProgressEmbed()
{
var description = GenerateGameDescription();

var embed = new EmbedBuilder()
.WithTitle($"🃏 {GameName} Game")
.WithDescription(description)
.WithColor(Color.Blue)
.AddField("Current Player", GetCurrentPlayerName(), true);

return embed.Build();
}

protected override Embed GenerateFinishedEmbed()
{
var description = GenerateGameDescription();
description += GenerateResultsDescription();

return new EmbedBuilder()
.WithTitle($"🃏 {GameName} Finished")
.WithDescription(description)
.WithColor(Color.Gold)
.AddField("Total Pot", $"{GetTotalPot} tokens", true)
.Build();
}

public override Embed GenerateRules()
{
return base.GenerateRules()
.ToEmbedBuilder()
.WithDescription("**Five Card Draw Poker** - Get the best 5-card poker hand!\nType `/casino game poker 5` to start playing!")
.AddField("🎯 **Objective**",
"Get the best possible 5-card poker hand to win the pot!", false)
.AddField("🎮 **How to Play**",
"1. Each player is dealt 5 cards\n" +
"2. Players take turns discarding unwanted cards\n" +
"3. New cards are drawn to replace discarded ones\n" +
"4. Best hand wins the entire pot!", false)
.AddField("🏆 **Hand Rankings** (High to Low)",
"• **Royal Flush** - A, K, Q, J, 10 (same suit)\n" +
"• **Straight Flush** - 5 consecutive cards (same suit)\n" +
"• **Four of a Kind** - 4 cards of same rank\n" +
"• **Full House** - 3 of a kind + pair\n" +
"• **Flush** - 5 cards of same suit\n" +
"• **Straight** - 5 consecutive cards\n" +
"• **Three of a Kind** - 3 cards of same rank\n" +
"• **Two Pair** - 2 pairs of different ranks\n" +
"• **One Pair** - 2 cards of same rank\n" +
"• **High Card** - No pairs or combinations", false)
.AddField("💡 **Tips**",
"• Click 'Show Hand' to see your cards privately\n" +
"• Select cards to discard by clicking the card buttons\n" +
"• Click 'Confirm Discard' when ready\n" +
"• You can discard 0-5 cards", false)
.WithColor(Color.Purple)
.Build();
}
}
Loading
Loading