- Added waifu price decay functionality

- Waifu prices changed to long, supporting much higher prices than before
- Fixed .yml comment indentation in some cases
- Updated changelog
This commit is contained in:
Kwoth
2022-02-02 11:25:22 +01:00
parent 41653a317b
commit 15ee3dd638
12 changed files with 287 additions and 139 deletions

View File

@@ -11,6 +11,11 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
- Added `.deleteemptyservers` command - Added `.deleteemptyservers` command
- Added `.curtr <id>` which lets you see full information about one of your own transactions with the specified id - Added `.curtr <id>` which lets you see full information about one of your own transactions with the specified id
- Added trovo.live support for stream notifications (`.stadd`) - Added trovo.live support for stream notifications (`.stadd`)
- Added unclaimed waifu decay functionality
- Added 3 new settings to `data/gambling.yml` to control it:
- waifu.decay.percent - How much % to subtract from unclaimed waifu
- waifu.decay.hourInterval - How often to decay the price
- waifu.decay.minPrice - Unclaimed waifus with price lower than the one specified here will not be affected by the decay
### Fixed ### Fixed
- Fixed an extra whitespace in usage part of command help if the command has no arguments - Fixed an extra whitespace in usage part of command help if the command has no arguments
@@ -18,6 +23,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
- `.gvc` should now properly trigger when a user is already in a gvc and changes his activity - `.gvc` should now properly trigger when a user is already in a gvc and changes his activity
- `.gvc` should now properly detect multiple activities - `.gvc` should now properly detect multiple activities
- Fixed reference to non-existent command in bot.yml - Fixed reference to non-existent command in bot.yml
- Comment indentation in .yml files should now make more sense
### Changed ### Changed
- CustomReactions module (and customreactions db table) has been renamed to Expressions. - CustomReactions module (and customreactions db table) has been renamed to Expressions.
@@ -30,6 +36,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
- Some of the old aliases like `.acr` `.dcr` `.lcr` and a few others have been kept - Some of the old aliases like `.acr` `.dcr` `.lcr` and a few others have been kept
- Currency output format improvement (will use guild locale now for some commands) - Currency output format improvement (will use guild locale now for some commands)
- `.crypto` will now also show CoinMarketCap rank - `.crypto` will now also show CoinMarketCap rank
- Waifus can now be claimed for much higher prices (int -> long)
- Improved .curtrs (It will now have a lot more useful data in the database, show Tx ids, and be partially localized) - Improved .curtrs (It will now have a lot more useful data in the database, show Tx ids, and be partially localized)
- [dev] Reason renamed to Note - [dev] Reason renamed to Note
- [dev] Added Type, Extra, OtherId fields to the database - [dev] Added Type, Extra, OtherId fields to the database

View File

@@ -17,8 +17,15 @@ public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor
{ {
if (value is CommentsObjectDescriptor commentsDescriptor if (value is CommentsObjectDescriptor commentsDescriptor
&& !string.IsNullOrWhiteSpace(commentsDescriptor.Comment)) && !string.IsNullOrWhiteSpace(commentsDescriptor.Comment))
context.Emit(new Comment(commentsDescriptor.Comment.Replace("\n", "\n# "), false)); {
var parts = commentsDescriptor.Comment.Split('\n');
foreach (var part in parts)
{
context.Emit(new Comment(part.Trim(), false));
}
}
return base.EnterMapping(key, value, context); return base.EnterMapping(key, value, context);
} }
} }

View File

@@ -9,7 +9,7 @@ namespace NadekoBot.Db;
public class WaifuInfoStats public class WaifuInfoStats
{ {
public string FullName { get; init; } public string FullName { get; init; }
public int Price { get; init; } public long Price { get; init; }
public string ClaimerName { get; init; } public string ClaimerName { get; init; }
public string AffinityName { get; init; } public string AffinityName { get; init; }
public int AffinityCount { get; init; } public int AffinityCount { get; init; }

View File

@@ -14,7 +14,7 @@ public class WaifuInfo : DbEntity
public int? AffinityId { get; set; } public int? AffinityId { get; set; }
public DiscordUser Affinity { get; set; } public DiscordUser Affinity { get; set; }
public int Price { get; set; } public long Price { get; set; }
public List<WaifuItem> Items { get; set; } = new(); public List<WaifuItem> Items { get; set; } = new();
public override string ToString() public override string ToString()
@@ -49,7 +49,7 @@ public class WaifuLbResult
public string Affinity { get; set; } public string Affinity { get; set; }
public string AffinityDiscrim { get; set; } public string AffinityDiscrim { get; set; }
public int Price { get; set; } public long Price { get; set; }
public override string ToString() public override string ToString()
{ {

View File

@@ -29,7 +29,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("ClubApplicants"); b.ToTable("ClubApplicants", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b => modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b =>
@@ -44,7 +44,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("ClubBans"); b.ToTable("ClubBans", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b => modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b =>
@@ -86,7 +86,7 @@ namespace NadekoBot.Migrations
b.HasIndex("OwnerId") b.HasIndex("OwnerId")
.IsUnique(); .IsUnique();
b.ToTable("Clubs"); b.ToTable("Clubs", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b => modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b =>
@@ -155,7 +155,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("DiscordUser"); b.ToTable("DiscordUser", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b => modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b =>
@@ -189,7 +189,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("FollowedStream"); b.ToTable("FollowedStream", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
@@ -218,7 +218,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId") b.HasIndex("GuildConfigId")
.IsUnique(); .IsUnique();
b.ToTable("AntiAltSetting"); b.ToTable("AntiAltSetting", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
@@ -250,7 +250,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId") b.HasIndex("GuildConfigId")
.IsUnique(); .IsUnique();
b.ToTable("AntiRaidSetting"); b.ToTable("AntiRaidSetting", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
@@ -272,7 +272,7 @@ namespace NadekoBot.Migrations
b.HasIndex("AntiSpamSettingId"); b.HasIndex("AntiSpamSettingId");
b.ToTable("AntiSpamIgnore"); b.ToTable("AntiSpamIgnore", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
@@ -304,7 +304,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId") b.HasIndex("GuildConfigId")
.IsUnique(); .IsUnique();
b.ToTable("AntiSpamSetting"); b.ToTable("AntiSpamSetting", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoCommand", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoCommand", b =>
@@ -342,7 +342,7 @@ namespace NadekoBot.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("AutoCommands"); b.ToTable("AutoCommands", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateChannel", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateChannel", b =>
@@ -370,7 +370,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId"); b.HasIndex("GuildId");
b.ToTable("AutoTranslateChannels"); b.ToTable("AutoTranslateChannels", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateUser", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateUser", b =>
@@ -398,7 +398,7 @@ namespace NadekoBot.Migrations
b.HasAlternateKey("ChannelId", "UserId"); b.HasAlternateKey("ChannelId", "UserId");
b.ToTable("AutoTranslateUsers"); b.ToTable("AutoTranslateUsers", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.BanTemplate", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.BanTemplate", b =>
@@ -421,7 +421,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId") b.HasIndex("GuildId")
.IsUnique(); .IsUnique();
b.ToTable("BanTemplates"); b.ToTable("BanTemplates", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistEntry", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistEntry", b =>
@@ -441,7 +441,7 @@ namespace NadekoBot.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Blacklist"); b.ToTable("Blacklist", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
@@ -466,7 +466,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("CommandAlias"); b.ToTable("CommandAlias", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
@@ -491,7 +491,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("CommandCooldown"); b.ToTable("CommandCooldown", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
@@ -529,7 +529,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("CurrencyTransactions"); b.ToTable("CurrencyTransactions", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.DelMsgOnCmdChannel", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.DelMsgOnCmdChannel", b =>
@@ -554,7 +554,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("DelMsgOnCmdChannel"); b.ToTable("DelMsgOnCmdChannel", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordPermOverride", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordPermOverride", b =>
@@ -580,7 +580,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId", "Command") b.HasIndex("GuildId", "Command")
.IsUnique(); .IsUnique();
b.ToTable("DiscordPermOverrides"); b.ToTable("DiscordPermOverrides", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b =>
@@ -605,7 +605,7 @@ namespace NadekoBot.Migrations
b.HasIndex("XpSettingsId"); b.HasIndex("XpSettingsId");
b.ToTable("ExcludedItem"); b.ToTable("ExcludedItem", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b =>
@@ -631,7 +631,7 @@ namespace NadekoBot.Migrations
b.HasAlternateKey("GuildConfigId", "Url"); b.HasAlternateKey("GuildConfigId", "Url");
b.ToTable("FeedSub"); b.ToTable("FeedSub", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
@@ -653,7 +653,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("FilterChannelId"); b.ToTable("FilterChannelId", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
@@ -675,7 +675,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord"); b.ToTable("FilteredWord", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterLinksChannelId", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterLinksChannelId", b =>
@@ -697,7 +697,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("FilterLinksChannelId"); b.ToTable("FilterLinksChannelId", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterWordsChannelId", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterWordsChannelId", b =>
@@ -719,7 +719,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("FilterWordsChannelId"); b.ToTable("FilterWordsChannelId", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
@@ -741,7 +741,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("GCChannelId"); b.ToTable("GCChannelId", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.GroupName", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.GroupName", b =>
@@ -767,7 +767,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId", "Number") b.HasIndex("GuildConfigId", "Number")
.IsUnique(); .IsUnique();
b.ToTable("GroupName"); b.ToTable("GroupName", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
@@ -897,7 +897,7 @@ namespace NadekoBot.Migrations
b.HasIndex("WarnExpireHours"); b.HasIndex("WarnExpireHours");
b.ToTable("GuildConfigs"); b.ToTable("GuildConfigs", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogItem", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogItem", b =>
@@ -923,7 +923,7 @@ namespace NadekoBot.Migrations
b.HasIndex("LogSettingId", "LogItemId", "ItemType") b.HasIndex("LogSettingId", "LogItemId", "ItemType")
.IsUnique(); .IsUnique();
b.ToTable("IgnoredLogChannels"); b.ToTable("IgnoredLogChannels", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
@@ -945,7 +945,7 @@ namespace NadekoBot.Migrations
b.HasIndex("LogSettingId"); b.HasIndex("LogSettingId");
b.ToTable("IgnoredVoicePresenceCHannels"); b.ToTable("IgnoredVoicePresenceCHannels", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ImageOnlyChannel", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.ImageOnlyChannel", b =>
@@ -968,7 +968,7 @@ namespace NadekoBot.Migrations
b.HasIndex("ChannelId") b.HasIndex("ChannelId")
.IsUnique(); .IsUnique();
b.ToTable("ImageOnlyChannels"); b.ToTable("ImageOnlyChannels", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
@@ -1033,7 +1033,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId") b.HasIndex("GuildId")
.IsUnique(); .IsUnique();
b.ToTable("LogSettings"); b.ToTable("LogSettings", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlayerSettings", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlayerSettings", b =>
@@ -1067,7 +1067,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId") b.HasIndex("GuildId")
.IsUnique(); .IsUnique();
b.ToTable("MusicPlayerSettings"); b.ToTable("MusicPlayerSettings", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
@@ -1090,7 +1090,7 @@ namespace NadekoBot.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("MusicPlaylists"); b.ToTable("MusicPlaylists", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
@@ -1112,7 +1112,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("MutedUserId"); b.ToTable("MutedUserId", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.NadekoExpression", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.NadekoExpression", b =>
@@ -1150,7 +1150,7 @@ namespace NadekoBot.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Expressions"); b.ToTable("Expressions", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklistedTag", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklistedTag", b =>
@@ -1172,7 +1172,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId"); b.HasIndex("GuildId");
b.ToTable("NsfwBlacklistedTags"); b.ToTable("NsfwBlacklistedTags", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b =>
@@ -1212,7 +1212,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("Permissions"); b.ToTable("Permissions", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlantedCurrency", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.PlantedCurrency", b =>
@@ -1249,7 +1249,7 @@ namespace NadekoBot.Migrations
b.HasIndex("MessageId") b.HasIndex("MessageId")
.IsUnique(); .IsUnique();
b.ToTable("PlantedCurrency"); b.ToTable("PlantedCurrency", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
@@ -1283,7 +1283,7 @@ namespace NadekoBot.Migrations
b.HasIndex("MusicPlaylistId"); b.HasIndex("MusicPlaylistId");
b.ToTable("PlaylistSong"); b.ToTable("PlaylistSong", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.Poll", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Poll", b =>
@@ -1309,7 +1309,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId") b.HasIndex("GuildId")
.IsUnique(); .IsUnique();
b.ToTable("Poll"); b.ToTable("Poll", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.PollAnswer", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.PollAnswer", b =>
@@ -1334,7 +1334,7 @@ namespace NadekoBot.Migrations
b.HasIndex("PollId"); b.HasIndex("PollId");
b.ToTable("PollAnswer"); b.ToTable("PollAnswer", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.PollVote", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.PollVote", b =>
@@ -1359,7 +1359,7 @@ namespace NadekoBot.Migrations
b.HasIndex("PollId"); b.HasIndex("PollId");
b.ToTable("PollVote"); b.ToTable("PollVote", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
@@ -1395,7 +1395,7 @@ namespace NadekoBot.Migrations
b.HasIndex("Keyword"); b.HasIndex("Keyword");
b.ToTable("Quotes"); b.ToTable("Quotes", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRole", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRole", b =>
@@ -1420,7 +1420,7 @@ namespace NadekoBot.Migrations
b.HasIndex("ReactionRoleMessageId"); b.HasIndex("ReactionRoleMessageId");
b.ToTable("ReactionRole"); b.ToTable("ReactionRole", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRoleMessage", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRoleMessage", b =>
@@ -1451,7 +1451,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("ReactionRoleMessage"); b.ToTable("ReactionRoleMessage", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
@@ -1485,7 +1485,7 @@ namespace NadekoBot.Migrations
b.HasIndex("When"); b.HasIndex("When");
b.ToTable("Reminders"); b.ToTable("Reminders", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b =>
@@ -1520,7 +1520,7 @@ namespace NadekoBot.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Repeaters"); b.ToTable("Repeaters", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b =>
@@ -1549,7 +1549,7 @@ namespace NadekoBot.Migrations
b.HasIndex("PatreonUserId") b.HasIndex("PatreonUserId")
.IsUnique(); .IsUnique();
b.ToTable("RewardedUsers"); b.ToTable("RewardedUsers", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.RotatingPlayingStatus", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.RotatingPlayingStatus", b =>
@@ -1569,7 +1569,7 @@ namespace NadekoBot.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("RotatingStatus"); b.ToTable("RotatingStatus", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
@@ -1600,7 +1600,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildId", "RoleId") b.HasIndex("GuildId", "RoleId")
.IsUnique(); .IsUnique();
b.ToTable("SelfAssignableRoles"); b.ToTable("SelfAssignableRoles", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b =>
@@ -1640,7 +1640,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("ShopEntry"); b.ToTable("ShopEntry", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b =>
@@ -1662,7 +1662,7 @@ namespace NadekoBot.Migrations
b.HasIndex("ShopEntryId"); b.HasIndex("ShopEntryId");
b.ToTable("ShopEntryItem"); b.ToTable("ShopEntryItem", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b =>
@@ -1684,7 +1684,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("SlowmodeIgnoredRole"); b.ToTable("SlowmodeIgnoredRole", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b =>
@@ -1706,7 +1706,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("SlowmodeIgnoredUser"); b.ToTable("SlowmodeIgnoredUser", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b =>
@@ -1731,7 +1731,7 @@ namespace NadekoBot.Migrations
b.HasIndex("StreamRoleSettingsId"); b.HasIndex("StreamRoleSettingsId");
b.ToTable("StreamRoleBlacklistedUser"); b.ToTable("StreamRoleBlacklistedUser", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b =>
@@ -1763,7 +1763,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId") b.HasIndex("GuildConfigId")
.IsUnique(); .IsUnique();
b.ToTable("StreamRoleSettings"); b.ToTable("StreamRoleSettings", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b =>
@@ -1788,7 +1788,7 @@ namespace NadekoBot.Migrations
b.HasIndex("StreamRoleSettingsId"); b.HasIndex("StreamRoleSettingsId");
b.ToTable("StreamRoleWhitelistedUser"); b.ToTable("StreamRoleWhitelistedUser", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnbanTimer", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.UnbanTimer", b =>
@@ -1813,7 +1813,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("UnbanTimer"); b.ToTable("UnbanTimer", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
@@ -1838,7 +1838,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("UnmuteTimer"); b.ToTable("UnmuteTimer", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnroleTimer", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.UnroleTimer", b =>
@@ -1866,7 +1866,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("UnroleTimer"); b.ToTable("UnroleTimer", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserXpStats", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.UserXpStats", b =>
@@ -1911,7 +1911,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId", "GuildId") b.HasIndex("UserId", "GuildId")
.IsUnique(); .IsUnique();
b.ToTable("UserXpStats"); b.ToTable("UserXpStats", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b =>
@@ -1936,7 +1936,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("VcRoleInfo"); b.ToTable("VcRoleInfo", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
@@ -1971,7 +1971,7 @@ namespace NadekoBot.Migrations
b.HasIndex("WaifuId") b.HasIndex("WaifuId")
.IsUnique(); .IsUnique();
b.ToTable("WaifuInfo"); b.ToTable("WaifuInfo", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b =>
@@ -1996,7 +1996,7 @@ namespace NadekoBot.Migrations
b.HasIndex("WaifuInfoId"); b.HasIndex("WaifuInfoId");
b.ToTable("WaifuItem"); b.ToTable("WaifuItem", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b =>
@@ -2028,7 +2028,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("WaifuUpdates"); b.ToTable("WaifuUpdates", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b =>
@@ -2071,7 +2071,7 @@ namespace NadekoBot.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("Warnings"); b.ToTable("Warnings", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b =>
@@ -2102,7 +2102,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId"); b.HasIndex("GuildConfigId");
b.ToTable("WarningPunishment"); b.ToTable("WarningPunishment", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpCurrencyReward", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.XpCurrencyReward", b =>
@@ -2127,7 +2127,7 @@ namespace NadekoBot.Migrations
b.HasIndex("XpSettingsId"); b.HasIndex("XpSettingsId");
b.ToTable("XpCurrencyReward"); b.ToTable("XpCurrencyReward", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b =>
@@ -2156,7 +2156,7 @@ namespace NadekoBot.Migrations
b.HasIndex("XpSettingsId", "Level") b.HasIndex("XpSettingsId", "Level")
.IsUnique(); .IsUnique();
b.ToTable("XpRoleReward"); b.ToTable("XpRoleReward", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b =>
@@ -2179,7 +2179,7 @@ namespace NadekoBot.Migrations
b.HasIndex("GuildConfigId") b.HasIndex("GuildConfigId")
.IsUnique(); .IsUnique();
b.ToTable("XpSettings"); b.ToTable("XpSettings", (string)null);
}); });
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b => modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>

View File

@@ -3,7 +3,6 @@ using NadekoBot.Db;
namespace NadekoBot.Modules.Administration.Services; namespace NadekoBot.Modules.Administration.Services;
// todo timers
public class GameVoiceChannelService : INService public class GameVoiceChannelService : INService
{ {
public ConcurrentHashSet<ulong> GameVoiceChannels { get; } public ConcurrentHashSet<ulong> GameVoiceChannels { get; }

View File

@@ -207,7 +207,6 @@ public partial class Gambling : GamblingModule<GamblingService>
=> InternalCurrencyTransactions(usr.Id, page); => InternalCurrencyTransactions(usr.Id, page);
// todo curtrs max lifetime // todo curtrs max lifetime
// todo waifu decay
private async Task InternalCurrencyTransactions(ulong userId, int page) private async Task InternalCurrencyTransactions(ulong userId, int page)
{ {
if (--page < 0) if (--page < 0)

View File

@@ -182,10 +182,14 @@ public partial class WheelOfFortuneSettings
public sealed partial class WaifuConfig public sealed partial class WaifuConfig
{ {
[Comment(@"Minimum price a waifu can have")] [Comment(@"Minimum price a waifu can have")]
public int MinPrice { get; set; } = 50; public long MinPrice { get; set; } = 50;
public MultipliersData Multipliers { get; set; } = new(); public MultipliersData Multipliers { get; set; } = new();
[Comment(@"Settings for periodic waifu price decay.
Waifu price decays only if the waifu has no claimer.")]
public WaifuDecayConfig Decay { get; set; } = new();
[Comment(@"List of items available for gifting. [Comment(@"List of items available for gifting.
If negative is true, gift will instead reduce waifu value.")] If negative is true, gift will instead reduce waifu value.")]
public List<WaifuItemModel> Items { get; set; } = new(); public List<WaifuItemModel> Items { get; set; } = new();
@@ -230,6 +234,21 @@ If negative is true, gift will instead reduce waifu value.")]
new("🚀", 30000, "Spaceship"), new("🚀", 30000, "Spaceship"),
new("🌕", 50000, "Moon") new("🌕", 50000, "Moon")
}; };
public class WaifuDecayConfig
{
[Comment(@"Percentage (0 - 100) of the waifu value to reduce.
Set 0 to disable
For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)")]
public int Percent { get; set; } = 0;
[Comment(@"How often to decay waifu values, in hours")]
public int HourInterval { get; set; } = 24;
[Comment(@"Minimum waifu price required for the decay to be applied.
For example if this value is set to 300, any waifu with the price 300 or less will not experience decay.")]
public long MinPrice { get; set; } = 300;
}
} }
[Cloneable] [Cloneable]
@@ -283,7 +302,7 @@ public sealed class SlotsConfig
public sealed partial class WaifuItemModel public sealed partial class WaifuItemModel
{ {
public string ItemEmoji { get; set; } public string ItemEmoji { get; set; }
public int Price { get; set; } public long Price { get; set; }
public string Name { get; set; } public string Name { get; set; }
[YamlMember(DefaultValuesHandling = DefaultValuesHandling.OmitDefaults)] [YamlMember(DefaultValuesHandling = DefaultValuesHandling.OmitDefaults)]
@@ -295,7 +314,7 @@ public sealed partial class WaifuItemModel
public WaifuItemModel( public WaifuItemModel(
string itemEmoji, string itemEmoji,
int price, long price,
string name, string name,
bool negative = false) bool negative = false)
{ {

View File

@@ -14,84 +14,131 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
private readonly IEnumerable<WaifuItemModel> _antiGiftSeed = new[] private readonly IEnumerable<WaifuItemModel> _antiGiftSeed = new[]
{ {
new WaifuItemModel("🥀", 100, "WiltedRose", true), new WaifuItemModel("✂️", 1000, "Haircut", true), new WaifuItemModel("🥀", 100, "WiltedRose", true),
new WaifuItemModel("✂️", 1000, "Haircut", true),
new WaifuItemModel("🧻", 10000, "ToiletPaper", true) new WaifuItemModel("🧻", 10000, "ToiletPaper", true)
}; };
public GamblingConfigService(IConfigSeria serializer, IPubSub pubSub) public GamblingConfigService(IConfigSeria serializer, IPubSub pubSub)
: base(FILE_PATH, serializer, pubSub, _changeKey) : base(FILE_PATH, serializer, pubSub, _changeKey)
{ {
AddParsedProp("currency.name", gs => gs.Currency.Name, ConfigParsers.String, ConfigPrinters.ToString); AddParsedProp("currency.name",
AddParsedProp("currency.sign", gs => gs.Currency.Sign, ConfigParsers.String, ConfigPrinters.ToString); gs => gs.Currency.Name,
ConfigParsers.String,
ConfigPrinters.ToString);
AddParsedProp("currency.sign",
gs => gs.Currency.Sign,
ConfigParsers.String,
ConfigPrinters.ToString);
AddParsedProp("minbet", gs => gs.MinBet, int.TryParse, ConfigPrinters.ToString, val => val >= 0); AddParsedProp("minbet",
AddParsedProp("maxbet", gs => gs.MaxBet, int.TryParse, ConfigPrinters.ToString, val => val >= 0); gs => gs.MinBet,
int.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("maxbet",
gs => gs.MaxBet,
int.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("gen.min", gs => gs.Generation.MinAmount, int.TryParse, ConfigPrinters.ToString, val => val >= 1); AddParsedProp("gen.min",
AddParsedProp("gen.max", gs => gs.Generation.MaxAmount, int.TryParse, ConfigPrinters.ToString, val => val >= 1); gs => gs.Generation.MinAmount,
AddParsedProp("gen.cd", gs => gs.Generation.GenCooldown, int.TryParse, ConfigPrinters.ToString, val => val > 0); int.TryParse,
ConfigPrinters.ToString,
val => val >= 1);
AddParsedProp("gen.max",
gs => gs.Generation.MaxAmount,
int.TryParse,
ConfigPrinters.ToString,
val => val >= 1);
AddParsedProp("gen.cd",
gs => gs.Generation.GenCooldown,
int.TryParse,
ConfigPrinters.ToString,
val => val > 0);
AddParsedProp("gen.chance", AddParsedProp("gen.chance",
gs => gs.Generation.Chance, gs => gs.Generation.Chance,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val is >= 0 and <= 1); val => val is >= 0 and <= 1);
AddParsedProp("gen.has_pw", gs => gs.Generation.HasPassword, bool.TryParse, ConfigPrinters.ToString);
AddParsedProp("gen.has_pw",
gs => gs.Generation.HasPassword,
bool.TryParse,
ConfigPrinters.ToString);
AddParsedProp("bf.multi", AddParsedProp("bf.multi",
gs => gs.BetFlip.Multiplier, gs => gs.BetFlip.Multiplier,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 1); val => val >= 1);
AddParsedProp("waifu.min_price", AddParsedProp("waifu.min_price",
gs => gs.Waifu.MinPrice, gs => gs.Waifu.MinPrice,
int.TryParse, long.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 0); val => val >= 0);
AddParsedProp("waifu.multi.reset", AddParsedProp("waifu.multi.reset",
gs => gs.Waifu.Multipliers.WaifuReset, gs => gs.Waifu.Multipliers.WaifuReset,
int.TryParse, int.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 0); val => val >= 0);
AddParsedProp("waifu.multi.crush_claim", AddParsedProp("waifu.multi.crush_claim",
gs => gs.Waifu.Multipliers.CrushClaim, gs => gs.Waifu.Multipliers.CrushClaim,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 0); val => val >= 0);
AddParsedProp("waifu.multi.normal_claim", AddParsedProp("waifu.multi.normal_claim",
gs => gs.Waifu.Multipliers.NormalClaim, gs => gs.Waifu.Multipliers.NormalClaim,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val > 0); val => val > 0);
AddParsedProp("waifu.multi.divorce_value", AddParsedProp("waifu.multi.divorce_value",
gs => gs.Waifu.Multipliers.DivorceNewValue, gs => gs.Waifu.Multipliers.DivorceNewValue,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val > 0); val => val > 0);
AddParsedProp("waifu.multi.all_gifts", AddParsedProp("waifu.multi.all_gifts",
gs => gs.Waifu.Multipliers.AllGiftPrices, gs => gs.Waifu.Multipliers.AllGiftPrices,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val > 0); val => val > 0);
AddParsedProp("waifu.multi.gift_effect", AddParsedProp("waifu.multi.gift_effect",
gs => gs.Waifu.Multipliers.GiftEffect, gs => gs.Waifu.Multipliers.GiftEffect,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 0); val => val >= 0);
AddParsedProp("waifu.multi.negative_gift_effect", AddParsedProp("waifu.multi.negative_gift_effect",
gs => gs.Waifu.Multipliers.NegativeGiftEffect, gs => gs.Waifu.Multipliers.NegativeGiftEffect,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 0); val => val >= 0);
AddParsedProp("decay.percent", AddParsedProp("decay.percent",
gs => gs.Decay.Percent, gs => gs.Decay.Percent,
decimal.TryParse, decimal.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val is >= 0 and <= 1); val => val is >= 0 and <= 1);
AddParsedProp("decay.maxdecay", AddParsedProp("decay.maxdecay",
gs => gs.Decay.MaxDecay, gs => gs.Decay.MaxDecay,
int.TryParse, int.TryParse,
ConfigPrinters.ToString, ConfigPrinters.ToString,
val => val >= 0); val => val >= 0);
AddParsedProp("decay.threshold", AddParsedProp("decay.threshold",
gs => gs.Decay.MinThreshold, gs => gs.Decay.MinThreshold,
int.TryParse, int.TryParse,
@@ -116,11 +163,11 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
c.Version = 3; c.Version = 3;
c.VoteReward = 100; c.VoteReward = 100;
}); });
if (data.Version < 4) if(data.Version < 5)
ModifyConfig(c => ModifyConfig(c =>
{ {
c.Version = 4; c.Version = 5;
}); });
} }
} }

View File

@@ -37,7 +37,7 @@ public partial class Gambling
[Cmd] [Cmd]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async partial Task WaifuClaim(int amount, [Leftover] IUser target) public async partial Task WaifuClaim(long amount, [Leftover] IUser target)
{ {
if (amount < Config.Waifu.MinPrice) if (amount < Config.Waifu.MinPrice)
{ {

View File

@@ -1,5 +1,7 @@
#nullable disable #nullable disable
using LinqToDB;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NadekoBot.Common.ModuleBehaviors;
using NadekoBot.Db; using NadekoBot.Db;
using NadekoBot.Db.Models; using NadekoBot.Db.Models;
using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Common;
@@ -8,23 +10,30 @@ using NadekoBot.Services.Database.Models;
namespace NadekoBot.Modules.Gambling.Services; namespace NadekoBot.Modules.Gambling.Services;
public class WaifuService : INService // todo waifu price int
public class WaifuService : INService, IReadyExecutor
{ {
private readonly DbService _db; private readonly DbService _db;
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
private readonly IDataCache _cache; private readonly IDataCache _cache;
private readonly GamblingConfigService _gss; private readonly GamblingConfigService _gss;
private readonly IBotCredentials _creds;
private readonly DiscordSocketClient _client;
public WaifuService( public WaifuService(
DbService db, DbService db,
ICurrencyService cs, ICurrencyService cs,
IDataCache cache, IDataCache cache,
GamblingConfigService gss) GamblingConfigService gss,
IBotCredentials creds,
DiscordSocketClient client)
{ {
_db = db; _db = db;
_cs = cs; _cs = cs;
_cache = cache; _cache = cache;
_gss = gss; _gss = gss;
_creds = creds;
_client = client;
} }
public async Task<bool> WaifuTransfer(IUser owner, ulong waifuId, IUser newOwner) public async Task<bool> WaifuTransfer(IUser owner, ulong waifuId, IUser newOwner)
@@ -45,11 +54,11 @@ public class WaifuService : INService
// if waifu likes the person, gotta pay the penalty // if waifu likes the person, gotta pay the penalty
if (waifu.AffinityId == ownerUser.Id) if (waifu.AffinityId == ownerUser.Id)
{ {
if (!await _cs.RemoveAsync(owner.Id, (int)(waifu.Price * 0.6), new("waifu", "affinity-penalty"))) if (!await _cs.RemoveAsync(owner.Id, (long)(waifu.Price * 0.6), new("waifu", "affinity-penalty")))
// unable to pay 60% penalty // unable to pay 60% penalty
return false; return false;
waifu.Price = (int)(waifu.Price * 0.7); // half of 60% = 30% price reduction waifu.Price = (long)(waifu.Price * 0.7); // half of 60% = 30% price reduction
if (waifu.Price < settings.Waifu.MinPrice) if (waifu.Price < settings.Waifu.MinPrice)
waifu.Price = settings.Waifu.MinPrice; waifu.Price = settings.Waifu.MinPrice;
} }
@@ -58,7 +67,7 @@ public class WaifuService : INService
if (!await _cs.RemoveAsync(owner.Id, waifu.Price / 10, new("waifu", "transfer"))) if (!await _cs.RemoveAsync(owner.Id, waifu.Price / 10, new("waifu", "transfer")))
return false; return false;
waifu.Price = (int)(waifu.Price * 0.95); // half of 10% = 5% price reduction waifu.Price = (long)(waifu.Price * 0.95); // half of 10% = 5% price reduction
if (waifu.Price < settings.Waifu.MinPrice) if (waifu.Price < settings.Waifu.MinPrice)
waifu.Price = settings.Waifu.MinPrice; waifu.Price = settings.Waifu.MinPrice;
} }
@@ -72,7 +81,7 @@ public class WaifuService : INService
return true; return true;
} }
public int GetResetPrice(IUser user) public long GetResetPrice(IUser user)
{ {
var settings = _gss.Data; var settings = _gss.Data;
using var uow = _db.GetDbContext(); using var uow = _db.GetDbContext();
@@ -91,7 +100,7 @@ public class WaifuService : INService
.GroupBy(x => x.New) .GroupBy(x => x.New)
.Count(); .Count();
return (int)Math.Ceiling(waifu.Price * 1.25f) + ((divorces + affs + 2) * settings.Waifu.Multipliers.WaifuReset); return (long)Math.Ceiling(waifu.Price * 1.25f) + ((divorces + affs + 2) * settings.Waifu.Multipliers.WaifuReset);
} }
public async Task<bool> TryReset(IUser user) public async Task<bool> TryReset(IUser user)
@@ -131,7 +140,7 @@ public class WaifuService : INService
return true; return true;
} }
public async Task<(WaifuInfo, bool, WaifuClaimResult)> ClaimWaifuAsync(IUser user, IUser target, int amount) public async Task<(WaifuInfo, bool, WaifuClaimResult)> ClaimWaifuAsync(IUser user, IUser target, long amount)
{ {
var settings = _gss.Data; var settings = _gss.Data;
WaifuClaimResult result; WaifuClaimResult result;
@@ -317,7 +326,7 @@ public class WaifuService : INService
if (w.Affinity?.UserId == user.Id) if (w.Affinity?.UserId == user.Id)
{ {
await _cs.AddAsync(w.Waifu.UserId, amount, new("waifu", "compensation")); await _cs.AddAsync(w.Waifu.UserId, amount, new("waifu", "compensation"));
w.Price = (int)Math.Floor(w.Price * _gss.Data.Waifu.Multipliers.DivorceNewValue); w.Price = (long)Math.Floor(w.Price * _gss.Data.Waifu.Multipliers.DivorceNewValue);
result = DivorceResult.SucessWithPenalty; result = DivorceResult.SucessWithPenalty;
} }
else else
@@ -370,13 +379,13 @@ public class WaifuService : INService
}); });
if (w.Claimer?.UserId == from.Id) if (w.Claimer?.UserId == from.Id)
w.Price += (int)(itemObj.Price * _gss.Data.Waifu.Multipliers.GiftEffect); w.Price += (long)(itemObj.Price * _gss.Data.Waifu.Multipliers.GiftEffect);
else else
w.Price += itemObj.Price / 2; w.Price += itemObj.Price / 2;
} }
else else
{ {
w.Price -= (int)(itemObj.Price * _gss.Data.Waifu.Multipliers.NegativeGiftEffect); w.Price -= (long)(itemObj.Price * _gss.Data.Waifu.Multipliers.NegativeGiftEffect);
if (w.Price < 1) if (w.Price < 1)
w.Price = 1; w.Price = 1;
} }
@@ -479,16 +488,65 @@ public class WaifuService : INService
var conf = _gss.Data; var conf = _gss.Data;
return conf.Waifu.Items.Select(x return conf.Waifu.Items.Select(x
=> new WaifuItemModel(x.ItemEmoji, => new WaifuItemModel(x.ItemEmoji,
(int)(x.Price * conf.Waifu.Multipliers.AllGiftPrices), (long)(x.Price * conf.Waifu.Multipliers.AllGiftPrices),
x.Name, x.Name,
x.Negative)) x.Negative))
.ToList(); .ToList();
} }
public class FullWaifuInfo public async Task OnReadyAsync()
{ {
public WaifuInfo Waifu { get; set; } // only decay waifu values from shard 0
public IEnumerable<string> Claims { get; set; } if (_client.ShardId != 0)
public int Divorces { get; set; } return;
var redisKey = $"{_creds.RedisKey()}_last_waifu_decay";
while (true)
{
try
{
var multi = _gss.Data.Waifu.Decay.Percent / 100f;
var minPrice = _gss.Data.Waifu.Decay.MinPrice;
var decayInterval = _gss.Data.Waifu.Decay.HourInterval;
if (multi is < 0f or > 1f || decayInterval < 0)
{
continue;
}
var val = await _cache.Redis.GetDatabase().StringGetAsync(redisKey);
if (val != default)
{
var lastDecay = DateTime.FromBinary((long)val);
var toWait = decayInterval.Hours() - (DateTime.UtcNow - lastDecay);
if (toWait > 0.Hours())
{
continue;
}
}
await _cache.Redis.GetDatabase().StringSetAsync(redisKey, DateTime.UtcNow.ToBinary());
await using var uow = _db.GetDbContext();
await uow.WaifuInfo
.Where(x => x.Price > minPrice && x.ClaimerId == null)
.UpdateAsync(old => new()
{
Price = (long)(old.Price * multi)
});
await uow.SaveChangesAsync();
}
catch (Exception ex)
{
Log.Error(ex, "Unexpected error occured in waifu decay loop: {ErrorMessage}", ex.Message);
}
finally
{
await Task.Delay(1.Hours());
}
}
} }
} }

View File

@@ -1,5 +1,5 @@
# DO NOT CHANGE # DO NOT CHANGE
version: 4 version: 5
# Currency settings # Currency settings
currency: currency:
# What is the emoji/character which represents the currency # What is the emoji/character which represents the currency
@@ -34,28 +34,28 @@ generation:
# in order to get it # in order to get it
hasPassword: true hasPassword: true
# Every message sent has a certain % chance to generate the currency # Every message sent has a certain % chance to generate the currency
# specify the percentage here (1 being 100%, 0 being 0% - for example # specify the percentage here (1 being 100%, 0 being 0% - for example
# default is 0.02, which is 2% # default is 0.02, which is 2%
chance: 0.02 chance: 0.02
# How many seconds have to pass for the next message to have a chance to spawn currency # How many seconds have to pass for the next message to have a chance to spawn currency
genCooldown: 10 genCooldown: 10
# Minimum amount of currency that can spawn # Minimum amount of currency that can spawn
minAmount: 1 minAmount: 1
# Maximum amount of currency that can spawn. # Maximum amount of currency that can spawn.
# Set to the same value as MinAmount to always spawn the same amount # Set to the same value as MinAmount to always spawn the same amount
maxAmount: 1 maxAmount: 1
# Settings for timely command # Settings for timely command
# (letting people claim X amount of currency every Y hours) # (letting people claim X amount of currency every Y hours)
timely: timely:
# How much currency will the users get every time they run .timely command # How much currency will the users get every time they run .timely command
# setting to 0 or less will disable this feature # setting to 0 or less will disable this feature
amount: 0 amount: 0
# How often (in hours) can users claim currency with .timely command # How often (in hours) can users claim currency with .timely command
# setting to 0 or less will disable this feature # setting to 0 or less will disable this feature
cooldown: 24 cooldown: 24
# How much will each user's owned currency decay over time. # How much will each user's owned currency decay over time.
decay: decay:
# Percentage of user's current currency which will be deducted every 24h. # Percentage of user's current currency which will be deducted every 24h.
# 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) # 0 - 1 (1 is 100%, 0.5 50%, 0 disabled)
percent: 0 percent: 0
# Maximum amount of user's currency that can decay at each interval. 0 for unlimited. # Maximum amount of user's currency that can decay at each interval. 0 for unlimited.
@@ -82,37 +82,49 @@ waifu:
minPrice: 50 minPrice: 50
multipliers: multipliers:
# Multiplier for waifureset. Default 150. # Multiplier for waifureset. Default 150.
# Formula (at the time of writing this): # Formula (at the time of writing this):
# price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up # price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up
waifuReset: 150 waifuReset: 150
# The minimum amount of currency that you have to pay # The minimum amount of currency that you have to pay
# in order to buy a waifu who doesn't have a crush on you. # in order to buy a waifu who doesn't have a crush on you.
# Default is 1.1 # Default is 1.1
# Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her. # Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her.
# (100 * 1.1 = 110) # (100 * 1.1 = 110)
normalClaim: 1.1 normalClaim: 1.1
# The minimum amount of currency that you have to pay # The minimum amount of currency that you have to pay
# in order to buy a waifu that has a crush on you. # in order to buy a waifu that has a crush on you.
# Default is 0.88 # Default is 0.88
# Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her. # Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her.
# (100 * 0.88 = 88) # (100 * 0.88 = 88)
crushClaim: 0.88 crushClaim: 0.88
# When divorcing a waifu, her new value will be her current value multiplied by this number. # When divorcing a waifu, her new value will be her current value multiplied by this number.
# Default 0.75 (meaning will lose 25% of her value) # Default 0.75 (meaning will lose 25% of her value)
divorceNewValue: 0.75 divorceNewValue: 0.75
# All gift prices will be multiplied by this number. # All gift prices will be multiplied by this number.
# Default 1 (meaning no effect) # Default 1 (meaning no effect)
allGiftPrices: 1.0 allGiftPrices: 1.0
# What percentage of the value of the gift will a waifu gain when she's gifted. # What percentage of the value of the gift will a waifu gain when she's gifted.
# Default 0.95 (meaning 95%) # Default 0.95 (meaning 95%)
# Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095) # Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095)
giftEffect: 0.95 giftEffect: 0.95
# What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'. # What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'.
# Default 0.5 (meaning 50%) # Default 0.5 (meaning 50%)
# Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950) # Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950)
negativeGiftEffect: 0.50 negativeGiftEffect: 0.50
# Settings for periodic waifu price decay.
# Waifu price decays only if the waifu has no claimer.
decay:
# Percentage (0 - 100) of the waifu value to reduce.
# Set 0 to disable
# For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)
percent: 0
# How often to decay waifu values, in hours
hourInterval: 24
# Minimum waifu price required for the decay to be applied.
# For example if this value is set to 300, any waifu with the price 300 or less will not experience decay.
minPrice: 300
# List of items available for gifting. # List of items available for gifting.
# If negative is true, gift will instead reduce waifu value. # If negative is true, gift will instead reduce waifu value.
items: items:
- itemEmoji: "🥔" - itemEmoji: "🥔"
price: 5 price: 5