diff --git a/Discord.Net b/Discord.Net index f27cce08..58766448 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit f27cce0854abc42b92d29f9040625238a8991999 +Subproject commit 58766448d79ac9adec228f341f258aa262a3f278 diff --git a/docs/Commands List.md b/docs/Commands List.md index 1d354c4a..ed71757c 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -125,6 +125,14 @@ Command and aliases | Description | Usage ### Gambling Command and aliases | Description | Usage ----------------|--------------|------- +`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama` +`$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot` +`$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity` +`$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus` +`$waifuinfo` `$waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `$waifuinfo @MyCrush` or `$waifuinfo` +`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot Owner only.** | `$slotstats` +`$slottest` | Tests to see how much slots payout for X number of plays. **Bot Owner only.** | `$slottest 1000` +`$slot` | Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. | `$slot 5` `$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3` `$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet. | `$bf 5 heads` or `$bf 3 t` `$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5` @@ -132,6 +140,7 @@ Command and aliases | Description | Usage `$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. Y can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF` `$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` +`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction` `$race` | Starts a new animal race. | `$race` `$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5` `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName` @@ -206,7 +215,6 @@ Command and aliases | Description | Usage `!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot Owner only.** | `!!lopl C:/music/classical` `!!radio` `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `!!ra radio link here` `!!local` `!!lo` | Queues a local file by specifying a full path. **Bot Owner only.** | `!!lo C:/music/mysong.mp3` -`!!move` `!!mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!!mv` `!!remove` `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5` `!!movesong` `!!ms` | Moves a song from one position to another. | `!!ms 5>3` `!!setmaxqueue` `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq 50` or `!!smq` @@ -226,7 +234,7 @@ Command and aliases | Description | Usage Command and aliases | Description | Usage ----------------|--------------|------- `~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri` -`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. | `~autohentai 30 yuri|tail|long_hair` or `~autohentai` +`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai` `~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri` `~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~danbooru yuri+kissing` `~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2` @@ -249,6 +257,7 @@ Command and aliases | Description | Usage `;chnlfilterwords` `;cfw` | Toggles automatic deleting of messages containing banned words on the channel. Does not negate the ;srvrfilterwords enabled setting. Does not affect bot owner. | `;cfw` `;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop` `;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw` +`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2` `;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set to 0 to remove the cooldown. | `;cmdcd "some cmd" 5` `;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds` `;ubl` | Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. **Bot Owner only.** | `;ubl add @SomeUser` or `;ubl rem 12312312313` diff --git a/docs/guides/Windows Guide.md b/docs/guides/Windows Guide.md index 1f996b1c..0d569909 100644 --- a/docs/guides/Windows Guide.md +++ b/docs/guides/Windows Guide.md @@ -16,8 +16,8 @@ ________________________________________________________________________________ ####Guide - Make sure you have installed both [Git][Git] and the [.NET Core SDK][.NET Core SDK]. - Create a **new folder** anywhere you like and name it `Nadeko`. -- Next, [Right-Click on this link](https://github.com/Kwoth/NadekoBotInstallerWin/raw/master/NadekoInstaller.bat) and select **Save link as** and save the file `NadekoInstaller.bat` inside the `Nadeko` folder that we created earlier. (**DO NOT** rename the file `NadekoInstaller.bat`) -- Once that's done, double-click on `NadekoInstaller.bat` to run it. +- Next, [Right-Click on this link](https://github.com/Kwoth/NadekoBotInstallerWin/raw/master/NadekoInstaller.bat) and select **Save link as** and save the file `NadekoInstaller.bat` inside the `Nadeko` folder that we created earlier. (Please **DO NOT** rename the file `NadekoInstaller.bat`.) +- Once that's done, right-click on `NadekoInstaller.bat` to run it as Administrator. - From the options, - Choose `1` to get the **most recent build**. - Choose `2` to get the **stable build**. @@ -58,7 +58,7 @@ ________________________________________________________________________________ - The bot should have been added to your server. ####Starting the bot -- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file. +- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file as Administrator. - From the options, - Choose `3` to **run the bot normally**. (with normal-run the bot will shutdown and will stay offline if it disconnects by the use of `.die` command until you manually run it again. Useful if you want to test the bot.) @@ -83,6 +83,16 @@ ________________________________________________________________________________ In order to have a functioning music module, you need to install ffmpeg and setup api keys. +#### Setting up `ffmpeg` using NadekoBot Client! +- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file as Administrator. +- From the options select `6` Install ffmpeg (for music) +- Next, **Press Any Key** if you are running as Administrator or just close and relaunch it as Administrator using mouse right-click. +- Wait for it to finish installing and backing up existing. +- Once done, you should see "ffmpeg Installation complete!". +- Next, **Press Any Key** to go back to NadekoBot Client. +- Press `3` to run the bot normally just to test music. (optional) +- `ffmpeg` installation for Music is now complete. + #### Manual `ffmpeg` setup - Create a folder named `ffmpeg` in your main Windows directory. We will use **C:\ffmpeg** (for our guide) - Download FFMPEG through the link https://ffmpeg.zeranoe.com/builds/ (download static build) diff --git a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs index ad0af9e3..e29e5c8c 100644 --- a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs +++ b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Migrations name: "BetflipMultiplier", table: "BotConfig", nullable: false, - defaultValue: 1.8f); + defaultValue: 1.95f); migrationBuilder.AddColumn( name: "Betroll100Multiplier", @@ -30,7 +30,7 @@ namespace NadekoBot.Migrations name: "Betroll91Multiplier", table: "BotConfig", nullable: false, - defaultValue: 3f); + defaultValue: 4f); migrationBuilder.AddColumn( name: "CurrencyDropAmount", @@ -42,7 +42,7 @@ namespace NadekoBot.Migrations name: "MinimumBetAmount", table: "BotConfig", nullable: false, - defaultValue: 3); + defaultValue: 2); migrationBuilder.AddColumn( name: "TriviaCurrencyReward", diff --git a/src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs new file mode 100644 index 00000000..b13f8275 --- /dev/null +++ b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs @@ -0,0 +1,988 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170118202307_ok-error-colors")] + partial class okerrorcolors + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs new file mode 100644 index 00000000..b52bee10 --- /dev/null +++ b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class okerrorcolors : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ErrorColor", + table: "BotConfig", + nullable: false, + defaultValue: "ee281f"); + + migrationBuilder.AddColumn( + name: "OkColor", + table: "BotConfig", + nullable: false, + defaultValue: "71cd40"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ErrorColor", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "OkColor", + table: "BotConfig"); + } + } +} diff --git a/src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs b/src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs new file mode 100644 index 00000000..46eebfab --- /dev/null +++ b/src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs @@ -0,0 +1,1089 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170122044958_waifus")] + partial class waifus + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170122044958_waifus.cs b/src/NadekoBot/Migrations/20170122044958_waifus.cs new file mode 100644 index 00000000..4396ae77 --- /dev/null +++ b/src/NadekoBot/Migrations/20170122044958_waifus.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class waifus : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DiscordUser", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AvatarId = table.Column(nullable: true), + Discriminator = table.Column(nullable: true), + UserId = table.Column(nullable: false), + Username = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DiscordUser", x => x.Id); + table.UniqueConstraint("AK_DiscordUser_UserId", x => x.UserId); + }); + + migrationBuilder.CreateTable( + name: "WaifuInfo", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AffinityId = table.Column(nullable: true), + ClaimerId = table.Column(nullable: true), + Price = table.Column(nullable: false), + WaifuId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WaifuInfo", x => x.Id); + table.ForeignKey( + name: "FK_WaifuInfo_DiscordUser_AffinityId", + column: x => x.AffinityId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuInfo_DiscordUser_ClaimerId", + column: x => x.ClaimerId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuInfo_DiscordUser_WaifuId", + column: x => x.WaifuId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "WaifuUpdates", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + NewId = table.Column(nullable: true), + OldId = table.Column(nullable: true), + UpdateType = table.Column(nullable: false), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WaifuUpdates", x => x.Id); + table.ForeignKey( + name: "FK_WaifuUpdates_DiscordUser_NewId", + column: x => x.NewId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuUpdates_DiscordUser_OldId", + column: x => x.OldId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuUpdates_DiscordUser_UserId", + column: x => x.UserId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_WaifuInfo_AffinityId", + table: "WaifuInfo", + column: "AffinityId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuInfo_ClaimerId", + table: "WaifuInfo", + column: "ClaimerId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuInfo_WaifuId", + table: "WaifuInfo", + column: "WaifuId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_WaifuUpdates_NewId", + table: "WaifuUpdates", + column: "NewId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuUpdates_OldId", + table: "WaifuUpdates", + column: "OldId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuUpdates_UserId", + table: "WaifuUpdates", + column: "UserId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "WaifuInfo"); + + migrationBuilder.DropTable( + name: "WaifuUpdates"); + + migrationBuilder.DropTable( + name: "DiscordUser"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 91f7b6fc..dd9bb84d 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; namespace NadekoBot.Migrations { @@ -118,6 +120,8 @@ namespace NadekoBot.Migrations b.Property("DMHelpString"); + b.Property("ErrorColor"); + b.Property("ForwardMessages"); b.Property("ForwardToAllOwners"); @@ -128,6 +132,8 @@ namespace NadekoBot.Migrations b.Property("MinimumBetAmount"); + b.Property("OkColor"); + b.Property("RemindMessageFormat"); b.Property("RotatingStatuses"); @@ -293,6 +299,26 @@ namespace NadekoBot.Migrations b.ToTable("CustomReactions"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => { b.Property("Id") @@ -811,6 +837,55 @@ namespace NadekoBot.Migrations b.ToTable("PokeGame"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") @@ -976,6 +1051,38 @@ namespace NadekoBot.Migrations .WithMany("RaceAnimals") .HasForeignKey("BotConfigId"); }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); } } } diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 6cb49f71..85092dc7 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Gambling str = $"{Context.User.Mention}`Better luck next time.`"; } - await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), "coin.jpg", str).ConfigureAwait(false); + await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), new FileInfo(imgPathToSend).Name, str).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs new file mode 100644 index 00000000..e1671a6d --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -0,0 +1,304 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Gambling +{ + public partial class Gambling + { + [Group] + public class Slots : ModuleBase + { + private static int totalBet = 0; + private static int totalPaidOut = 0; + + private const string backgroundPath = "data/slots/background.png"; + + private static readonly byte[] backgroundBuffer; + private static readonly byte[][] numbersBuffer = new byte[10][]; + private static readonly byte[][] emojiBuffer; + + const int alphaCutOut = byte.MaxValue / 3; + + static Slots() + { + backgroundBuffer = File.ReadAllBytes(backgroundPath); + + for (int i = 0; i < 10; i++) + { + numbersBuffer[i] = File.ReadAllBytes("data/slots/" + i + ".png"); + } + int throwaway; + var emojiFiles = Directory.GetFiles("data/slots/emojis/", "*.png") + .Where(f => int.TryParse(Path.GetFileNameWithoutExtension(f), out throwaway)) + .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) + .ToArray(); + + emojiBuffer = new byte[emojiFiles.Length][]; + for (int i = 0; i < emojiFiles.Length; i++) + { + emojiBuffer[i] = File.ReadAllBytes(emojiFiles[i]); + } + } + + + private static MemoryStream InternalGetStream(string path) + { + var ms = new MemoryStream(); + using (var fs = File.Open(path, FileMode.Open)) + { + fs.CopyTo(ms); + fs.Flush(); + } + ms.Position = 0; + return ms; + } + + //here is a payout chart + //https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg + //thanks to judge for helping me with this + + public class SlotMachine + { + public const int MaxValue = 5; + + static readonly List> winningCombos = new List>() + { + //three flowers + (arr) => arr.All(a=>a==MaxValue) ? 30 : 0, + //three of the same + (arr) => !arr.Any(a => a != arr[0]) ? 10 : 0, + //two flowers + (arr) => arr.Count(a => a == MaxValue) == 2 ? 4 : 0, + //one flower + (arr) => arr.Any(a => a == MaxValue) ? 1 : 0, + }; + + public static SlotResult Pull() + { + var numbers = new int[3]; + for (int i = 0; i < numbers.Length; i++) + { + numbers[i] = new NadekoRandom().Next(0, MaxValue + 1); + } + int multi = 0; + for (int i = 0; i < winningCombos.Count; i++) + { + multi = winningCombos[i](numbers); + if (multi != 0) + break; + } + + return new SlotResult(numbers, multi); + } + + public struct SlotResult + { + public int[] Numbers { get; } + public int Multiplier { get; } + public SlotResult(int[] nums, int multi) + { + this.Numbers = nums; + this.Multiplier = multi; + } + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task SlotStats() + { + //i remembered to not be a moron + var paid = totalPaidOut; + var bet = totalBet; + + if (bet <= 0) + bet = 1; + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle("Slot Stats") + .AddField(efb => efb.WithName("Total Bet").WithValue(bet.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("Paid Out").WithValue(paid.ToString()).WithIsInline(true)) + .WithFooter(efb => efb.WithText($"Payout Rate: {paid * 1.0 / bet * 100:f4}%")); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task SlotTest(int tests = 1000) + { + if (tests <= 0) + return; + //multi vs how many times it occured + var dict = new Dictionary(); + for (int i = 0; i < tests; i++) + { + var res = SlotMachine.Pull(); + if (dict.ContainsKey(res.Multiplier)) + dict[res.Multiplier] += 1; + else + dict.Add(res.Multiplier, 1); + } + + var sb = new StringBuilder(); + const int bet = 1; + int payout = 0; + foreach (var key in dict.Keys.OrderByDescending(x=>x)) + { + sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); + payout += key * dict[key]; + } + await Context.Channel.SendConfirmAsync("Slot Test Results", sb.ToString(), + footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + } + + static HashSet runningUsers = new HashSet(); + [NadekoCommand, Usage, Description, Aliases] + public async Task Slot(int amount = 0) + { + if (!runningUsers.Add(Context.User.Id)) + return; + try + { + if (amount < 1) + { + await Context.Channel.SendErrorAsync($"You can't bet less than 1{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + return; + } + + if (amount > 999) + { + await Context.Channel.SendErrorAsync($"You can't bet more than 999{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + return; + } + + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Slot Machine", amount, false)) + { + await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencySign}.").ConfigureAwait(false); + return; + } + Interlocked.Add(ref totalBet, amount); + using (var bgFileStream = new MemoryStream(backgroundBuffer)) + { + var bgImage = new ImageSharp.Image(bgFileStream); + + var result = SlotMachine.Pull(); + int[] numbers = result.Numbers; + using (var bgPixels = bgImage.Lock()) + { + for (int i = 0; i < 3; i++) + { + using (var file = new MemoryStream(emojiBuffer[numbers[i]])) + { + var randomImage = new ImageSharp.Image(file); + using (var toAdd = randomImage.Lock()) + { + for (int j = 0; j < toAdd.Width; j++) + { + for (int k = 0; k < toAdd.Height; k++) + { + var x = 95 + 142 * i + j; + int y = 330 + k; + var toSet = toAdd[j, k]; + if (toSet.A < alphaCutOut) + continue; + bgPixels[x, y] = toAdd[j, k]; + } + } + } + } + } + + var won = amount * result.Multiplier; + var printWon = won; + var n = 0; + do + { + var digit = printWon % 10; + using (var fs = new MemoryStream(numbersBuffer[digit])) + { + var img = new ImageSharp.Image(fs); + using (var pixels = img.Lock()) + { + for (int i = 0; i < pixels.Width; i++) + { + for (int j = 0; j < pixels.Height; j++) + { + if (pixels[i, j].A < alphaCutOut) + continue; + var x = 230 - n * 16 + i; + bgPixels[x, 462 + j] = pixels[i, j]; + } + } + } + } + n++; + } while ((printWon /= 10) != 0); + + var printAmount = amount; + n = 0; + do + { + var digit = printAmount % 10; + using (var fs = new MemoryStream(numbersBuffer[digit])) + { + var img = new ImageSharp.Image(fs); + using (var pixels = img.Lock()) + { + for (int i = 0; i < pixels.Width; i++) + { + for (int j = 0; j < pixels.Height; j++) + { + if (pixels[i, j].A < alphaCutOut) + continue; + var x = 395 - n * 16 + i; + bgPixels[x, 462 + j] = pixels[i, j]; + } + } + } + } + n++; + } while ((printAmount /= 10) != 0); + } + + var msg = "Better luck next time ^_^"; + if (result.Multiplier != 0) + { + await CurrencyHandler.AddCurrencyAsync(Context.User, $"Slot Machine x{result.Multiplier}", amount * result.Multiplier, false); + Interlocked.Add(ref totalPaidOut, amount * result.Multiplier); + if (result.Multiplier == 1) + msg = $"A single {NadekoBot.BotConfig.CurrencySign}, x1 - Try again!"; + else if (result.Multiplier == 4) + msg = $"Good job! Two {NadekoBot.BotConfig.CurrencySign} - bet x4"; + else if (result.Multiplier == 10) + msg = "Wow! Lucky! Three of a kind! x10"; + else if (result.Multiplier == 30) + msg = "WOAAHHHHHH!!! Congratulations!!! x30"; + } + + await Context.Channel.SendFileAsync(bgImage.ToStream(), "result.png", Context.User.Mention + " " + msg + $"\n`Bet:`{amount} `Won:` {amount * result.Multiplier}{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + } + } + finally + { + var t = Task.Run(async () => + { + await Task.Delay(3000); + runningUsers.Remove(Context.User.Id); + }); + } + } + } + } +} diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs new file mode 100644 index 00000000..3a365bf0 --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -0,0 +1,516 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Gambling +{ + public partial class Gambling + { + public enum ClaimTitles + { + Lonely, + Devoted, + Rookie, + Schemer, + Dilettante, + Intermediate, + Seducer, + Expert, + Veteran, + Incubis, + Harem_King, + Harem_God, + } + + public enum AffinityTitles + { + Pure, + Faithful, + Defiled, + Cheater, + Tainted, + Corrupted, + Lewd, + Sloot, + Depraved, + Harlot + } + + [Group] + public class WaifuClaimCommands : ModuleBase + { + private static ConcurrentDictionary _divorceCooldowns { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary _affinityCooldowns { get; } = new ConcurrentDictionary(); + + enum WaifuClaimResult + { + Success, + NotEnoughFunds, + InsufficientAmount + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuClaim(int amount, [Remainder]IUser target) + { + if (amount < 50) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} No waifu is that cheap. You must pay at least 50{NadekoBot.BotConfig.CurrencySign} to get a waifu, even if their actual value is lower.").ConfigureAwait(false); + return; + } + + if (target.Id == Context.User.Id) + { + await Context.Channel.SendErrorAsync(Context.User.Mention + " You can't claim yourself.").ConfigureAwait(false); + return; + } + + WaifuClaimResult result = WaifuClaimResult.NotEnoughFunds; + int? oldPrice = null; + WaifuInfo w; + var isAffinity = false; + using (var uow = DbHandler.UnitOfWork()) + { + w = uow.Waifus.ByWaifuUserId(target.Id); + isAffinity = (w?.Affinity?.UserId == Context.User.Id); + if (w == null) + { + var claimer = uow.DiscordUsers.GetOrCreate(Context.User); + var waifu = uow.DiscordUsers.GetOrCreate(target); + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) + { + result = WaifuClaimResult.NotEnoughFunds; + } + else + { + uow.Waifus.Add(w = new WaifuInfo() + { + Waifu = waifu, + Claimer = claimer, + Affinity = null, + Price = amount + }); + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = waifu, + Old = null, + New = claimer, + UpdateType = WaifuUpdateType.Claimed + }); + result = WaifuClaimResult.Success; + } + } + else if (isAffinity && amount >= w.Price * 0.88f) + { + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) + { + result = WaifuClaimResult.NotEnoughFunds; + } + else + { + var oldClaimer = w.Claimer; + w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User); + oldPrice = w.Price; + w.Price = amount + (amount / 4); + result = WaifuClaimResult.Success; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldClaimer, + New = w.Claimer, + UpdateType = WaifuUpdateType.Claimed + }); + } + } + else if (amount >= w.Price * 1.1f) // if no affinity + { + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) + { + result = WaifuClaimResult.NotEnoughFunds; + } + else + { + var oldClaimer = w.Claimer; + w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User); + oldPrice = w.Price; + w.Price = amount; + result = WaifuClaimResult.Success; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldClaimer, + New = w.Claimer, + UpdateType = WaifuUpdateType.Claimed + }); + } + } + else + result = WaifuClaimResult.InsufficientAmount; + + + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (result == WaifuClaimResult.InsufficientAmount) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must pay {Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))} or more to claim that waifu!").ConfigureAwait(false); + return; + } + else if (result == WaifuClaimResult.NotEnoughFunds) + { + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} you don't have {amount}{NadekoBot.BotConfig.CurrencySign}!") + .ConfigureAwait(false); + } + else + { + var msg = $"{Context.User.Mention} claimed {target.Mention} as their waifu for {amount}{NadekoBot.BotConfig.CurrencySign}!"; + if (w.Affinity?.UserId == Context.User.Id) + msg += $"\n🎉 Their love is fulfilled! 🎉\n**{target}'s** new value is {w.Price}{NadekoBot.BotConfig.CurrencySign}!"; + await Context.Channel.SendConfirmAsync(msg) + .ConfigureAwait(false); + } + } + + public enum DivorceResult + { + Success, + SucessWithPenalty, + NotYourWife, + Cooldown + } + + + private static readonly TimeSpan DivorceLimit = TimeSpan.FromHours(6); + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Divorce([Remainder]IUser target) + { + var channel = (ITextChannel)Context.Channel; + + if (target.Id == Context.User.Id) + return; + + var result = DivorceResult.NotYourWife; + TimeSpan difference = TimeSpan.Zero; + var amount = 0; + WaifuInfo w = null; + using (var uow = DbHandler.UnitOfWork()) + { + w = uow.Waifus.ByWaifuUserId(target.Id); + var now = DateTime.UtcNow; + if (w == null || w.Claimer == null || w.Claimer.UserId != Context.User.Id) + result = DivorceResult.NotYourWife; + else if (_divorceCooldowns.AddOrUpdate(Context.User.Id, + now, + (key, old) => ((difference = now.Subtract(old)) > DivorceLimit) ? now : old) != now) + { + result = DivorceResult.Cooldown; + } + else + { + amount = w.Price / 2; + + if (w.Affinity?.UserId == Context.User.Id) + { + await CurrencyHandler.AddCurrencyAsync(w.Waifu.UserId, "Waifu Compensation", amount, uow).ConfigureAwait(false); + w.Price = (int)Math.Floor(w.Price * 0.75f); + result = DivorceResult.SucessWithPenalty; + } + else + { + await CurrencyHandler.AddCurrencyAsync(Context.User.Id, "Waifu Refund", amount, uow).ConfigureAwait(false); + + result = DivorceResult.Success; + } + var oldClaimer = w.Claimer; + w.Claimer = null; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldClaimer, + New = null, + UpdateType = WaifuUpdateType.Claimed + }); + } + + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (result == DivorceResult.SucessWithPenalty) + { + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who likes you. You heartless monster.\n{w.Waifu} received {amount}{NadekoBot.BotConfig.CurrencySign} as a compensation.").ConfigureAwait(false); + } + else if (result == DivorceResult.Success) + { + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who doesn't like you. You received {amount}{NadekoBot.BotConfig.CurrencySign} back.").ConfigureAwait(false); + } + else if (result == DivorceResult.NotYourWife) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} That waifu is not yours.").ConfigureAwait(false); + } + else + { + var remaining = DivorceLimit.Subtract(difference); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You divorced recently. You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** to divorce again.").ConfigureAwait(false); + } + } + + private static readonly TimeSpan AffinityLimit = TimeSpan.FromMinutes(30); + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuClaimerAffinity([Remainder]IUser u = null) + { + if (u?.Id == Context.User.Id) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} you can't set affinity to yourself, you egomaniac.").ConfigureAwait(false); + return; + } + DiscordUser oldAff = null; + var sucess = false; + var cooldown = false; + TimeSpan difference = TimeSpan.Zero; + using (var uow = DbHandler.UnitOfWork()) + { + var w = uow.Waifus.ByWaifuUserId(Context.User.Id); + var newAff = u == null ? null : uow.DiscordUsers.GetOrCreate(u); + var now = DateTime.UtcNow; + if (w?.Affinity?.UserId == u?.Id) + { + sucess = false; + } + else if (_affinityCooldowns.AddOrUpdate(Context.User.Id, + now, + (key, old) => ((difference = now.Subtract(old)) > AffinityLimit) ? now : old) != now) + { + sucess = false; + cooldown = true; + } + else if (w == null) + { + var thisUser = uow.DiscordUsers.GetOrCreate(Context.User); + uow.Waifus.Add(new WaifuInfo() + { + Affinity = newAff, + Waifu = thisUser, + Price = 1, + Claimer = null + }); + sucess = true; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = thisUser, + Old = null, + New = newAff, + UpdateType = WaifuUpdateType.AffinityChanged + }); + } + else + { + if (w.Affinity != null) + oldAff = w.Affinity; + w.Affinity = newAff; + sucess = true; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldAff, + New = newAff, + UpdateType = WaifuUpdateType.AffinityChanged + }); + } + + await uow.CompleteAsync().ConfigureAwait(false); + } + if (!sucess) + { + if (cooldown) + { + var remaining = AffinityLimit.Subtract(difference); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** in order to change your affinity again.").ConfigureAwait(false); + } + else + await Context.Channel.SendErrorAsync($"{Context.User.Mention} your affinity is already set to that waifu or you're trying to remove your affinity while not having one.").ConfigureAwait(false); + return; + } + if (u == null) + await Context.Channel.SendConfirmAsync("Affinity Reset", $"{Context.User.Mention} Your affinity is reset. You no longer have a person you like.").ConfigureAwait(false); + else if (oldAff == null) + await Context.Channel.SendConfirmAsync("Affinity Set", $"{Context.User.Mention} wants to be {u.Mention}'s waifu. Aww <3").ConfigureAwait(false); + else + await Context.Channel.SendConfirmAsync("Affinity Changed", $"{Context.User.Mention} changed their affinity from {oldAff} to {u.Mention}.\n\n*This is morally questionable.*🤔").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuLeaderboard() + { + IList waifus; + using (var uow = DbHandler.UnitOfWork()) + { + waifus = uow.Waifus.GetTop(9); + } + + if (waifus.Count == 0) + { + await Context.Channel.SendConfirmAsync("No waifus have been claimed yet.").ConfigureAwait(false); + return; + } + + var embed = new EmbedBuilder() + .WithTitle("Top Waifus") + .WithOkColor(); + + for (int i = 0; i < waifus.Count; i++) + { + var w = waifus[i]; + + embed.AddField(efb => efb.WithName("#" + (i + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false)); + } + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuInfo([Remainder]IUser target = null) + { + if (target == null) + target = Context.User; + WaifuInfo w; + IList claims; + int divorces = 0; + using (var uow = DbHandler.UnitOfWork()) + { + w = uow.Waifus.ByWaifuUserId(target.Id); + claims = uow.Waifus.ByClaimerUserId(target.Id); + divorces = uow._context.WaifuUpdates.Count(x => x.Old != null && + x.Old.UserId == target.Id && + x.UpdateType == WaifuUpdateType.Claimed && + x.New == null); + if (w == null) + uow.Waifus.Add(w = new WaifuInfo() + { + Affinity = null, + Claimer = null, + Price = 1, + Waifu = uow.DiscordUsers.GetOrCreate(target), + }); + await uow.CompleteAsync().ConfigureAwait(false); + } + + var claimInfo = GetClaimTitle(target.Id); + var affInfo = GetAffinityTitle(target.Id); + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle("Waifu " + w.Waifu.ToString() + " - \"the " + claimInfo.Title + "\"") + .AddField(efb => efb.WithName("Price").WithValue(w.Price.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("Claimed by").WithValue(w.Claimer?.ToString() ?? "No one").WithIsInline(true)) + .AddField(efb => efb.WithName("Likes").WithValue(w.Affinity?.ToString() ?? "Nobody").WithIsInline(true)) + .AddField(efb => efb.WithName("Changes Of Heart").WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true)) + .AddField(efb => efb.WithName("Divorces").WithValue(divorces.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? "Nobody" : string.Join("\n", claims.Select(x => x.Waifu))).WithIsInline(true)); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + + public struct WaifuProfileTitle + { + public int Count { get; } + public string Title { get; } + + public WaifuProfileTitle(int count, string title) + { + Count = count; + Title = title; + } + } + + private static WaifuProfileTitle GetClaimTitle(ulong userId) + { + int count = 0; + using (var uow = DbHandler.UnitOfWork()) + { + count = uow.Waifus.ByClaimerUserId(userId).Count; + } + + ClaimTitles title = ClaimTitles.Lonely; + if (count == 0) + title = ClaimTitles.Lonely; + else if (count == 1) + title = ClaimTitles.Devoted; + else if (count < 4) + title = ClaimTitles.Rookie; + else if (count < 6) + title = ClaimTitles.Schemer; + else if (count < 8) + title = ClaimTitles.Dilettante; + else if (count < 10) + title = ClaimTitles.Intermediate; + else if (count < 12) + title = ClaimTitles.Seducer; + else if (count < 15) + title = ClaimTitles.Expert; + else if (count < 17) + title = ClaimTitles.Veteran; + else if (count < 25) + title = ClaimTitles.Incubis; + else if (count < 50) + title = ClaimTitles.Harem_King; + else + title = ClaimTitles.Harem_God; + + return new WaifuProfileTitle(count, title.ToString().Replace('_', ' ')); + } + + private static WaifuProfileTitle GetAffinityTitle(ulong userId) + { + int count = 0; + using (var uow = DbHandler.UnitOfWork()) + { + count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged); + } + + AffinityTitles title = AffinityTitles.Pure; + if (count < 1) + title = AffinityTitles.Pure; + else if (count < 2) + title = AffinityTitles.Faithful; + else if (count < 4) + title = AffinityTitles.Defiled; + else if (count < 7) + title = AffinityTitles.Cheater; + else if (count < 9) + title = AffinityTitles.Tainted; + else if (count < 11) + title = AffinityTitles.Corrupted; + else if (count < 13) + title = AffinityTitles.Lewd; + else if (count < 15) + title = AffinityTitles.Sloot; + else if (count < 17) + title = AffinityTitles.Depraved; + else if (count < 20) + title = AffinityTitles.Harlot; + + return new WaifuProfileTitle(count, title.ToString().Replace('_', ' ')); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index a52ea433..12071254 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -145,6 +145,61 @@ namespace NadekoBot.Modules.Gambling await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false); } + //[NadekoCommand, Usage, Description, Aliases] + //[OwnerOnly] + //public Task BrTest(int tests = 1000) + //{ + // var t = Task.Run(async () => + // { + // if (tests <= 0) + // return; + // //multi vs how many times it occured + // var dict = new Dictionary(); + // var generator = new NadekoRandom(); + // for (int i = 0; i < tests; i++) + // { + // var rng = generator.Next(0, 101); + // var mult = 0; + // if (rng < 67) + // { + // mult = 0; + // } + // else if (rng < 91) + // { + // mult = 2; + // } + // else if (rng < 100) + // { + // mult = 4; + // } + // else + // mult = 10; + + // if (dict.ContainsKey(mult)) + // dict[mult] += 1; + // else + // dict.Add(mult, 1); + // } + + // var sb = new StringBuilder(); + // const int bet = 1; + // int payout = 0; + // foreach (var key in dict.Keys.OrderByDescending(x => x)) + // { + // sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); + // payout += key * dict[key]; + // } + // try + // { + // await Context.Channel.SendConfirmAsync("BetRoll Test Results", sb.ToString(), + // footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + // } + // catch { } + + // }); + // return Task.CompletedTask; + //} + [NadekoCommand, Usage, Description, Aliases] public async Task BetRoll(long amount) { diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 3782fe78..272ced2a 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -93,10 +93,10 @@ namespace NadekoBot.Modules.Games { firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; } - + var file = GetRandomCurrencyImagePath(); var sent = await channel.SendFileAsync( - File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate), - "RandomFlower.jpg", + File.Open(file, FileMode.OpenOrCreate), + new FileInfo(file).Name, $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") .ConfigureAwait(false); @@ -167,7 +167,7 @@ namespace NadekoBot.Modules.Games } else { - msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), "plant.jpg", msgToSend).ConfigureAwait(false); + msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), new FileInfo(file).Name, msgToSend).ConfigureAwait(false); } plantedFlowers.AddOrUpdate(Context.Channel.Id, new List() { msg }, (id, old) => { old.Add(msg); return old; }); } diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 701bc937..6d101975 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -43,7 +43,12 @@ namespace NadekoBot.Modules.Music.Classes /// public uint MaxPlaytimeSeconds { get; set; } = 0; - public TimeSpan TotalPlaytime => new TimeSpan(playlist.Sum(s => s.TotalTime.Ticks)); + + // this should be written better + public TimeSpan TotalPlaytime => + playlist.Any(s => s.TotalTime == TimeSpan.MaxValue) ? + TimeSpan.MaxValue : + new TimeSpan(playlist.Sum(s => s.TotalTime.Ticks)); /// /// Users who recently got their music wish diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 0cb28121..868a0885 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -204,6 +204,7 @@ namespace NadekoBot.Modules.Music const int itemsPerPage = 10; var total = musicPlayer.TotalPlaytime; + var totalStr = total == TimeSpan.MaxValue ? "∞" : $"{(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s"; var maxPlaytime = musicPlayer.MaxPlaytimeSeconds; var lastPage = musicPlayer.Playlist.Count / itemsPerPage; Func printAction = (curPage) => @@ -218,7 +219,7 @@ namespace NadekoBot.Modules.Music .Take(itemsPerPage) .Select(v => $"`{++number}.` {v.PrettyFullName}"))) .WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " + - $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s | " + + $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " + (musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit"))) .WithOkColor(); @@ -804,7 +805,7 @@ namespace NadekoBot.Modules.Music if (voiceCh == null || voiceCh.Guild != textCh.Guild) { if (!silent) - await textCh.SendErrorAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice (ITextChannel)Context.Channel, try rejoining.").ConfigureAwait(false); + await textCh.SendErrorAsync($"💢 You need to be in a voice channel on this server.").ConfigureAwait(false); throw new ArgumentNullException(nameof(voiceCh)); } if (string.IsNullOrWhiteSpace(query) || query.Length < 3) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index ae9f8568..266ffa68 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -19,6 +19,7 @@ namespace NadekoBot.Modules.NSFW [NadekoModule("NSFW", "~")] public class NSFW : DiscordModule { +#if !GLOBAL_NADEKO private static ConcurrentDictionary AutoHentaiTimers { get; } = new ConcurrentDictionary(); private static ConcurrentHashSet _hentaiBombBlacklist { get; } = new ConcurrentHashSet(); @@ -66,6 +67,7 @@ namespace NadekoBot.Modules.NSFW InternalHentai(Context.Channel, tag, false); [NadekoCommand, Usage, Description, Aliases] + [RequireUserPermission(ChannelPermission.ManageMessages)] public async Task AutoHentai(int interval = 0, string tags = null) { Timer t; @@ -188,7 +190,7 @@ namespace NadekoBot.Modules.NSFW .WithFooter(efb => efb.WithText("e621"))) .ConfigureAwait(false); } - +#endif [NadekoCommand, Usage, Description, Aliases] public async Task Cp() { @@ -203,7 +205,7 @@ namespace NadekoBot.Modules.NSFW JToken obj; using (var http = new HttpClient()) { - obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{ new NadekoRandom().Next(0, 10229) }").ConfigureAwait(false))[0]; + obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{ new NadekoRandom().Next(0, 10330) }").ConfigureAwait(false))[0]; } await Context.Channel.SendMessageAsync($"http://media.oboobs.ru/{ obj["preview"].ToString() }").ConfigureAwait(false); } @@ -221,7 +223,7 @@ namespace NadekoBot.Modules.NSFW JToken obj; using (var http = new HttpClient()) { - obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{ new NadekoRandom().Next(0, 4222) }").ConfigureAwait(false))[0]; + obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{ new NadekoRandom().Next(0, 4335) }").ConfigureAwait(false))[0]; } await Context.Channel.SendMessageAsync($"http://media.obutts.ru/{ obj["preview"].ToString() }").ConfigureAwait(false); } @@ -230,7 +232,7 @@ namespace NadekoBot.Modules.NSFW await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); } } - +#if !GLOBAL_NADEKO public static Task GetDanbooruImageLink(string tag) => Task.Run(async () => { try @@ -287,5 +289,6 @@ namespace NadekoBot.Modules.NSFW public static Task GetRule34ImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34); +#endif } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 60bebedf..34ef1074 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -618,9 +618,13 @@ namespace NadekoBot.Modules.Searches if (usr == null) usr = Context.User; + var avatarUrl = usr.RealAvatarUrl(); + var shortenedAvatarUrl = await NadekoBot.Google.ShortenUrl(avatarUrl).ConfigureAwait(false); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle($"{usr}'s Avatar") - .WithImageUrl(usr.AvatarUrl)).ConfigureAwait(false); + .AddField(efb => efb.WithName("Username").WithValue(usr.ToString()).WithIsInline(false)) + .AddField(efb => efb.WithName("Avatar Url").WithValue(shortenedAvatarUrl).WithIsInline(false)) + //.AddField(efb => efb.WithName("Avatar Id").WithValue(usr.AvatarId).WithIsInline(false)) + .WithThumbnailUrl(avatarUrl), Context.User.Mention).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 8814c50c..7d57ff8a 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -34,6 +34,9 @@ namespace NadekoBot.Modules.Utility var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(guild.Id >> 22); var sb = new StringBuilder(); var users = await guild.GetUsersAsync().ConfigureAwait(false); + var features = string.Join("\n", guild.Features); + if (string.IsNullOrWhiteSpace(features)) + features = "-"; var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName("Server Info")) .WithTitle(guild.Name) @@ -45,11 +48,12 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName("**Features**").WithValue(features).WithIsInline(true)) .WithImageUrl(guild.IconUrl) .WithColor(NadekoBot.OkColor); if (guild.Emojis.Count() > 0) { - embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(Format.Italics(string.Join(", ", guild.Emojis))).WithIsInline(true)); + embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(string.Join(" ", guild.Emojis.Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -92,8 +96,8 @@ namespace NadekoBot.Modules.Utility embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count})** - {string.Join(", ", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) - .WithThumbnailUrl(user.AvatarUrl) + .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) + .WithThumbnailUrl(user.RealAvatarUrl()) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 71bd6748..619b71fa 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -1,5 +1,6 @@ using Discord; using Discord.Commands; +using Discord.Net; using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; @@ -64,7 +65,24 @@ namespace NadekoBot.Modules.Utility if (oldMsg != null) try { await oldMsg.DeleteAsync(); } catch { } - try { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try + { + oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + _log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id); + return; + } + catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) + { + _log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id); + return; + } + catch (Exception ex) + { + _log.Warn(ex); + } } } catch (OperationCanceledException) { } diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 7796571d..fd60a591 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Utility keyword = keyword.ToUpperInvariant(); Quote quote; - using (var uow = DbHandler.Instance.GetUnitOfWork()) + using (var uow = DbHandler.UnitOfWork()) { quote = await uow.Quotes.GetRandomQuoteByKeywordAsync(Context.Guild.Id, keyword).ConfigureAwait(false); } diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index c8084905..2e4d3daf 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -23,8 +23,8 @@ namespace NadekoBot { private Logger _log; - public static Color OkColor { get; } = new Color(0x71cd40); - public static Color ErrorColor { get; } = new Color(0xee281f); + public static Color OkColor { get; } + public static Color ErrorColor { get; } public static CommandService CommandService { get; private set; } public static CommandHandler CommandHandler { get; private set; } @@ -49,6 +49,8 @@ namespace NadekoBot { AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(); BotConfig = uow.BotConfig.GetOrCreate(); + OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16)); + ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16)); } } @@ -96,7 +98,7 @@ namespace NadekoBot //connect await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false); await Client.ConnectAsync().ConfigureAwait(false); - await Client.DownloadAllUsersAsync().ConfigureAwait(false); + //await Client.DownloadAllUsersAsync().ConfigureAwait(false); Stats.Initialize(); _log.Info("Connected"); diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 717d767e..0f25ceb5 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2489,6 +2489,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to divorce. + /// + public static string divorce_cmd { + get { + return ResourceManager.GetString("divorce_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown.. + /// + public static string divorce_desc { + get { + return ResourceManager.GetString("divorce_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}divorce @CheatingSloot`. + /// + public static string divorce_usage { + get { + return ResourceManager.GetString("divorce_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to donadd. /// @@ -7079,6 +7106,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to slot. + /// + public static string slot_cmd { + get { + return ResourceManager.GetString("slot_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user.. + /// + public static string slot_desc { + get { + return ResourceManager.GetString("slot_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slot 5`. + /// + public static string slot_usage { + get { + return ResourceManager.GetString("slot_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to slotstats. + /// + public static string slotstats_cmd { + get { + return ResourceManager.GetString("slotstats_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows the total stats of the slot command for this bot's session.. + /// + public static string slotstats_desc { + get { + return ResourceManager.GetString("slotstats_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slotstats`. + /// + public static string slotstats_usage { + get { + return ResourceManager.GetString("slotstats_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to slottest. + /// + public static string slottest_cmd { + get { + return ResourceManager.GetString("slottest_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tests to see how much slots payout for X number of plays.. + /// + public static string slottest_desc { + get { + return ResourceManager.GetString("slottest_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slottest 1000`. + /// + public static string slottest_usage { + get { + return ResourceManager.GetString("slottest_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to slowmode. /// @@ -8294,6 +8402,114 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to claimwaifu claim. + /// + public static string waifuclaim_cmd { + get { + return ResourceManager.GetString("waifuclaim_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `{0}affinity` towards you.. + /// + public static string waifuclaim_desc { + get { + return ResourceManager.GetString("waifuclaim_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}claim 50 @Himesama`. + /// + public static string waifuclaim_usage { + get { + return ResourceManager.GetString("waifuclaim_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to affinity. + /// + public static string waifuclaimeraffinity_cmd { + get { + return ResourceManager.GetString("waifuclaimeraffinity_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown.. + /// + public static string waifuclaimeraffinity_desc { + get { + return ResourceManager.GetString("waifuclaimeraffinity_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}affinity @MyHusband` or `{0}affinity`. + /// + public static string waifuclaimeraffinity_usage { + get { + return ResourceManager.GetString("waifuclaimeraffinity_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to waifuinfo waifustats. + /// + public static string waifuinfo_cmd { + get { + return ResourceManager.GetString("waifuinfo_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows waifu stats for a target person. Defaults to you if no user is provided.. + /// + public static string waifuinfo_desc { + get { + return ResourceManager.GetString("waifuinfo_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}waifuinfo @MyCrush` or `{0}waifuinfo`. + /// + public static string waifuinfo_usage { + get { + return ResourceManager.GetString("waifuinfo_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to waifus waifulb. + /// + public static string waifuleaderboard_cmd { + get { + return ResourceManager.GetString("waifuleaderboard_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows top 9 waifus.. + /// + public static string waifuleaderboard_desc { + get { + return ResourceManager.GetString("waifuleaderboard_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}waifus`. + /// + public static string waifuleaderboard_usage { + get { + return ResourceManager.GetString("waifuleaderboard_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to weather we. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1e9ba5d4..2b742f4a 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2952,4 +2952,76 @@ `{0}startevent flowerreaction` + + slotstats + + + Shows the total stats of the slot command for this bot's session. + + + `{0}slotstats` + + + slottest + + + Tests to see how much slots payout for X number of plays. + + + `{0}slottest 1000` + + + slot + + + Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. + + + `{0}slot 5` + + + affinity + + + Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. + + + `{0}affinity @MyHusband` or `{0}affinity` + + + claimwaifu claim + + + Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `{0}affinity` towards you. + + + `{0}claim 50 @Himesama` + + + waifus waifulb + + + Shows top 9 waifus. + + + `{0}waifus` + + + divorce + + + Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. + + + `{0}divorce @CheatingSloot` + + + waifuinfo waifustats + + + Shows waifu stats for a target person. Defaults to you if no user is provided. + + + `{0}waifuinfo @MyCrush` or `{0}waifuinfo` + \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs index 08269207..d5df8dfe 100644 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs +++ b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs @@ -32,7 +32,7 @@ namespace Services.CleverBotApi #if GLOBAL_NADEKO var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot"; #else - var url = "http://www.cleverbot.com/webservicemin?uc=3210"; + var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=chatterbotapi"; #endif switch (type) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 16bf8e89..f2aab51c 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -30,7 +30,11 @@ namespace NadekoBot.Services } public class CommandHandler { +#if GLOBAL_NADEKO public const int GlobalCommandsCooldown = 1500; +#else + public const int GlobalCommandsCooldown = 750; +#endif private readonly DiscordShardedClient _client; private readonly CommandService _commandService; @@ -119,18 +123,18 @@ namespace NadekoBot.Services private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) { _log.Warn("Command Errored after {5}s\n\t" + - "User: {0}\n\t" + - "Server: {1}\n\t" + - "Channel: {2}\n\t" + - "Message: {3}\n\t" + - "Error: {4}", - usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0} - (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} - (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} - usrMsg.Content,// {3} - exec.Result.ErrorReason, // {4} - ticks * oneThousandth // {5} - ); + "User: {0}\n\t" + + "Server: {1}\n\t" + + "Channel: {2}\n\t" + + "Message: {3}\n\t" + + "Error: {4}", + usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0} + (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} + (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} + usrMsg.Content,// {3} + exec.Result.ErrorReason, // {4} + ticks * oneThousandth // {5} + ); } private async Task InviteFiltered(IGuild guild, SocketUserMessage usrMsg) @@ -193,13 +197,10 @@ namespace NadekoBot.Services if (usrMsg == null) //has to be an user message, not system/other messages. return; +#if !GLOBAL_NADEKO // track how many messagges each user is sending UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old); - - // Bot will ignore commands which are ran more often than what specified by - // GlobalCommandsCooldown constant (miliseconds) - if (!UsersOnShortCooldown.Add(usrMsg.Author.Id)) - return; +#endif var channel = msg.Channel as SocketTextChannel; var guild = channel?.Guild; @@ -216,19 +217,19 @@ namespace NadekoBot.Services if (IsBlacklisted(guild, usrMsg)) return; - var cleverBotRan = await TryRunCleverbot(usrMsg, guild).ConfigureAwait(false); + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); if (cleverBotRan) return; // maybe this message is a custom reaction - var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false); + var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); if (crExecuted) //if it was, don't execute the command return; string messageContent = usrMsg.Content; // execute the command and measure the time it took - var exec = await ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best); + var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false); execTime = Environment.TickCount - execTime; if (exec.Result.IsSuccess) @@ -367,9 +368,13 @@ namespace NadekoBot.Services } } + // Bot will ignore commands which are ran more often than what specified by + // GlobalCommandsCooldown constant (miliseconds) + if (!UsersOnShortCooldown.Add(context.Message.Author.Id)) + return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"You are on a global cooldown.")); if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User)) - return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"That command is on cooldown for you.")); + return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"That command is on a cooldown for you.")); return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, dependencyMap)); } diff --git a/src/NadekoBot/Services/CurrencyHandler.cs b/src/NadekoBot/Services/CurrencyHandler.cs index f2d699a0..7e2939e4 100644 --- a/src/NadekoBot/Services/CurrencyHandler.cs +++ b/src/NadekoBot/Services/CurrencyHandler.cs @@ -4,6 +4,7 @@ using Discord; using NadekoBot.Extensions; using NadekoBot.Modules.Gambling; using NadekoBot.Services.Database.Models; +using NadekoBot.Services.Database; namespace NadekoBot.Services { @@ -19,26 +20,36 @@ namespace NadekoBot.Services return success; } - public static async Task RemoveCurrencyAsync(ulong authorId, string reason, long amount) + public static async Task RemoveCurrencyAsync(ulong authorId, string reason, long amount, IUnitOfWork uow = null) { if (amount < 0) throw new ArgumentNullException(nameof(amount)); - using (var uow = DbHandler.UnitOfWork()) + if (uow == null) { - var success = uow.Currency.TryUpdateState(authorId, -amount); - if (!success) - return false; - uow.CurrencyTransactions.Add(new CurrencyTransaction() + using (uow = DbHandler.UnitOfWork()) { - UserId = authorId, - Reason = reason, - Amount = -amount, - }); - await uow.CompleteAsync().ConfigureAwait(false); + var toReturn = InternalRemoveCurrency(authorId, reason, amount, uow); + await uow.CompleteAsync().ConfigureAwait(false); + return toReturn; + } } + return InternalRemoveCurrency(authorId, reason, amount, uow); + } + + private static bool InternalRemoveCurrency(ulong authorId, string reason, long amount, IUnitOfWork uow) + { + var success = uow.Currency.TryUpdateState(authorId, -amount); + if (!success) + return false; + uow.CurrencyTransactions.Add(new CurrencyTransaction() + { + UserId = authorId, + Reason = reason, + Amount = -amount, + }); return true; } @@ -50,22 +61,29 @@ namespace NadekoBot.Services try { await author.SendConfirmAsync($"`You received:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } } - public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount) + public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount, IUnitOfWork uow = null) { if (amount < 0) throw new ArgumentNullException(nameof(amount)); + var transaction = new CurrencyTransaction() + { + UserId = receiverId, + Reason = reason, + Amount = amount, + }; - using (var uow = DbHandler.UnitOfWork()) + if (uow == null) + using (uow = DbHandler.UnitOfWork()) + { + uow.Currency.TryUpdateState(receiverId, amount); + uow.CurrencyTransactions.Add(transaction); + await uow.CompleteAsync(); + } + else { uow.Currency.TryUpdateState(receiverId, amount); - uow.CurrencyTransactions.Add(new CurrencyTransaction() - { - UserId = receiverId, - Reason = reason, - Amount = amount, - }); - await uow.CompleteAsync(); + uow.CurrencyTransactions.Add(transaction); } } } diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index f17e1f6a..c1c9479e 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -21,6 +21,8 @@ namespace NadekoBot.Services.Database ICurrencyTransactionsRepository CurrencyTransactions { get; } IMusicPlaylistRepository MusicPlaylists { get; } IPokeGameRepository PokeGame { get; } + IWaifuRepository Waifus { get; } + IDiscordUserRepository DiscordUsers { get; } int Complete(); Task CompleteAsync(); diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 080770ec..d96d4cc8 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -25,11 +25,11 @@ namespace NadekoBot.Services.Database.Models public string CurrencyPluralName { get; set; } = "Nadeko Flowers"; public int TriviaCurrencyReward { get; set; } = 0; - public int MinimumBetAmount { get; set; } = 3; - public float BetflipMultiplier { get; set; } = 1.8f; + public int MinimumBetAmount { get; set; } = 2; + public float BetflipMultiplier { get; set; } = 1.95f; public int CurrencyDropAmount { get; set; } = 1; public float Betroll67Multiplier { get; set; } = 2; - public float Betroll91Multiplier { get; set; } = 3; + public float Betroll91Multiplier { get; set; } = 4; public float Betroll100Multiplier { get; set; } = 10; //public HashSet CommandCosts { get; set; } = new HashSet(); @@ -57,6 +57,9 @@ For a specific command help, use `{1}h CommandName` (for example {1}h !!q) Nadeko Support Server: https://discord.gg/0ehQwTK2RBjAxzEY"; public int MigrationVersion { get; set; } + + public string OkColor { get; set; } = "71cd40"; + public string ErrorColor { get; set; } = "ee281f"; } public class PlayingStatus :DbEntity diff --git a/src/NadekoBot/Services/Database/Models/DiscordUser.cs b/src/NadekoBot/Services/Database/Models/DiscordUser.cs new file mode 100644 index 00000000..608daf81 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/DiscordUser.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class DiscordUser : DbEntity + { + public ulong UserId { get; set; } + public string Username { get; set; } + public string Discriminator { get; set; } + public string AvatarId { get; set; } + + public override string ToString() => + Username + "#" + Discriminator; + } +} diff --git a/src/NadekoBot/Services/Database/Models/Waifu.cs b/src/NadekoBot/Services/Database/Models/Waifu.cs new file mode 100644 index 00000000..947bf516 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Waifu.cs @@ -0,0 +1,49 @@ +using NadekoBot.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class WaifuInfo : DbEntity + { + public int WaifuId { get; set; } + public DiscordUser Waifu { get; set; } + + public int? ClaimerId { get; set; } + public DiscordUser Claimer { get; set; } + + public int? AffinityId { get; set; } + public DiscordUser Affinity { get; set; } + + public int Price { get; set; } + + public override string ToString() + { + var claimer = "no one"; + var status = ""; + + var waifuUsername = Waifu.Username.TrimTo(20); + var claimerUsername = Claimer?.Username.TrimTo(20); + + if (Claimer != null) + { + claimer = $"{ claimerUsername }#{Claimer.Discriminator}"; + } + if (AffinityId == null) + { + status = $"... but {waifuUsername}'s heart is empty"; + } + else if (AffinityId == ClaimerId) + { + status = $"... and {waifuUsername} likes {claimerUsername} too <3"; + } + else { + status = $"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}"; + } + return $"**{waifuUsername}#{Waifu.Discriminator}** - claimed by **{claimer}**\n\t{status}"; + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/WaifuUpdate.cs b/src/NadekoBot/Services/Database/Models/WaifuUpdate.cs new file mode 100644 index 00000000..1c48826e --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/WaifuUpdate.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class WaifuUpdate : DbEntity + { + public int UserId { get; set; } + public DiscordUser User { get; set; } + public WaifuUpdateType UpdateType { get; set; } + + public int? OldId { get; set; } + public DiscordUser Old { get; set; } + + public int? NewId { get; set; } + public DiscordUser New { get; set; } + } + + public enum WaifuUpdateType + { + AffinityChanged, + Claimed + } +} diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index b49439f6..102c6703 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -3,9 +3,26 @@ using System.Collections.Generic; using System.Linq; using NadekoBot.Services.Database.Models; using NadekoBot.Extensions; +using Microsoft.EntityFrameworkCore.Infrastructure; namespace NadekoBot.Services.Database { + + public class NadekoContextFactory : IDbContextFactory + { + /// + /// :\ Used for migrations + /// + /// + /// + public NadekoContext Create(DbContextFactoryOptions options) + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); + return new NadekoContext(optionsBuilder.Options); + } + } + public class NadekoContext : DbContext { public DbSet Quotes { get; set; } @@ -22,6 +39,7 @@ namespace NadekoBot.Services.Database public DbSet CustomReactions { get; set; } public DbSet CurrencyTransactions { get; set; } public DbSet PokeGame { get; set; } + public DbSet WaifuUpdates { get; set; } //logging public DbSet LogSettings { get; set; } @@ -33,23 +51,15 @@ namespace NadekoBot.Services.Database public DbSet RaceAnimals { get; set; } public DbSet ModulePrefixes { get; set; } - public NadekoContext() + public NadekoContext() : base() { - this.Database.Migrate(); + } public NadekoContext(DbContextOptions options) : base(options) { - this.Database.Migrate(); - EnsureSeedData(); } - ////Uncomment this to db initialisation with dotnet ef migration add [module] - //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - //{ - // optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); - //} - public void EnsureSeedData() { if (!BotConfig.Any()) @@ -244,6 +254,24 @@ namespace NadekoBot.Services.Database // .HasIndex(cp => cp.CommandName) // .IsUnique(); #endregion + + #region Waifus + + var wi = modelBuilder.Entity(); + wi.HasOne(x => x.Waifu) + .WithOne(); + // //.HasForeignKey(w => w.WaifuId) + // //.IsRequired(true); + + //wi.HasOne(x => x.Claimer) + // .WithOne(); + // //.HasForeignKey(w => w.ClaimerId) + // //.IsRequired(false); + + var du = modelBuilder.Entity(); + du.HasAlternateKey(w => w.UserId); + + #endregion } } } diff --git a/src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs b/src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs new file mode 100644 index 00000000..c80608dd --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs @@ -0,0 +1,15 @@ +using Discord; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IDiscordUserRepository : IRepository + { + DiscordUser GetOrCreate(IUser original); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs b/src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs new file mode 100644 index 00000000..2f2dc0f6 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs @@ -0,0 +1,13 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IWaifuRepository : IRepository + { + IList GetTop(int count); + WaifuInfo ByWaifuUserId(ulong userId); + IList ByClaimerUserId(ulong userId); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs new file mode 100644 index 00000000..9425f049 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs @@ -0,0 +1,36 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Discord; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class DiscordUserRepository : Repository, IDiscordUserRepository + { + public DiscordUserRepository(DbContext context) : base(context) + { + } + + public DiscordUser GetOrCreate(IUser original) + { + DiscordUser toReturn; + + toReturn = _set.FirstOrDefault(u => u.UserId == original.Id); + + if (toReturn == null) + _set.Add(toReturn = new DiscordUser() + { + AvatarId = original.AvatarId, + Discriminator = original.Discriminator, + UserId = original.Id, + Username = original.Username, + }); + + return toReturn; + } + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs new file mode 100644 index 00000000..8a973202 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs @@ -0,0 +1,49 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class WaifuRepository : Repository, IWaifuRepository + { + public WaifuRepository(DbContext context) : base(context) + { + } + + public WaifuInfo ByWaifuUserId(ulong userId) + { + return _set.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .FirstOrDefault(wi => wi.Waifu.UserId == userId); + } + + public IList ByClaimerUserId(ulong userId) + { + return _set.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .Where(wi => wi.Claimer != null && wi.Claimer.UserId == userId) + .ToList(); + } + + public IList GetTop(int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + if (count == 0) + return new List(); + + return _set.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .OrderByDescending(wi => wi.Price) + .Take(count) + .ToList(); + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 88231d6b..032c0bb7 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -48,6 +48,12 @@ namespace NadekoBot.Services.Database private IPokeGameRepository _pokegame; public IPokeGameRepository PokeGame => _pokegame ?? (_pokegame = new PokeGameRepository(_context)); + private IWaifuRepository _waifus; + public IWaifuRepository Waifus => _waifus ?? (_waifus = new WaifuRepository(_context)); + + private IDiscordUserRepository _discordUsers; + public IDiscordUserRepository DiscordUsers => _discordUsers ?? (_discordUsers = new DiscordUserRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; diff --git a/src/NadekoBot/Services/DbHandler.cs b/src/NadekoBot/Services/DbHandler.cs index 03d12a94..9a4ab212 100644 --- a/src/NadekoBot/Services/DbHandler.cs +++ b/src/NadekoBot/Services/DbHandler.cs @@ -1,4 +1,6 @@ -using Microsoft.EntityFrameworkCore; +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; using NadekoBot.Services.Database; namespace NadekoBot.Services @@ -13,7 +15,8 @@ namespace NadekoBot.Services static DbHandler() { } - private DbHandler() { + private DbHandler() + { connectionString = NadekoBot.Credentials.Db.ConnectionString; var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseSqlite(NadekoBot.Credentials.Db.ConnectionString); @@ -32,13 +35,19 @@ namespace NadekoBot.Services //} } - public NadekoContext GetDbContext() => - new NadekoContext(options); + public NadekoContext GetDbContext() + { + var context = new NadekoContext(options); + context.Database.Migrate(); + context.EnsureSeedData(); - public IUnitOfWork GetUnitOfWork() => + return context; + } + + private IUnitOfWork GetUnitOfWork() => new UnitOfWork(GetDbContext()); public static IUnitOfWork UnitOfWork() => DbHandler.Instance.GetUnitOfWork(); } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 86955b83..cdd6fd8f 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl private DiscordShardedClient client; private DateTime started; - public const string BotVersion = "1.1.1"; + public const string BotVersion = "1.1.4"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index d2dd36fc..fc50058f 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -183,18 +183,18 @@ namespace NadekoBot.Extensions await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(message, isTTS).ConfigureAwait(false); public static async Task SendConfirmAsync(this IUser user, string text) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text)); + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text)); public static async Task SendConfirmAsync(this IUser user, string title, string text, string url = null) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text) + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text) .WithTitle(title).WithUrl(url)); public static async Task SendErrorAsync(this IUser user, string title, string error, string url = null) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error) + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error) .WithTitle(title).WithUrl(url)); public static async Task SendErrorAsync(this IUser user, string error) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error)); + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error)); public static async Task SendFileAsync(this IUser user, string filePath, string caption = null, string text = null, bool isTTS = false) => await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(File.Open(filePath, FileMode.Open), caption ?? "x", text, isTTS).ConfigureAwait(false); @@ -212,18 +212,18 @@ namespace NadekoBot.Extensions => ch.SendMessageAsync(msg, embed: embed); public static Task SendErrorAsync(this IMessageChannel ch, string title, string error, string url = null, string footer = null) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.ErrorColor).WithDescription(error) + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error) .WithTitle(title).WithUrl(url).WithFooter(efb => efb.WithText(footer))); public static Task SendErrorAsync(this IMessageChannel ch, string error) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error)); + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error)); public static Task SendConfirmAsync(this IMessageChannel ch, string title, string text, string url = null, string footer = null) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text) + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text) .WithTitle(title).WithUrl(url).WithFooter(efb => efb.WithText(footer))); public static Task SendConfirmAsync(this IMessageChannel ch, string text) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text)); + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text)); public static Task SendTableAsync(this IMessageChannel ch, string seed, IEnumerable items, Func howToPrint, int columns = 3) { @@ -425,5 +425,12 @@ namespace NadekoBot.Extensions public static bool IsDiscordInvite(this string str) => filterRegex.IsMatch(str); + + public static string RealAvatarUrl(this IUser usr) + { + return usr.AvatarId.StartsWith("a_") + ? $"{DiscordConfig.CDNUrl}avatars/{usr.Id}/{usr.AvatarId}.gif" + : usr.AvatarUrl; + } } } \ No newline at end of file diff --git a/src/NadekoBot/data/slots/0.png b/src/NadekoBot/data/slots/0.png new file mode 100644 index 00000000..e260e400 Binary files /dev/null and b/src/NadekoBot/data/slots/0.png differ diff --git a/src/NadekoBot/data/slots/1.png b/src/NadekoBot/data/slots/1.png new file mode 100644 index 00000000..4766b854 Binary files /dev/null and b/src/NadekoBot/data/slots/1.png differ diff --git a/src/NadekoBot/data/slots/2.png b/src/NadekoBot/data/slots/2.png new file mode 100644 index 00000000..57c5525a Binary files /dev/null and b/src/NadekoBot/data/slots/2.png differ diff --git a/src/NadekoBot/data/slots/3.png b/src/NadekoBot/data/slots/3.png new file mode 100644 index 00000000..04d6e982 Binary files /dev/null and b/src/NadekoBot/data/slots/3.png differ diff --git a/src/NadekoBot/data/slots/4.png b/src/NadekoBot/data/slots/4.png new file mode 100644 index 00000000..d4941650 Binary files /dev/null and b/src/NadekoBot/data/slots/4.png differ diff --git a/src/NadekoBot/data/slots/5.png b/src/NadekoBot/data/slots/5.png new file mode 100644 index 00000000..bc78e972 Binary files /dev/null and b/src/NadekoBot/data/slots/5.png differ diff --git a/src/NadekoBot/data/slots/6.png b/src/NadekoBot/data/slots/6.png new file mode 100644 index 00000000..b596051d Binary files /dev/null and b/src/NadekoBot/data/slots/6.png differ diff --git a/src/NadekoBot/data/slots/7.png b/src/NadekoBot/data/slots/7.png new file mode 100644 index 00000000..0ffc89b9 Binary files /dev/null and b/src/NadekoBot/data/slots/7.png differ diff --git a/src/NadekoBot/data/slots/8.png b/src/NadekoBot/data/slots/8.png new file mode 100644 index 00000000..48ceed02 Binary files /dev/null and b/src/NadekoBot/data/slots/8.png differ diff --git a/src/NadekoBot/data/slots/9.png b/src/NadekoBot/data/slots/9.png new file mode 100644 index 00000000..b71dceec Binary files /dev/null and b/src/NadekoBot/data/slots/9.png differ diff --git a/src/NadekoBot/data/slots/background.png b/src/NadekoBot/data/slots/background.png new file mode 100644 index 00000000..6ed6026a Binary files /dev/null and b/src/NadekoBot/data/slots/background.png differ diff --git a/src/NadekoBot/data/slots/emojis/0.png b/src/NadekoBot/data/slots/emojis/0.png new file mode 100644 index 00000000..1f99099b Binary files /dev/null and b/src/NadekoBot/data/slots/emojis/0.png differ diff --git a/src/NadekoBot/data/slots/emojis/1.png b/src/NadekoBot/data/slots/emojis/1.png new file mode 100644 index 00000000..7cb68815 Binary files /dev/null and b/src/NadekoBot/data/slots/emojis/1.png differ diff --git a/src/NadekoBot/data/slots/emojis/2.png b/src/NadekoBot/data/slots/emojis/2.png new file mode 100644 index 00000000..c567b887 Binary files /dev/null and b/src/NadekoBot/data/slots/emojis/2.png differ diff --git a/src/NadekoBot/data/slots/emojis/3.png b/src/NadekoBot/data/slots/emojis/3.png new file mode 100644 index 00000000..d6803b20 Binary files /dev/null and b/src/NadekoBot/data/slots/emojis/3.png differ diff --git a/src/NadekoBot/data/slots/emojis/4.png b/src/NadekoBot/data/slots/emojis/4.png new file mode 100644 index 00000000..36dd054c Binary files /dev/null and b/src/NadekoBot/data/slots/emojis/4.png differ diff --git a/src/NadekoBot/data/slots/emojis/5.png b/src/NadekoBot/data/slots/emojis/5.png new file mode 100644 index 00000000..84b4db13 Binary files /dev/null and b/src/NadekoBot/data/slots/emojis/5.png differ