Daily dollar that resets midnight BMT

This commit is contained in:
barelyprofessional
2026-01-04 23:59:14 -06:00
parent e952179663
commit 19571d54e7
4 changed files with 77 additions and 1 deletions

View File

@@ -387,3 +387,51 @@ public class HostessCommand : ICommand
await botInstance.SendChatMessageAsync(llmResponse, true, ChatBot.LengthLimitBehavior.TruncateExactly); await botInstance.SendChatMessageAsync(llmResponse, true, ChatBot.LengthLimitBehavior.TruncateExactly);
} }
} }
[KasinoCommand]
public class GetDailyDollarCommand : ICommand
{
public List<Regex> Patterns => [
new Regex("^daily", RegexOptions.IgnoreCase),
];
public string? HelpText => "Get your daily dollah";
public UserRight RequiredRight => UserRight.Loser;
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
public RateLimitOptionsModel? RateLimitOptions => null;
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments,
CancellationToken ctx)
{
var settings = await SettingsProvider.GetMultipleValuesAsync([
BuiltIn.Keys.KasinoDailyDollarEnabled, BuiltIn.Keys.KasinoDailyDollarAmount
]);
if (!settings[BuiltIn.Keys.KasinoDailyDollarEnabled].ToBoolean())
{
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, daily dollar has been disabled :(", true,
autoDeleteAfter: TimeSpan.FromSeconds(15));
return;
}
var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx);
await using var db = new ApplicationDbContext();
var mostRecentTxn = await db.Transactions.OrderBy(x => x.Id).LastOrDefaultAsync(x =>
x.Gambler == gambler && x.EventSource == TransactionSourceEventType.DailyDollar, cancellationToken: ctx);
if (mostRecentTxn != null)
{
var rolloverTime = await Money.GetKasinoDate();
// It's really more a question of whether the most recent txn was in the same game day
if (mostRecentTxn.Time >= rolloverTime)
{
var span = rolloverTime.AddDays(1) - DateTimeOffset.UtcNow;
await botInstance.SendChatMessageAsync(
$"{user.FormatUsername()}, your next daily dollar will be available in {span.Humanize(maxUnit: TimeUnit.Hour, minUnit: TimeUnit.Second)}",
true, autoDeleteAfter: TimeSpan.FromSeconds(15));
return;
}
}
var amount = settings[BuiltIn.Keys.KasinoDailyDollarAmount].ToType<decimal>();
await Money.ModifyBalanceAsync(gambler!.Id, amount, TransactionSourceEventType.DailyDollar,
"Daily dollar redemption", ct: ctx);
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, you redeemed {await amount.FormatKasinoCurrencyAsync()}", true,
autoDeleteAfter: TimeSpan.FromSeconds(15));
}
}

View File

@@ -270,7 +270,11 @@ public enum TransactionSourceEventType
/// to figure out what the next lossback should be. (Basically return a small % of the player's losses /// to figure out what the next lossback should be. (Basically return a small % of the player's losses
/// unless the player's actual position is positive during the period, then tell them to fuck off) /// unless the player's actual position is positive during the period, then tell them to fuck off)
/// </summary> /// </summary>
Lossback Lossback,
/// <summary>
/// A specific form of 24 hour time-based reload that has no wager requirement
/// </summary>
DailyDollar
} }
public enum WagerGame public enum WagerGame

View File

@@ -531,4 +531,22 @@ public static class Money
{ {
return Convert.ToHexString(Guid.NewGuid().ToByteArray()[..4]).ToLower(); return Convert.ToHexString(Guid.NewGuid().ToByteArray()[..4]).ToLower();
} }
/// <summary>
/// Get the current Kasino day based on the configured timezone offset
/// </summary>
/// <returns>Kasino day at midnight</returns>
/// <exception cref="InvalidOperationException">Thrown if Kasino.Timezone is null or empty</exception>
public static async Task<DateTimeOffset> GetKasinoDate()
{
var tz = await SettingsProvider.GetValueAsync(BuiltIn.Keys.KasinoTimezone);
if (string.IsNullOrEmpty(tz.Value))
{
throw new InvalidOperationException();
}
var systemTz = TimeZoneInfo.FindSystemTimeZoneById(tz.Value);
var now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, systemTz);
return new DateTimeOffset(now.Date, systemTz.BaseUtcOffset);
}
} }

View File

@@ -465,6 +465,12 @@ public static class BuiltIn
public static string ZiplineUrl = "Zipline.Url"; public static string ZiplineUrl = "Zipline.Url";
[BuiltInSetting("Delay in milliseconds before cleaning up blackjack", SettingValueType.Text, "20000", WholeNumberRegex)] [BuiltInSetting("Delay in milliseconds before cleaning up blackjack", SettingValueType.Text, "20000", WholeNumberRegex)]
public static string KasinoBlackjackCleanupDelay = "Kasino.Blackjack.CleanupDelay"; public static string KasinoBlackjackCleanupDelay = "Kasino.Blackjack.CleanupDelay";
[BuiltInSetting("Amount for the daily dollar to pay out", SettingValueType.Text, "100", WholeNumberRegex)]
public static string KasinoDailyDollarAmount = "Kasino.DailyDollar.Amount";
[BuiltInSetting("Whether daily dollars can be redeemed", SettingValueType.Boolean, "true", BooleanRegex)]
public static string KasinoDailyDollarEnabled = "Kasino.DailyDollar.Enabled";
[BuiltInSetting("Timezone to use for daily reloads etc.", SettingValueType.Text, "Eastern Standard Time")]
public static string KasinoTimezone = "Kasino.Timezone";
} }
} }