forked from Invertex/UDHBot
-
Notifications
You must be signed in to change notification settings - Fork 9
Implement complete casino system with blackjack game and token management #340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
103 commits
Select commit
Hold shift + click to select a range
f5b0548
Initial plan
Copilot 40551ec
Implement core casino system with database, service, and command infr…
Copilot 5fe4d0d
Fix double down betting logic to only deduct additional bet amount
Copilot 7b0b82e
Fix Insight.Database transaction parameter conflict by renaming Inser…
Copilot 87d600d
Add comprehensive error handling and logging to casino blackjack inte…
Copilot 7d3d752
Fix component interaction pattern matching for casino blackjack buttons
Copilot 43580a6
✨ Update component interaction patterns for casino commands
Pierre-Demessence ae53982
Fix all interactions components
Pierre-Demessence 514d611
Use DisplayName in leaderboard
Pierre-Demessence fe55a13
Added custom bet button
Pierre-Demessence 9c3488c
✨ Enhance token history command with admin user support
Pierre-Demessence 423ddbd
✨ Update betting embed for Blackjack game
Pierre-Demessence b6bfb76
🔧 Remove unnecessary defer for reset command
Pierre-Demessence 55d1140
Fix formatting
Pierre-Demessence af31984
✨ Refactor transaction history display logic
Pierre-Demessence afdf471
✨ Update token history commands for improved access
Pierre-Demessence 941caba
✨ Enhance logging for casino commands
Pierre-Demessence 3a1e132
🔧 Remove logging statements from StartBlackjackGame and CompleteBlack…
Pierre-Demessence cace47c
✨ Clean up whitespace and improve code readability
Pierre-Demessence 6702824
- 🔒 Disable "Double Down" button if user lacks sufficient tokens
Pierre-Demessence 65b852b
✨ Refactor Blackjack game handling and improve logging
Pierre-Demessence d37f11f
✨ Enhance Blackjack game flow with auto-win feature
Pierre-Demessence fd9d50d
- ⏳ Adjust delay for dealer's turn to enhance user experience
Pierre-Demessence 0cee6ab
✨ Refactor Blackjack game embed creation for improved readability
Pierre-Demessence 947bd7d
✨ Update Blackjack game logic for auto-win scenario
Pierre-Demessence 5e8e542
✨ Adjust delay for dealer's turn in Blackjack game from 2000ms to 100…
Pierre-Demessence 5cfdbd8
✨ Update Blackjack game logic allow double down at any turn
Pierre-Demessence 3831fd6
✨ Add detailed rules for Blackjack game
Pierre-Demessence e508327
Dealer gets two cards initially instead of just 1
Pierre-Demessence 02581a6
✨ Enhance dealer turn experience in Blackjack game
Pierre-Demessence f44fc58
✨ Implement dealer soft 17 rule in Blackjack game
Pierre-Demessence 18eba4a
✨ Refactor Blackjack game logic and introduce BlackjackService
Pierre-Demessence a0b79a6
🃏 Change title from "🃏 Blackjack Game" to "🃏 Blackjack - Your Turn" i…
Pierre-Demessence a51f935
✨ Update Blackjack game logic and token management
Pierre-Demessence 0d00823
Refactor CasinoSlashModule: Remove blackjack commands and related met…
Pierre-Demessence 8389f0e
✨ Implement daily token reward system
Pierre-Demessence 7f3f928
✨ Refactor Blackjack game and introduce card system
Pierre-Demessence 792eb4e
✨ Enhance Card and Deck classes to support Jokers
Pierre-Demessence 437026f
✨ Refactor Blackjack game structure and introduce generic ActiveGame …
Pierre-Demessence 1073636
✨ Update dealer card display in Blackjack game description
Pierre-Demessence ff002cc
✨ Remove asynchronous logging on service initialization in Blackjack …
Pierre-Demessence 46b0842
Moved files
Pierre-Demessence ecf396f
Moved files again
Pierre-Demessence b6b4a5d
✨ Refactor transaction handling and introduce TransactionType enum
Pierre-Demessence f0d660d
✨ Enhance token transaction handling and details storage
Pierre-Demessence fbdcb79
🔍 Add current balance description in transaction history embed for be…
Pierre-Demessence cd74ee2
Refactored CasinoSlashModule.Blackjack and BlackjackService into Casi…
Pierre-Demessence 56d2373
✨ Update .NET Core version in GitHub Actions workflow from 6.0.x to 8…
Pierre-Demessence 430e109
✨ Fix: Shuffle the deck at the start of the Blackjack game
Pierre-Demessence 5d00557
✨ Refactor: Simplify object initialization in Blackjack and Deck classes
Pierre-Demessence 7886bd5
✨ Enhance: Improve error messaging for game session seat validation
Pierre-Demessence 1f05fd2
✨ Enhance: Skip AI players when updating user tokens after game ends
Pierre-Demessence 1d558d8
✨ Fix: Update current player selection logic to include blackjack check
Pierre-Demessence c741726
✨ Fix: Adjust player game result logic to prioritize player bust check
Pierre-Demessence dd9dbc1
Remove last bot instead of first bot
Pierre-Demessence fc463eb
✨ Enhance: Improve player and dealer action descriptions in game state
Pierre-Demessence 5300f45
✨ Enhance: Add GameName property to IGameSession interface and use it…
Pierre-Demessence 3352195
✨ Enhance: Implement JoinGame method in GameService and update JoinGa…
Pierre-Demessence abc85f4
✨ Change title format to "Game of" before the emoji and game name
Pierre-Demessence 1fcb145
Merge branch 'master' into copilot/fix-339
Pierre-Demessence eed5e91
Refactor GameService to remove hardcoded Blackjack session creation
Copilot ef39000
Add Rock Paper Scissors casino game with 2-player support and 2-minut…
Copilot f8f7c6e
Add casino game statistics command showing wins/losses and profit ana…
Copilot 870e508
Fix rules
Pierre-Demessence 487bcb5
Reworked results so it's factorized
Pierre-Demessence f4dc81e
Added AI to RPS
Pierre-Demessence dcdf554
Removed obsolete comments
Pierre-Demessence 3760ad7
✨ Refactor Blackjack and RockPaperScissors game session descriptions
Pierre-Demessence 60bfcb8
✨ Update game finish logic for better state management
Pierre-Demessence 2787e2d
✨ Simplify CurrentPlayer property and refactor GetPlayerGameResult logic
Pierre-Demessence affcecf
- 🎮 Implemented auto-start check when adding AI players
Pierre-Demessence d82d8e1
Reworked code that handle AIAction, DealerAction and FinishGame, so i…
Pierre-Demessence 7d5deae
Reworked RPS choice showing
Pierre-Demessence 8344329
✨ Update payout calculation to include total pot
Pierre-Demessence 928690b
Don't show blackjack for Dealer since we don't handle it
Pierre-Demessence 7dd0ede
Fix dealer and AI playing before game even start
Pierre-Demessence 0b44233
Fixed statistics
Pierre-Demessence 16243b2
Reworked stats a bit
Pierre-Demessence 559d36d
✨ Update daily reward logic for new users
Pierre-Demessence d58617c
✨ Update token balance message with additional commands
Pierre-Demessence 0574947
✨ Enhance daily reward notifications
Pierre-Demessence d334bb6
🃏 Implement Five Card Draw Poker game with private hands and card sel…
Copilot 5be2aa3
Modified Show hand a bit
Pierre-Demessence 2541414
✨ Add ButtonMetadata attribute for game actions
Pierre-Demessence 0e78576
Fix text issue
Pierre-Demessence 5ccec2f
Fix emoji for action buttons
Pierre-Demessence 031a4e9
Added simple AI that doesn't Discard for poker
Pierre-Demessence 0b4ee5d
Removed useless code
Pierre-Demessence b6ba261
Simplified getter
Pierre-Demessence a2d3b1f
Fix possible null errors
Pierre-Demessence 8af7b6b
Reworked whole UI of Poker
Pierre-Demessence d05451f
✨ Sort player cards in descending order for better visibility for Poker
Pierre-Demessence cfc785a
Way faster bot action
Pierre-Demessence 75980de
✨ Add "Add FULL AI" button and corresponding interaction
Pierre-Demessence 32db210
✨ Improve hand evaluation and winner determination in Poker game
Pierre-Demessence ce5d0e7
✨ Enhance Poker player actions with button metadata labels
Pierre-Demessence 50bfc6d
✨ Update game description to show selected cards for discard
Pierre-Demessence 68cb856
✨ Upgrade Dockerfile to use .NET SDK and runtime version 8.0
Pierre-Demessence 8f08477
AI buttons are enabled by DEBUG flag
Pierre-Demessence b80a097
Fix issue with buttons labels
Pierre-Demessence 4d0f7bb
Cleaned code
Pierre-Demessence 2eb5229
Removed deepsource
Pierre-Demessence ca2b62b
Removed deepsource.toml
Pierre-Demessence File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| public class AIAction | ||
| { | ||
| public Func<Task> Execute { get; set; } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | ||
| 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
127
DiscordBot/Domain/Casino/Discord/BlackjackDiscordGameSession.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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
106
DiscordBot/Domain/Casino/Discord/PokerDiscordGameSession.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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(); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.