change: gambling commands now show amount bet. Slightly changed the layout. Updated some gambling strings

add: added .btr excl
This commit is contained in:
Kwoth
2024-11-25 06:08:04 +00:00
parent 96ce7e23bb
commit 75d0eb631d
19 changed files with 184 additions and 80 deletions

View File

@@ -12,6 +12,7 @@ Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except da
- `.btr list` to list all button roles on the server
- `.btr rm` to remove a button role from the specified message
- `.btr rma` to remove all button roles on the specified message
- `.btr excl` to toggle exclusive button roles (only 1 role per message or any number)
- Use `.h` on any of the above for more info
- Added `.wrongsong` which will delete the last queued song.
- Useful in case you made a mistake, or the bot queued a wrong song

View File

@@ -22,4 +22,6 @@ public sealed class ButtonRole
[MaxLength(50)]
public string Label { get; set; } = string.Empty;
public bool Exclusive { get; set; }
}

View File

@@ -12,8 +12,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace NadekoBot.Migrations.PostgreSql
{
[DbContext(typeof(PostgreSqlContext))]
[Migration("20241119135917_guildcolors")]
partial class guildcolors
[Migration("20241126033634_btnroles_guildcolors")]
partial class btnroles_guildcolors
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -479,6 +479,10 @@ namespace NadekoBot.Migrations.PostgreSql
.HasColumnType("character varying(100)")
.HasColumnName("emote");
b.Property<bool>("Exclusive")
.HasColumnType("boolean")
.HasColumnName("exclusive");
b.Property<decimal>("GuildId")
.HasColumnType("numeric(20,0)")
.HasColumnName("guildid");

View File

@@ -6,7 +6,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace NadekoBot.Migrations.PostgreSql
{
/// <inheritdoc />
public partial class guildcolors : Migration
public partial class btnroles_guildcolors : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
@@ -24,7 +24,8 @@ namespace NadekoBot.Migrations.PostgreSql
position = table.Column<int>(type: "integer", nullable: false),
roleid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
emote = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
label = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false)
label = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
exclusive = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{

View File

@@ -476,6 +476,10 @@ namespace NadekoBot.Migrations.PostgreSql
.HasColumnType("character varying(100)")
.HasColumnName("emote");
b.Property<bool>("Exclusive")
.HasColumnType("boolean")
.HasColumnName("exclusive");
b.Property<decimal>("GuildId")
.HasColumnType("numeric(20,0)")
.HasColumnName("guildid");

View File

@@ -11,8 +11,8 @@ using NadekoBot.Db;
namespace NadekoBot.Migrations
{
[DbContext(typeof(SqliteContext))]
[Migration("20241119135908_guildcolors")]
partial class guildcolors
[Migration("20241126033626_btnroles_guildcolors")]
partial class btnroles_guildcolors
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -357,6 +357,9 @@ namespace NadekoBot.Migrations
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<bool>("Exclusive")
.HasColumnType("INTEGER");
b.Property<ulong>("GuildId")
.HasColumnType("INTEGER");

View File

@@ -5,7 +5,7 @@
namespace NadekoBot.Migrations
{
/// <inheritdoc />
public partial class guildcolors : Migration
public partial class btnroles_guildcolors : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
@@ -23,7 +23,8 @@ namespace NadekoBot.Migrations
Position = table.Column<int>(type: "INTEGER", nullable: false),
RoleId = table.Column<ulong>(type: "INTEGER", nullable: false),
Emote = table.Column<string>(type: "TEXT", maxLength: 100, nullable: false),
Label = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false)
Label = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
Exclusive = table.Column<bool>(type: "INTEGER", nullable: false)
},
constraints: table =>
{

View File

@@ -354,6 +354,9 @@ namespace NadekoBot.Migrations
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<bool>("Exclusive")
.HasColumnType("INTEGER");
b.Property<ulong>("GuildId")
.HasColumnType("INTEGER");

View File

@@ -1,4 +1,5 @@
using NadekoBot.Db.Models;
using NadekoBot.Common.TypeReaders.Models;
using NadekoBot.Db.Models;
using NadekoBot.Modules.Administration.Services;
using System.Text;
using ContextType = Discord.Commands.ContextType;
@@ -7,6 +8,7 @@ namespace NadekoBot.Modules.Administration;
public partial class Administration
{
[Group("btr")]
public partial class ButtonRoleCommands : NadekoModule<ButtonRolesService>
{
private List<ActionRowBuilder> GetActionRows(IReadOnlyList<ButtonRole> roles)
@@ -228,7 +230,7 @@ public partial class Administration
{
eb.WithPendingColor()
.WithDescription(GetText(strs.btnrole_none));
return eb;
}
@@ -265,5 +267,30 @@ public partial class Administration
})
.SendAsync();
}
[Cmd]
[RequireContext(ContextType.Guild)]
[BotPerm(GuildPerm.ManageRoles)]
[RequireUserPermission(GuildPerm.ManageRoles)]
public Task BtnRoleExclusive(MessageLink link, PermissionAction exclusive)
=> BtnRoleExclusive(link.Message.Id, exclusive);
[Cmd]
[RequireContext(ContextType.Guild)]
[BotPerm(GuildPerm.ManageRoles)]
[RequireUserPermission(GuildPerm.ManageRoles)]
public async Task BtnRoleExclusive(ulong messageId, PermissionAction exclusive)
{
var res = await _service.SetExclusiveButtonRoles(ctx.Guild.Id, messageId, exclusive.Value);
if (res)
{
await Response().Confirm(strs.btnrole_exclusive).SendAsync();
}
else
{
await Response().Confirm(strs.btnrole_multiple).SendAsync();
}
}
}
}

View File

@@ -42,32 +42,49 @@ public sealed class ButtonRolesService : INService, IReadyExecutor
_ = Task.Run(async () =>
{
await using var uow = _db.GetDbContext();
var buttonRole = await uow.GetTable<ButtonRole>()
.Where(x => x.ButtonId == smc.Data.CustomId && x.MessageId == smc.Message.Id)
.FirstOrDefaultAsyncLinqToDB();
if (buttonRole is null)
return;
var guild = _client.GetGuild(buttonRole.GuildId);
if (guild is null)
return;
var role = guild.GetRole(buttonRole.RoleId);
if (role is null)
return;
if (smc.User is not IGuildUser user)
return;
if (user.GetRoles().Any(x => x.Id == role.Id))
try
{
await user.RemoveRoleAsync(role.Id);
return;
}
await using var uow = _db.GetDbContext();
var buttonRole = await uow.GetTable<ButtonRole>()
.Where(x => x.ButtonId == smc.Data.CustomId && x.MessageId == smc.Message.Id)
.FirstOrDefaultAsyncLinqToDB();
await user.AddRoleAsync(role.Id);
if (buttonRole is null)
return;
var guild = _client.GetGuild(buttonRole.GuildId);
if (guild is null)
return;
var role = guild.GetRole(buttonRole.RoleId);
if (role is null)
return;
if (smc.User is not IGuildUser user)
return;
if (user.GetRoles().Any(x => x.Id == role.Id))
{
await user.RemoveRoleAsync(role.Id);
return;
}
if (buttonRole.Exclusive)
{
var otherRoles = await uow.GetTable<ButtonRole>()
.Where(x => x.GuildId == smc.GuildId && x.MessageId == smc.Message.Id)
.Select(x => x.RoleId)
.ToListAsyncLinqToDB();
await user.RemoveRolesAsync(otherRoles);
}
await user.AddRoleAsync(role.Id);
}
catch (Exception ex)
{
Log.Warning(ex, "Unable to handle button role interaction for user {UserId}", inter.User.Id);
}
});
}
@@ -108,7 +125,8 @@ public sealed class ButtonRolesService : INService, IReadyExecutor
: 1,
Emote = emoteStr,
Label = string.Empty,
ButtonId = $"{BTN_PREFIX}:{guildId}:{guid}"
ButtonId = $"{BTN_PREFIX}:{guildId}:{guid}",
Exclusive = (uow.GetTable<ButtonRole>().Where(x => x.GuildId == guildId && x.MessageId == messageId).All(x => x.Exclusive))
},
_ => new()
{
@@ -151,4 +169,16 @@ public sealed class ButtonRolesService : INService, IReadyExecutor
.OrderBy(x => x.Id)
.ToListAsyncLinqToDB();
}
public async Task<bool> SetExclusiveButtonRoles(ulong guildId, ulong messageId, bool exclusive)
{
await using var uow = _db.GetDbContext();
return await uow.GetTable<ButtonRole>()
.Where(x => x.GuildId == guildId && x.MessageId == messageId)
.UpdateAsync((_) => new()
{
Exclusive = exclusive
})
> 0;
}
}

View File

@@ -57,7 +57,7 @@ public partial class Gambling
i.Dispose();
var eb = CreateEmbed()
.WithOkColor();
.WithOkColor();
var toSend = string.Empty;
if (cardObjects.Count == 5)
@@ -172,13 +172,14 @@ public partial class Gambling
}
var eb = CreateEmbed()
.WithOkColor()
.WithAuthor(ctx.User)
.WithDescription(result.Card.GetEmoji())
.AddField(GetText(strs.guess), GetGuessInfo(val, col), true)
.AddField(GetText(strs.card), GetCardInfo(result.Card), true)
.AddField(GetText(strs.won), N((long)result.Won), false)
.WithImageUrl("attachment://card.png");
.WithOkColor()
.WithAuthor(ctx.User)
.WithDescription(result.Card.GetEmoji())
.AddField(GetText(strs.guess), GetGuessInfo(val, col), true)
.AddField(GetText(strs.card), GetCardInfo(result.Card), false)
.AddField(GetText(strs.bet), N(amount), true)
.AddField(GetText(strs.won), N((long)result.Won), true)
.WithImageUrl("attachment://card.png");
using var img = await GetCardImageAsync(result.Card);
await using var imgStream = await img.ToStreamAsync();

View File

@@ -56,7 +56,7 @@ public partial class Gambling
var tailsArr = await _images.GetTailsImageAsync();
var result = await _service.FlipAsync(count);
for (var i = 0; i < result.Length; i++)
{
if (result[i].Side == 0)
@@ -77,18 +77,18 @@ public partial class Gambling
i.Dispose();
var imgName = $"coins.{format.FileExtensions.First()}";
var msg = count != 1
? Format.Bold(GetText(strs.flip_results(count, headCount, tailCount)))
: GetText(strs.flipped(headCount > 0
? Format.Bold(GetText(strs.heads))
: Format.Bold(GetText(strs.tails))));
var eb = CreateEmbed()
.WithOkColor()
.WithAuthor(ctx.User)
.WithDescription(msg)
.WithImageUrl($"attachment://{imgName}");
.WithOkColor()
.WithAuthor(ctx.User)
.WithDescription(msg)
.WithImageUrl($"attachment://{imgName}");
await ctx.Channel.SendFileAsync(stream,
imgName,
@@ -123,18 +123,22 @@ public partial class Gambling
var won = (long)result.Won;
if (won > 0)
{
str = Format.Bold(GetText(strs.flip_guess(N(won))));
str = Format.Bold(GetText(strs.betflip_guess));
}
else
{
str = Format.Bold(GetText(strs.better_luck));
}
await Response().Embed(CreateEmbed()
.WithAuthor(ctx.User)
.WithDescription(str)
.WithOkColor()
.WithImageUrl(imageToSend.ToString())).SendAsync();
await Response()
.Embed(CreateEmbed()
.WithAuthor(ctx.User)
.WithDescription(str)
.AddField(GetText(strs.bet), N(amount), true)
.AddField(GetText(strs.won), N((long)result.Won), true)
.WithOkColor()
.WithImageUrl(imageToSend.ToString()))
.SendAsync();
}
}
}

View File

@@ -718,7 +718,7 @@ public partial class Gambling : GamblingModule<GamblingService>
string str;
if (win > 0)
{
str = GetText(strs.br_win(N(win), result.Threshold + (result.Roll == 100 ? " 👑" : "")));
str = GetText(strs.betroll_win(result.Threshold + (result.Roll == 100 ? " 👑" : "")));
}
else
{
@@ -728,7 +728,9 @@ public partial class Gambling : GamblingModule<GamblingService>
var eb = CreateEmbed()
.WithAuthor(ctx.User)
.WithDescription(Format.Bold(str))
.AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
.AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture), true)
.AddField(GetText(strs.bet), N(amount), true)
.AddField(GetText(strs.won), N((long)result.Won), true)
.WithOkColor();
await Response().Embed(eb).SendAsync();
@@ -922,8 +924,8 @@ public partial class Gambling : GamblingModule<GamblingService>
var eb = CreateEmbed()
.WithOkColor()
.WithDescription(sb.ToString())
.AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true)
.AddField(GetText(strs.won), $"{(long)result.Won}", true)
.AddField(GetText(strs.bet), N(amount), true)
.AddField(GetText(strs.won), $"{N((long)result.Won)}", true)
.WithAuthor(ctx.User);

View File

@@ -66,10 +66,10 @@ public partial class Gambling
var eb = CreateEmbed()
.WithAuthor(ctx.User)
.WithDescription(Format.Bold(text))
.WithImageUrl($"attachment://result.png")
.WithOkColor();
.WithAuthor(ctx.User)
.WithDescription(Format.Bold(text))
.WithImageUrl($"attachment://result.png")
.WithOkColor();
var bb = new ButtonBuilder(emote: Emoji.Parse("🔁"), customId: "slot:again", label: "Pull Again");
var inter = _inter.Create(ctx.User.Id,
@@ -168,7 +168,8 @@ public partial class Gambling
await using (var uow = _db.GetDbContext())
{
ownedAmount = uow.Set<DiscordUser>()
.FirstOrDefault(x => x.UserId == ctx.User.Id)?.CurrencyAmount
.FirstOrDefault(x => x.UserId == ctx.User.Id)
?.CurrencyAmount
?? 0;
}

View File

@@ -1499,18 +1499,22 @@ snipe:
- snipe
- sn
btnroleadd:
- btnradd
- btnra
- add
- a
btnroleremove:
- btnrrem
- btnrr
- btnrrm
- rem
- r
- rm
btnroleremoveall:
- btnrremall
- btnrra
- removeall
- rma
btnrolelist:
- btnrlist
- btnrl
- list
- l
- ls
btnroleexclusive:
- excl
- e
wrongsong:
- wrongsong
- wrongtrack

View File

@@ -4769,6 +4769,19 @@ btnrolelist:
- ''
params:
- { }
btnroleexclusive:
desc: |-
Toggles whether button roles are exclusive or not.
If enabled, users can only pick one role from the buttons per message.
If disabled, users can pick any number of roles.
ex:
- '123123123 enable'
- '123123123 disable'
params:
- message:
desc: "A message link or id of the message"
enable:
desc: "Whether to enable or disable exclusive button roles"
wrongsong:
desc: |-
Removes the last queued song.
@@ -4807,4 +4820,4 @@ servercolorpending:
- '#ffff00'
params:
- color:
desc: "The hex of the color to set"
desc: "The hex of the color to set"

View File

@@ -238,10 +238,10 @@
"sb_user": "User soft-banned",
"awarded": "{2} has awarded {0} to {1}",
"better_luck": "Better luck next time ^_^",
"br_win": "Congratulations! You won {0} for rolling above {1}",
"betroll_win": "Congratulations! You rolled above {0}",
"deck_reshuffled": "Deck reshuffled.",
"flipped": "Flipped {0}",
"flip_guess": "You guessed it! You won {0}",
"betflip_guess": "You guessed it!",
"flip_invalid": "Invalid number specified. You can flip 1 to {0} coins.",
"flip_results": "Flipped {0} coins. {1} heads, {2} tails.",
"cards_left": "{0} cards left in the deck.",
@@ -266,7 +266,8 @@
"available_tests": "Available Tests",
"test_results_for": "Test results for {0}",
"won": "Won",
"multiplier": "Multiplier",
"bet": "Bet",
"multi": "Multi",
"tails": "Tail",
"take": "successfully took {0} from {1}",
"take_fail": "was unable to take {0} from {1} because the user doesn't have that much {2}!",
@@ -1129,8 +1130,10 @@
"btnrole_none": "There are no button roles on this page.",
"btnrole_removeall_not_found": "Button role successfully removed but message wasn't found.",
"btnrole_removed": "Button role removed.",
"btnrole_exclusive": "Users can now pick only one of the roles from that message.",
"btnrole_multiple": "Users can now pick any number of button roles from that message.",
"no_last_queued_found": "No last queued track found.",
"wrongsong_success": "Oops! Wrong song removed: {0}",
"server_not_found": "Server not found.",
"server_color_set": "Successfully set a new server color.",
"server_color_set": "Successfully set a new server color."
}

View File

@@ -300,7 +300,7 @@
"hangman_running": "Hangman game already running on this channel.",
"hangman_start_errored": "Starting hangman errored.",
"hangman_types": "List of \u0022{0}hangman\u0022 term types:",
"picked": "picked {0}",
"picked": "{0} picked {1}",
"planted": "{0} planted {1}",
"trivia_already_running": "Trivia game is already running on this server.",
"trivia_game": "Trivia Game",