mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
add: added .rakeback to get a part of the house edge back. Rakeback is accumulated by betting (not winning or losing in particular). All games have manually specified rakeback values
add: slot now has 1 more icon (wheat!), and multipliers have been modified to even out the gains change: betroll is improved (around 2% better payout), as 66 is now a winning number, not a losing one
This commit is contained in:
@@ -38,6 +38,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
private readonly IRemindService _remind;
|
||||
private readonly GamblingTxTracker _gamblingTxTracker;
|
||||
private readonly IPatronageService _ps;
|
||||
private readonly RakebackService _rb;
|
||||
|
||||
public Gambling(
|
||||
IGamblingService gs,
|
||||
@@ -50,7 +51,8 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
IBankService bank,
|
||||
IRemindService remind,
|
||||
IPatronageService patronage,
|
||||
GamblingTxTracker gamblingTxTracker)
|
||||
GamblingTxTracker gamblingTxTracker,
|
||||
RakebackService rb)
|
||||
: base(configService)
|
||||
{
|
||||
_gs = gs;
|
||||
@@ -60,6 +62,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
_bank = bank;
|
||||
_remind = remind;
|
||||
_gamblingTxTracker = gamblingTxTracker;
|
||||
_rb = rb;
|
||||
_ps = patronage;
|
||||
_rng = new NadekoRandom();
|
||||
|
||||
@@ -1088,4 +1091,45 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
footer: $"Total Bet: {tests} | Payout: {payout:F0} | {payout * 1.0M / tests * 100}%")
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
private NadekoInteractionBase CreateRakebackInteraction()
|
||||
=> _inter.Create(ctx.User.Id,
|
||||
new ButtonBuilder(
|
||||
customId: "cash:rakeback",
|
||||
emote: new Emoji("💸")),
|
||||
RakebackAction);
|
||||
|
||||
private async Task RakebackAction(SocketMessageComponent arg)
|
||||
{
|
||||
var rb = await _rb.ClaimRakebackAsync(ctx.User.Id);
|
||||
|
||||
if (rb == 0)
|
||||
{
|
||||
await arg.DeferAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await arg.RespondAsync(_sender, GetText(strs.rakeback_claimed(N(rb))), MsgType.Ok);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task Rakeback()
|
||||
{
|
||||
var rb = await _rb.GetRakebackAsync(ctx.User.Id);
|
||||
|
||||
if (rb < 1)
|
||||
{
|
||||
await Response()
|
||||
.Error(strs.rakeback_none)
|
||||
.SendAsync();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var inter = CreateRakebackInteraction();
|
||||
await Response()
|
||||
.Pending(strs.rakeback_available(N(rb)))
|
||||
.Interaction(inter)
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
@@ -11,7 +11,7 @@ namespace NadekoBot.Modules.Gambling.Common;
|
||||
public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
|
||||
{
|
||||
[Comment("""DO NOT CHANGE""")]
|
||||
public int Version { get; set; } = 11;
|
||||
public int Version { get; set; } = 12;
|
||||
|
||||
[Comment("""Currency settings""")]
|
||||
public CurrencyConfig Currency { get; set; }
|
||||
@@ -164,7 +164,7 @@ public partial class BetRollConfig
|
||||
},
|
||||
new()
|
||||
{
|
||||
WhenAbove = 66,
|
||||
WhenAbove = 65,
|
||||
MultiplyBy = 2
|
||||
}
|
||||
];
|
||||
@@ -226,7 +226,7 @@ public partial class LuckyLadderSettings
|
||||
public decimal[] Multipliers { get; set; }
|
||||
|
||||
public LuckyLadderSettings()
|
||||
=> Multipliers = [2.4M, 1.7M, 1.5M, 1.2M, 0.5M, 0.3M, 0.2M, 0.1M];
|
||||
=> Multipliers = [2.4M, 1.7M, 1.5M, 1.1M, 0.5M, 0.3M, 0.2M, 0.1M];
|
||||
}
|
||||
|
||||
[Cloneable]
|
||||
|
@@ -189,11 +189,16 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
|
||||
});
|
||||
}
|
||||
|
||||
if (data.Version < 11)
|
||||
if (data.Version < 12)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 11;
|
||||
c.Version = 12;
|
||||
|
||||
if (c.BetRoll.Pairs.Length == 3 && c.BetRoll.Pairs[2].WhenAbove == 66)
|
||||
{
|
||||
c.BetRoll.Pairs[2].WhenAbove = 65;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -13,5 +13,10 @@ public interface IGamblingService
|
||||
Task<OneOf<SlotResult, GamblingError>> SlotAsync(ulong userId, long amount);
|
||||
Task<FlipResult[]> FlipAsync(int count);
|
||||
Task<OneOf<RpsResult, GamblingError>> RpsAsync(ulong userId, long amount, byte pick);
|
||||
Task<OneOf<BetdrawResult, GamblingError>> BetDrawAsync(ulong userId, long amount, byte? maybeGuessValue, byte? maybeGuessColor);
|
||||
|
||||
Task<OneOf<BetdrawResult, GamblingError>> BetDrawAsync(
|
||||
ulong userId,
|
||||
long amount,
|
||||
byte? maybeGuessValue,
|
||||
byte? maybeGuessColor);
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Modules.Gambling.Betdraw;
|
||||
using NadekoBot.Modules.Gambling.Rps;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
@@ -8,15 +10,15 @@ namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
public sealed class NewGamblingService : IGamblingService, INService
|
||||
{
|
||||
private readonly GamblingConfigService _bcs;
|
||||
private readonly GamblingConfigService _gcs;
|
||||
private readonly ICurrencyService _cs;
|
||||
|
||||
public NewGamblingService(GamblingConfigService bcs, ICurrencyService cs)
|
||||
public NewGamblingService(GamblingConfigService gcs, ICurrencyService cs)
|
||||
{
|
||||
_bcs = bcs;
|
||||
_gcs = gcs;
|
||||
_cs = cs;
|
||||
}
|
||||
|
||||
|
||||
public async Task<OneOf<LuLaResult, GamblingError>> LulaAsync(ulong userId, long amount)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(amount);
|
||||
@@ -31,13 +33,13 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
}
|
||||
}
|
||||
|
||||
var game = new LulaGame(_bcs.Data.LuckyLadder.Multipliers);
|
||||
var game = new LulaGame(_gcs.Data.LuckyLadder.Multipliers);
|
||||
var result = game.Spin(amount);
|
||||
|
||||
|
||||
var won = (long)result.Won;
|
||||
if (won > 0)
|
||||
{
|
||||
await _cs.AddAsync(userId, won, new("lula", result.Multiplier >= 1 ? "win" : "lose"));
|
||||
await _cs.AddAsync(userId, won, new("lula", result.Multiplier >= 1 ? "win" : "lose"));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -57,9 +59,9 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
}
|
||||
}
|
||||
|
||||
var game = new BetrollGame(_bcs.Data.BetRoll.Pairs
|
||||
.Select(x => (x.WhenAbove, (decimal)x.MultiplyBy))
|
||||
.ToList());
|
||||
var game = new BetrollGame(_gcs.Data.BetRoll.Pairs
|
||||
.Select(x => (x.WhenAbove, (decimal)x.MultiplyBy))
|
||||
.ToList());
|
||||
|
||||
var result = game.Roll(amount);
|
||||
|
||||
@@ -88,19 +90,23 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
}
|
||||
}
|
||||
|
||||
var game = new BetflipGame(_bcs.Data.BetFlip.Multiplier);
|
||||
var game = new BetflipGame(_gcs.Data.BetFlip.Multiplier);
|
||||
var result = game.Flip(guess, amount);
|
||||
|
||||
|
||||
var won = (long)result.Won;
|
||||
if (won > 0)
|
||||
{
|
||||
await _cs.AddAsync(userId, won, new("betflip", "win"));
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<OneOf<BetdrawResult, GamblingError>> BetDrawAsync(ulong userId, long amount, byte? maybeGuessValue, byte? maybeGuessColor)
|
||||
|
||||
public async Task<OneOf<BetdrawResult, GamblingError>> BetDrawAsync(
|
||||
ulong userId,
|
||||
long amount,
|
||||
byte? maybeGuessValue,
|
||||
byte? maybeGuessColor)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(amount);
|
||||
|
||||
@@ -109,7 +115,7 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
|
||||
if (maybeGuessColor > 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(maybeGuessColor));
|
||||
|
||||
|
||||
if (maybeGuessValue > 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(maybeGuessValue));
|
||||
|
||||
@@ -125,13 +131,13 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
|
||||
var game = new BetdrawGame();
|
||||
var result = game.Draw((BetdrawValueGuess?)maybeGuessValue, (BetdrawColorGuess?)maybeGuessColor, amount);
|
||||
|
||||
|
||||
var won = (long)result.Won;
|
||||
if (won > 0)
|
||||
{
|
||||
await _cs.AddAsync(userId, won, new("betdraw", "win"));
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -178,7 +184,7 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
|
||||
return Task.FromResult(results);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// private readonly ConcurrentDictionary<ulong, Deck> _decks = new ConcurrentDictionary<ulong, Deck>();
|
||||
@@ -236,7 +242,7 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(amount);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan(pick, 2);
|
||||
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("rps", "bet"));
|
||||
@@ -249,7 +255,7 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
|
||||
var rps = new RpsGame();
|
||||
var result = rps.Play((RpsPick)pick, amount);
|
||||
|
||||
|
||||
var won = (long)result.Won;
|
||||
if (won > 0)
|
||||
{
|
||||
@@ -265,4 +271,46 @@ public sealed class NewGamblingService : IGamblingService, INService
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RakebackService: INService
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly ICurrencyService _cs;
|
||||
|
||||
public RakebackService(DbService db, ICurrencyService cs)
|
||||
{
|
||||
_db = db;
|
||||
_cs = cs;
|
||||
}
|
||||
|
||||
public async Task<long> GetRakebackAsync(ulong userId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
var rb = uow.GetTable<Rakeback>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.Select(x => x.Amount)
|
||||
.FirstOrDefault();
|
||||
|
||||
return (long)rb;
|
||||
}
|
||||
|
||||
public async Task<long> ClaimRakebackAsync(ulong userId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
var rbs = await uow.GetTable<Rakeback>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.DeleteWithOutputAsync((x) => x.Amount);
|
||||
|
||||
if(rbs.Length == 0)
|
||||
return 0;
|
||||
|
||||
var rb = (long)rbs[0];
|
||||
|
||||
await _cs.AddAsync(userId, rb, new("rakeback", "claim"));
|
||||
|
||||
return rb;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user