commit
65bcda21c1
@ -1 +1 @@
|
||||
Subproject commit 58766448d79ac9adec228f341f258aa262a3f278
|
||||
Subproject commit 80384323790471d254c7db5c237a49dc62624378
|
@ -2,5 +2,6 @@
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="ImageSharp" value="https://www.myget.org/F/imagesharp/api/v3/index.json" />
|
||||
<add key="Kwoth" value="https://www.myget.org/F/kwoth/api/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
|
@ -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: <https://streamable.com/al54>) | `!!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`
|
||||
|
@ -1,5 +1,5 @@
|
||||
@ECHO off
|
||||
TITLE Downloading NadekoBot, please wait
|
||||
TITLE Downloading Latest Build of NadekoBot...
|
||||
::Setting convenient to read variables which don't delete the windows temp folder
|
||||
SET root=%~dp0
|
||||
CD /D %root%
|
||||
@ -24,30 +24,43 @@ ECHO Downloading Nadeko...
|
||||
ECHO.
|
||||
git clone -b dev --recursive --depth 1 --progress https://github.com/Kwoth/NadekoBot.git >nul
|
||||
IF %ERRORLEVEL% EQU 128 (GOTO :giterror)
|
||||
TITLE Installing NadekoBot, please wait
|
||||
TITLE Installing NadekoBot, please wait...
|
||||
ECHO.
|
||||
ECHO Installing...
|
||||
ECHO Installing Discord.Net(1/4)...
|
||||
::Building Nadeko
|
||||
CD /D %build1%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO Installing Discord.Net(2/4)...
|
||||
CD /D %build2%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO Installing Discord.Net(3/4)...
|
||||
CD /D %build3%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO Installing Discord.Net(4/4)...
|
||||
CD /D %build4%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO.
|
||||
ECHO Discord.Net installation completed successfully...
|
||||
ECHO.
|
||||
ECHO Installing NadekoBot...
|
||||
CD /D %build5%
|
||||
dotnet restore >nul 2>&1
|
||||
dotnet build --configuration Release >nul 2>&1
|
||||
ECHO.
|
||||
ECHO NadekoBot installation completed successfully...
|
||||
::Attempts to backup old files if they currently exist in the same folder as the batch file
|
||||
IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
||||
:freshinstall
|
||||
::Moves the NadekoBot folder to keep things tidy
|
||||
ECHO.
|
||||
ECHO Moving files, Please wait...
|
||||
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||
GOTO :end
|
||||
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
|
||||
:backupinstall
|
||||
TITLE Backing up old files
|
||||
TITLE Backing up old files...
|
||||
ECHO.
|
||||
ECHO Moving and Backing up old files...
|
||||
::Recursively copies all files and folders from NadekoBot to NadekoBot_Old
|
||||
ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1
|
||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||
@ -70,7 +83,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
||||
RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1
|
||||
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||
GOTO :end
|
||||
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
|
||||
:dotnet
|
||||
::Terminates the batch script if it can't run dotnet --version
|
||||
TITLE Error!
|
||||
@ -102,6 +115,25 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
||||
PAUSE >nul 2>&1
|
||||
CD /D "%root%"
|
||||
GOTO :EOF
|
||||
:64BIT
|
||||
ECHO.
|
||||
ECHO Your System Architecture is 64bit...
|
||||
GOTO end
|
||||
:32BIT
|
||||
ECHO.
|
||||
ECHO Your System Architecture is 32bit...
|
||||
timeout /t 5
|
||||
ECHO.
|
||||
ECHO Downloading libsodium.dll and opus.dll...
|
||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll"
|
||||
bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%"
|
||||
ECHO libsodium.dll downloaded.
|
||||
ECHO.
|
||||
timeout /t 5
|
||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll"
|
||||
bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%"
|
||||
ECHO opus.dll downloaded.
|
||||
GOTO end
|
||||
:end
|
||||
::Normal execution of end of script
|
||||
TITLE Installation complete!
|
||||
|
@ -1,5 +1,5 @@
|
||||
@ECHO off
|
||||
TITLE Downloading NadekoBot, please wait
|
||||
TITLE Downloading Stable Build of NadekoBot...
|
||||
::Setting convenient to read variables which don't delete the windows temp folder
|
||||
SET root=%~dp0
|
||||
CD /D %root%
|
||||
@ -24,30 +24,43 @@ ECHO Downloading Nadeko...
|
||||
ECHO.
|
||||
git clone -b master --recursive --depth 1 --progress https://github.com/Kwoth/NadekoBot.git >nul
|
||||
IF %ERRORLEVEL% EQU 128 (GOTO :giterror)
|
||||
TITLE Installing NadekoBot, please wait
|
||||
TITLE Installing NadekoBot, please wait...
|
||||
ECHO.
|
||||
ECHO Installing...
|
||||
ECHO Installing Discord.Net(1/4)...
|
||||
::Building Nadeko
|
||||
CD /D %build1%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO Installing Discord.Net(2/4)...
|
||||
CD /D %build2%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO Installing Discord.Net(3/4)...
|
||||
CD /D %build3%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO Installing Discord.Net(4/4)...
|
||||
CD /D %build4%
|
||||
dotnet restore >nul 2>&1
|
||||
ECHO.
|
||||
ECHO Discord.Net installation completed successfully...
|
||||
ECHO.
|
||||
ECHO Installing NadekoBot...
|
||||
CD /D %build5%
|
||||
dotnet restore >nul 2>&1
|
||||
dotnet build --configuration Release >nul 2>&1
|
||||
ECHO.
|
||||
ECHO NadekoBot installation completed successfully...
|
||||
::Attempts to backup old files if they currently exist in the same folder as the batch file
|
||||
IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
||||
:freshinstall
|
||||
::Moves the NadekoBot folder to keep things tidy
|
||||
ECHO.
|
||||
ECHO Moving files, Please wait...
|
||||
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||
GOTO :end
|
||||
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
|
||||
:backupinstall
|
||||
TITLE Backing up old files
|
||||
TITLE Backing up old files...
|
||||
ECHO.
|
||||
ECHO Moving and Backing up old files...
|
||||
::Recursively copies all files and folders from NadekoBot to NadekoBot_Old
|
||||
ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1
|
||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||
@ -70,7 +83,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
||||
RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1
|
||||
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||
GOTO :end
|
||||
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
|
||||
:dotnet
|
||||
::Terminates the batch script if it can't run dotnet --version
|
||||
TITLE Error!
|
||||
@ -102,6 +115,25 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
||||
PAUSE >nul 2>&1
|
||||
CD /D "%root%"
|
||||
GOTO :EOF
|
||||
:64BIT
|
||||
ECHO.
|
||||
ECHO Your System Architecture is 64bit...
|
||||
GOTO end
|
||||
:32BIT
|
||||
ECHO.
|
||||
ECHO Your System Architecture is 32bit...
|
||||
timeout /t 5
|
||||
ECHO.
|
||||
ECHO Downloading libsodium.dll and opus.dll...
|
||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll"
|
||||
bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%"
|
||||
ECHO libsodium.dll downloaded.
|
||||
ECHO.
|
||||
timeout /t 5
|
||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll"
|
||||
bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%"
|
||||
ECHO opus.dll downloaded.
|
||||
GOTO end
|
||||
:end
|
||||
::Normal execution of end of script
|
||||
TITLE Installation complete!
|
||||
|
@ -30,7 +30,7 @@ namespace NadekoBot.Migrations
|
||||
name: "Betroll91Multiplier",
|
||||
table: "BotConfig",
|
||||
nullable: false,
|
||||
defaultValue: 3f);
|
||||
defaultValue: 4f);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "CurrencyDropAmount",
|
||||
|
1089
src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs
generated
Normal file
1089
src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
140
src/NadekoBot/Migrations/20170122044958_waifus.cs
Normal file
140
src/NadekoBot/Migrations/20170122044958_waifus.cs
Normal file
@ -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<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
AvatarId = table.Column<string>(nullable: true),
|
||||
Discriminator = table.Column<string>(nullable: true),
|
||||
UserId = table.Column<ulong>(nullable: false),
|
||||
Username = table.Column<string>(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<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
AffinityId = table.Column<int>(nullable: true),
|
||||
ClaimerId = table.Column<int>(nullable: true),
|
||||
Price = table.Column<int>(nullable: false),
|
||||
WaifuId = table.Column<int>(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<int>(nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
NewId = table.Column<int>(nullable: true),
|
||||
OldId = table.Column<int>(nullable: true),
|
||||
UpdateType = table.Column<int>(nullable: false),
|
||||
UserId = table.Column<int>(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");
|
||||
}
|
||||
}
|
||||
}
|
@ -299,6 +299,26 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("CustomReactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AvatarId");
|
||||
|
||||
b.Property<string>("Discriminator");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<string>("Username");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("UserId");
|
||||
|
||||
b.ToTable("DiscordUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -817,6 +837,55 @@ namespace NadekoBot.Migrations
|
||||
b.ToTable("PokeGame");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("AffinityId");
|
||||
|
||||
b.Property<int?>("ClaimerId");
|
||||
|
||||
b.Property<int>("Price");
|
||||
|
||||
b.Property<int>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int?>("NewId");
|
||||
|
||||
b.Property<int?>("OldId");
|
||||
|
||||
b.Property<int>("UpdateType");
|
||||
|
||||
b.Property<int>("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")
|
||||
@ -982,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Administration
|
||||
var channel = msg.Channel as SocketTextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id))
|
||||
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune")
|
||||
await msg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -25,7 +25,6 @@ namespace NadekoBot.Modules.Administration
|
||||
static AutoAssignRoleCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
|
||||
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
|
||||
@ -46,9 +45,6 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
};
|
||||
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
@ -9,6 +10,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
@ -21,8 +23,8 @@ namespace NadekoBot.Modules.Administration
|
||||
private static Logger _log { get; }
|
||||
public static List<PlayingStatus> RotatingStatusMessages { get; }
|
||||
public static bool RotatingStatuses { get; private set; } = false;
|
||||
private static Timer _t { get; }
|
||||
|
||||
//todo wtf is with this while(true) in constructor
|
||||
static PlayingRotateCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
@ -30,39 +32,43 @@ namespace NadekoBot.Modules.Administration
|
||||
RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages;
|
||||
RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses;
|
||||
|
||||
var t = Task.Run(async () =>
|
||||
|
||||
|
||||
_t = new Timer(async (_) =>
|
||||
{
|
||||
var index = 0;
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!RotatingStatuses)
|
||||
continue;
|
||||
return;
|
||||
else
|
||||
{
|
||||
if (index >= RotatingStatusMessages.Count)
|
||||
index = 0;
|
||||
|
||||
if (!RotatingStatusMessages.Any())
|
||||
continue;
|
||||
return;
|
||||
var status = RotatingStatusMessages[index++].Status;
|
||||
if (string.IsNullOrWhiteSpace(status))
|
||||
continue;
|
||||
return;
|
||||
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value()));
|
||||
await NadekoBot.Client.SetGameAsync(status).ConfigureAwait(false);
|
||||
var shards = NadekoBot.Client.Shards;
|
||||
for (int i = 0; i < shards.Count; i++)
|
||||
{
|
||||
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i))));
|
||||
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Rotating playing status errored.\n" + ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(1));
|
||||
}
|
||||
} while (true);
|
||||
});
|
||||
}, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
|
||||
@ -81,7 +87,15 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
},
|
||||
{"%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}
|
||||
{ "%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
|
||||
{ "%time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
|
||||
{ "%shardcount%", () => NadekoBot.Client.Shards.Count.ToString() },
|
||||
};
|
||||
|
||||
public static Dictionary<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } =
|
||||
new Dictionary<string, Func<DiscordSocketClient, string>> {
|
||||
{ "%shardid%", (client) => client.ShardId.ToString()},
|
||||
{ "%shardguilds%", (client) => client.Guilds.Count.ToString()},
|
||||
};
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -132,7 +132,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (ids[1].ToUpperInvariant().StartsWith("C:"))
|
||||
{
|
||||
var cid = ulong.Parse(ids[1].Substring(2));
|
||||
var ch = (await server.GetTextChannelsAsync()).Where(c => c.Id == cid).FirstOrDefault();
|
||||
var ch = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault();
|
||||
if (ch == null)
|
||||
{
|
||||
return;
|
||||
@ -159,9 +159,7 @@ namespace NadekoBot.Modules.Administration
|
||||
[OwnerOnly]
|
||||
public async Task Announce([Remainder] string message)
|
||||
{
|
||||
var channels = await Task.WhenAll(NadekoBot.Client.GetGuilds().Select(g =>
|
||||
g.GetDefaultChannelAsync()
|
||||
)).ConfigureAwait(false);
|
||||
var channels = NadekoBot.Client.GetGuilds().Select(g => g.DefaultChannel).ToArray();
|
||||
if (channels == null)
|
||||
return;
|
||||
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync($"🆕 Message from {Context.User} `[Bot Owner]`:", message)))
|
||||
|
@ -4,9 +4,11 @@ using Discord.WebSocket;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -17,24 +19,76 @@ namespace NadekoBot.Modules.Administration
|
||||
[Group]
|
||||
public class ServerGreetCommands : ModuleBase
|
||||
{
|
||||
//make this to a field in the guildconfig table
|
||||
class GreetSettings
|
||||
{
|
||||
public int AutoDeleteGreetMessagesTimer { get; set; }
|
||||
public int AutoDeleteByeMessagesTimer { get; set; }
|
||||
|
||||
public ulong GreetMessageChannelId { get; set; }
|
||||
public ulong ByeMessageChannelId { get; set; }
|
||||
|
||||
public bool SendDmGreetMessage { get; set; }
|
||||
public string DmGreetMessageText { get; set; }
|
||||
|
||||
public bool SendChannelGreetMessage { get; set; }
|
||||
public string ChannelGreetMessageText { get; set; }
|
||||
|
||||
public bool SendChannelByeMessage { get; set; }
|
||||
public string ChannelByeMessageText { get; set; }
|
||||
|
||||
public static GreetSettings Create(GuildConfig g) => new GreetSettings()
|
||||
{
|
||||
AutoDeleteByeMessagesTimer = g.AutoDeleteByeMessagesTimer,
|
||||
AutoDeleteGreetMessagesTimer = g.AutoDeleteGreetMessagesTimer,
|
||||
GreetMessageChannelId = g.GreetMessageChannelId,
|
||||
ByeMessageChannelId = g.ByeMessageChannelId,
|
||||
SendDmGreetMessage = g.SendDmGreetMessage,
|
||||
DmGreetMessageText = g.DmGreetMessageText,
|
||||
SendChannelGreetMessage = g.SendChannelGreetMessage,
|
||||
ChannelGreetMessageText = g.ChannelGreetMessageText,
|
||||
SendChannelByeMessage = g.SendChannelByeMessage,
|
||||
ChannelByeMessageText = g.ChannelByeMessageText,
|
||||
};
|
||||
}
|
||||
|
||||
private static Logger _log { get; }
|
||||
|
||||
private static ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache { get; } = new ConcurrentDictionary<ulong, GreetSettings>();
|
||||
|
||||
static ServerGreetCommands()
|
||||
{
|
||||
NadekoBot.Client.UserJoined += UserJoined;
|
||||
NadekoBot.Client.UserLeft += UserLeft;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, (g) => GreetSettings.Create(g)));
|
||||
}
|
||||
|
||||
private static GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
||||
{
|
||||
GreetSettings settings;
|
||||
GuildConfigsCache.TryGetValue(guildId, out settings);
|
||||
|
||||
if (settings != null)
|
||||
return settings;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
settings = GreetSettings.Create(gc);
|
||||
}
|
||||
|
||||
GuildConfigsCache.TryAdd(guildId, settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
//todo optimize ASAP
|
||||
private static async Task UserLeft(IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
GuildConfig conf;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
|
||||
}
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
|
||||
if (!conf.SendChannelByeMessage) return;
|
||||
var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
|
||||
@ -62,11 +116,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
GuildConfig conf;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
|
||||
}
|
||||
var conf = GetOrAddSettingsForGuild(user.GuildId);
|
||||
|
||||
if (conf.SendChannelGreetMessage)
|
||||
{
|
||||
@ -133,6 +183,9 @@ namespace NadekoBot.Modules.Administration
|
||||
var conf = uow.GuildConfigs.For(id, set => set);
|
||||
conf.AutoDeleteGreetMessagesTimer = timer;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@ -159,6 +212,9 @@ namespace NadekoBot.Modules.Administration
|
||||
enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage;
|
||||
conf.GreetMessageChannelId = channelId;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
return enabled;
|
||||
@ -201,6 +257,9 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.ChannelGreetMessageText = message;
|
||||
greetMsgEnabled = conf.SendChannelGreetMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
return greetMsgEnabled;
|
||||
@ -227,6 +286,9 @@ namespace NadekoBot.Modules.Administration
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
return enabled;
|
||||
@ -269,6 +331,9 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.DmGreetMessageText = message;
|
||||
greetMsgEnabled = conf.SendDmGreetMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
return greetMsgEnabled;
|
||||
@ -296,6 +361,9 @@ namespace NadekoBot.Modules.Administration
|
||||
enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage;
|
||||
conf.ByeMessageChannelId = channelId;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
return enabled;
|
||||
@ -338,6 +406,9 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.ChannelByeMessageText = message;
|
||||
byeMsgEnabled = conf.SendChannelByeMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
return byeMsgEnabled;
|
||||
@ -356,16 +427,19 @@ namespace NadekoBot.Modules.Administration
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Automatic deletion of bye messages has been **disabled**.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task SetByeDel(ulong id, int timer)
|
||||
private static async Task SetByeDel(ulong guildId, int timer)
|
||||
{
|
||||
if (timer < 0 || timer > 600)
|
||||
return;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var conf = uow.GuildConfigs.For(id, set => set);
|
||||
var conf = uow.GuildConfigs.For(guildId, set => set);
|
||||
conf.AutoDeleteByeMessagesTimer = timer;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
await (await guild.GetOwnerAsync()).SendErrorAsync(
|
||||
await guild.Owner.SendErrorAsync(
|
||||
"⚠️ I don't have **manage server** and/or **manage channels** permission," +
|
||||
$" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false);
|
||||
}
|
||||
@ -75,16 +75,16 @@ namespace NadekoBot.Modules.Administration
|
||||
var beforeVch = before.VoiceChannel;
|
||||
if (beforeVch != null)
|
||||
{
|
||||
var textChannel = (await guild.GetTextChannelsAsync()).Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
|
||||
var textChannel = guild.TextChannels.Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
|
||||
if (textChannel != null)
|
||||
await textChannel.AddPermissionOverwriteAsync(user,
|
||||
new OverwritePermissions(readMessages: PermValue.Deny,
|
||||
sendMessages: PermValue.Deny)).ConfigureAwait(false);
|
||||
}
|
||||
var afterVch = after.VoiceChannel;
|
||||
if (afterVch != null && guild.AFKChannelId != afterVch.Id)
|
||||
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
||||
{
|
||||
var textChannel = (await guild.GetTextChannelsAsync())
|
||||
ITextChannel textChannel = guild.TextChannels
|
||||
.Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant())
|
||||
.FirstOrDefault();
|
||||
if (textChannel == null)
|
||||
|
@ -36,10 +36,8 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
.GetAllWars()
|
||||
.Select(cw =>
|
||||
{
|
||||
cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)
|
||||
?.GetTextChannelAsync(cw.ChannelId)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)?
|
||||
.GetTextChannel(cw.ChannelId);
|
||||
return cw;
|
||||
})
|
||||
.Where(cw => cw.Channel != null)
|
||||
@ -322,7 +320,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
|
||||
public static async Task<ClashWar> CreateWar(string enemyClan, int size, ulong serverId, ulong channelId)
|
||||
{
|
||||
var channel = await NadekoBot.Client.GetGuild(serverId)?.GetTextChannelAsync(channelId);
|
||||
var channel = NadekoBot.Client.GetGuild(serverId)?.GetTextChannel(channelId);
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var cw = new ClashWar
|
||||
|
@ -10,14 +10,16 @@ using NadekoBot.Extensions;
|
||||
using NLog;
|
||||
using System.Diagnostics;
|
||||
using Discord.WebSocket;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
[NadekoModule("CustomReactions", ".")]
|
||||
public class CustomReactions : DiscordModule
|
||||
{
|
||||
public static ConcurrentHashSet<CustomReaction> GlobalReactions { get; } = new ConcurrentHashSet<CustomReaction>();
|
||||
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>> GuildReactions { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>();
|
||||
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
|
||||
public static CustomReaction[] GlobalReactions => _globalReactions;
|
||||
public static ConcurrentDictionary<ulong, CustomReaction[]> GuildReactions { get; } = new ConcurrentDictionary<ulong, CustomReaction[]>();
|
||||
|
||||
public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
|
||||
|
||||
@ -30,8 +32,8 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var items = uow.CustomReactions.GetAll();
|
||||
GuildReactions = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => new ConcurrentHashSet<CustomReaction>(g)));
|
||||
GlobalReactions = new ConcurrentHashSet<CustomReaction>(items.Where(g => g.GuildId == null || g.GuildId == 0));
|
||||
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
|
||||
_globalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
|
||||
}
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
@ -46,17 +48,24 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
return false;
|
||||
|
||||
var content = umsg.Content.Trim().ToLowerInvariant();
|
||||
ConcurrentHashSet<CustomReaction> reactions;
|
||||
CustomReaction[] reactions;
|
||||
|
||||
GuildReactions.TryGetValue(channel.Guild.Id, out reactions);
|
||||
if (reactions != null && reactions.Any())
|
||||
{
|
||||
var reaction = reactions.Where(cr =>
|
||||
var rs = reactions.Where(cr =>
|
||||
{
|
||||
if (cr == null)
|
||||
return false;
|
||||
|
||||
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
|
||||
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
|
||||
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
|
||||
}).Shuffle().FirstOrDefault();
|
||||
}).ToArray();
|
||||
|
||||
if (rs.Length != 0)
|
||||
{
|
||||
var reaction = rs[new NadekoRandom().Next(0, rs.Length)];
|
||||
if (reaction != null)
|
||||
{
|
||||
if (reaction.Response != "-")
|
||||
@ -66,12 +75,19 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
return true;
|
||||
}
|
||||
}
|
||||
var greaction = GlobalReactions.Where(cr =>
|
||||
}
|
||||
|
||||
var grs = GlobalReactions.Where(cr =>
|
||||
{
|
||||
if (cr == null)
|
||||
return false;
|
||||
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
|
||||
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
|
||||
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
|
||||
}).Shuffle().FirstOrDefault();
|
||||
}).ToArray();
|
||||
if (grs.Length == 0)
|
||||
return false;
|
||||
var greaction = grs[new NadekoRandom().Next(0, grs.Length)];
|
||||
|
||||
if (greaction != null)
|
||||
{
|
||||
@ -114,12 +130,19 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
|
||||
if (channel == null)
|
||||
{
|
||||
GlobalReactions.Add(cr);
|
||||
Array.Resize(ref _globalReactions, _globalReactions.Length + 1);
|
||||
_globalReactions[_globalReactions.Length - 1] = cr;
|
||||
}
|
||||
else
|
||||
{
|
||||
var reactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
|
||||
reactions.Add(cr);
|
||||
var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id,
|
||||
Array.Empty<CustomReaction>(),
|
||||
(k, old) =>
|
||||
{
|
||||
Array.Resize(ref old, old.Length + 1);
|
||||
old[old.Length - 1] = cr;
|
||||
return old;
|
||||
});
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
@ -136,17 +159,17 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
if (page < 1 || page > 1000)
|
||||
return;
|
||||
ConcurrentHashSet<CustomReaction> customReactions;
|
||||
CustomReaction[] customReactions;
|
||||
if (Context.Guild == null)
|
||||
customReactions = GlobalReactions;
|
||||
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
|
||||
else
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty<CustomReaction>()).Where(cr => cr != null).ToArray();
|
||||
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
var lastPage = customReactions.Count / 20;
|
||||
var lastPage = customReactions.Length / 20;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, curPage =>
|
||||
new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("Custom reactions")
|
||||
@ -167,11 +190,11 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
[Priority(1)]
|
||||
public async Task ListCustReact(All x)
|
||||
{
|
||||
ConcurrentHashSet<CustomReaction> customReactions;
|
||||
CustomReaction[] customReactions;
|
||||
if (Context.Guild == null)
|
||||
customReactions = GlobalReactions;
|
||||
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
|
||||
else
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
|
||||
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
@ -195,11 +218,11 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
if (page < 1 || page > 10000)
|
||||
return;
|
||||
ConcurrentHashSet<CustomReaction> customReactions;
|
||||
CustomReaction[] customReactions;
|
||||
if (Context.Guild == null)
|
||||
customReactions = GlobalReactions;
|
||||
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
|
||||
else
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
|
||||
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
@ -225,13 +248,13 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task ShowCustReact(int id)
|
||||
{
|
||||
ConcurrentHashSet<CustomReaction> customReactions;
|
||||
CustomReaction[] customReactions;
|
||||
if (Context.Guild == null)
|
||||
customReactions = GlobalReactions;
|
||||
else
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>());
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ });
|
||||
|
||||
var found = customReactions.FirstOrDefault(cr => cr.Id == id);
|
||||
var found = customReactions.FirstOrDefault(cr => cr?.Id == id);
|
||||
|
||||
if (found == null)
|
||||
await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false);
|
||||
@ -265,13 +288,17 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null)
|
||||
{
|
||||
uow.CustomReactions.Remove(toDelete);
|
||||
GlobalReactions.RemoveWhere(cr => cr.Id == toDelete.Id);
|
||||
//todo i can dramatically improve performance of this, if Ids are ordered.
|
||||
_globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray();
|
||||
success = true;
|
||||
}
|
||||
else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId)
|
||||
{
|
||||
uow.CustomReactions.Remove(toDelete);
|
||||
GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()).RemoveWhere(cr => cr.Id == toDelete.Id);
|
||||
GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) =>
|
||||
{
|
||||
return old.Where(cr => cr?.Id != toDelete.Id).ToArray();
|
||||
});
|
||||
success = true;
|
||||
}
|
||||
if (success)
|
||||
@ -312,8 +339,10 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
if (page < 1)
|
||||
return;
|
||||
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToList();
|
||||
var lastPage = ordered.Count / 9;
|
||||
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToArray();
|
||||
if (!ordered.Any())
|
||||
return;
|
||||
var lastPage = ordered.Length / 9;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page,
|
||||
(curPage) => ordered.Skip((curPage - 1) * 9)
|
||||
.Take(9)
|
||||
|
@ -1,9 +1,11 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@ -25,9 +27,13 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if(ch == null)
|
||||
return "";
|
||||
|
||||
var usrs = (ch.Guild.GetUsersAsync().GetAwaiter().GetResult());
|
||||
var g = ch.Guild as SocketGuild;
|
||||
if(g == null)
|
||||
return "";
|
||||
|
||||
return usrs.Skip(new NadekoRandom().Next(0,usrs.Count-1)).Shuffle().FirstOrDefault()?.Mention ?? "";
|
||||
var users = g.Users.ToArray();
|
||||
|
||||
return users[new NadekoRandom().Next(0, users.Length-1)].Mention;
|
||||
} }
|
||||
//{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } }
|
||||
};
|
||||
|
@ -9,6 +9,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services.Database;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
@ -19,15 +21,26 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
public enum CurrencyEvent
|
||||
{
|
||||
FlowerReaction
|
||||
FlowerReaction,
|
||||
SneakyGameStatus
|
||||
}
|
||||
//flower reaction event
|
||||
public static readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
public static readonly ConcurrentHashSet<ulong> _sneakyGameAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
|
||||
|
||||
private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10)
|
||||
.Concat(Enumerable.Range(65, 26))
|
||||
.Concat(Enumerable.Range(97, 26))
|
||||
.Select(x => (char)x)
|
||||
.ToArray();
|
||||
|
||||
private static string _secretCode = String.Empty;
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartEvent(CurrencyEvent e)
|
||||
public async Task StartEvent(CurrencyEvent e, int arg = -1)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
try
|
||||
@ -38,6 +51,9 @@ namespace NadekoBot.Modules.Gambling
|
||||
case CurrencyEvent.FlowerReaction:
|
||||
await FlowerReactionEvent(Context).ConfigureAwait(false);
|
||||
break;
|
||||
case CurrencyEvent.SneakyGameStatus:
|
||||
await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -45,6 +61,63 @@ namespace NadekoBot.Modules.Gambling
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static async Task SneakyGameStatusEvent(CommandContext Context, int? arg)
|
||||
{
|
||||
int num;
|
||||
if (arg == null || arg < 5)
|
||||
num = 60;
|
||||
else
|
||||
num = arg.Value;
|
||||
|
||||
if (_secretCode != String.Empty)
|
||||
return;
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
_secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
||||
}
|
||||
|
||||
await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName)
|
||||
.ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync($"SneakyGameStatus event started",
|
||||
$"Users must type a secret code to get 100 currency.\n" +
|
||||
$"Lasts {num} seconds. Don't tell anyone. Shhh.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
NadekoBot.Client.MessageReceived += SneakyGameMessageReceivedEventHandler;
|
||||
await Task.Delay(num * 1000);
|
||||
NadekoBot.Client.MessageReceived -= SneakyGameMessageReceivedEventHandler;
|
||||
|
||||
_sneakyGameAwardedUsers.Clear();
|
||||
_secretCode = String.Empty;
|
||||
|
||||
await NadekoBot.Client.SetGameAsync($"SneakyGame event ended.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static Task SneakyGameMessageReceivedEventHandler(SocketMessage arg)
|
||||
{
|
||||
if (arg.Content == _secretCode &&
|
||||
_sneakyGameAwardedUsers.Add(arg.Author.Id))
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
await CurrencyHandler.AddCurrencyAsync(arg.Author, "Sneaky Game Event", 100, false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); }
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
|
||||
return Task.Delay(0);
|
||||
}
|
||||
|
||||
public static async Task FlowerReactionEvent(CommandContext Context)
|
||||
{
|
||||
@ -59,14 +132,14 @@ namespace NadekoBot.Modules.Gambling
|
||||
catch
|
||||
{
|
||||
try { await msg.DeleteAsync().ConfigureAwait(false); }
|
||||
catch { }
|
||||
catch { return; }
|
||||
}
|
||||
}
|
||||
using (msg.OnReaction(async (r) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
||||
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
||||
{
|
||||
try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
|
@ -184,7 +184,10 @@ namespace NadekoBot.Modules.Gambling
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
|
516
src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs
Normal file
516
src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs
Normal file
@ -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<ulong, DateTime> _divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||
private static ConcurrentDictionary<ulong, DateTime> _affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||
|
||||
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<WaifuInfo> 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<WaifuInfo> 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
|
||||
title = AffinityTitles.Harlot;
|
||||
|
||||
return new WaifuProfileTitle(count, title.ToString().Replace('_', ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown);
|
||||
var membersArray = members as IUser[] ?? members.ToArray();
|
||||
var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
|
||||
await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}** ID: `{usr.Id}`").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -67,14 +67,14 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
if (amount <= 0 || Context.User.Id == receiver.Id)
|
||||
return;
|
||||
var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, true).ConfigureAwait(false);
|
||||
var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, false).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} gifted {amount}{CurrencySign} to {Format.Bold(receiver.ToString())}!").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount}{CurrencySign} to <@{usrId}>!").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -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<int, int>();
|
||||
// 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)
|
||||
{
|
||||
@ -193,22 +248,33 @@ namespace NadekoBot.Modules.Gambling
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Leaderboard()
|
||||
{
|
||||
IEnumerable<Currency> richest = new List<Currency>();
|
||||
var richest = new List<Currency>();
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
richest = uow.Currency.GetTopRichest(10);
|
||||
richest = uow.Currency.GetTopRichest(9).ToList();
|
||||
}
|
||||
if (!richest.Any())
|
||||
return;
|
||||
await Context.Channel.SendMessageAsync(
|
||||
richest.Aggregate(new StringBuilder(
|
||||
$@"```xl
|
||||
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓
|
||||
┃ Id ┃ $$$ ┃
|
||||
"),
|
||||
(cur, cs) => cur.AppendLine($@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━┫
|
||||
┃{(Context.Guild.GetUserAsync(cs.UserId).GetAwaiter().GetResult()?.Username?.TrimTo(18, true) ?? cs.UserId.ToString()),-20} ┃ {cs.Amount,6} ┃")
|
||||
).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━┛```").ConfigureAwait(false);
|
||||
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle(NadekoBot.BotConfig.CurrencySign + " Leaderboard");
|
||||
|
||||
for (var i = 0; i < richest.Count; i++)
|
||||
{
|
||||
var x = richest[i];
|
||||
var usr = await Context.Guild.GetUserAsync(x.UserId).ConfigureAwait(false);
|
||||
var usrStr = "";
|
||||
if (usr == null)
|
||||
usrStr = x.UserId.ToString();
|
||||
else
|
||||
usrStr = usr.Username?.TrimTo(20, true);
|
||||
|
||||
embed.AddField(efb => efb.WithName("#" + (i + 1) + " " + usrStr).WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign).WithIsInline(true));
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ namespace NadekoBot.Modules.Games
|
||||
private readonly ConcurrentDictionary<string, IGuildUser> submissions = new ConcurrentDictionary<string, IGuildUser>();
|
||||
public IReadOnlyDictionary<string, IGuildUser> Submissions => submissions;
|
||||
|
||||
private readonly ConcurrentHashSet<ulong> usersWhoSubmitted = new ConcurrentHashSet<ulong>();
|
||||
private readonly ConcurrentHashSet<ulong> usersWhoVoted = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private int spamCount = 0;
|
||||
@ -190,10 +191,6 @@ namespace NadekoBot.Modules.Games
|
||||
try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
||||
catch { }
|
||||
}
|
||||
//user didn't input something already
|
||||
IGuildUser throwaway;
|
||||
if (submissions.TryGetValue(input, out throwaway))
|
||||
return;
|
||||
var inputWords = input.Split(' '); //get all words
|
||||
|
||||
if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters
|
||||
@ -207,9 +204,15 @@ namespace NadekoBot.Modules.Games
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!usersWhoSubmitted.Add(guildUser.Id))
|
||||
return;
|
||||
//try adding it to the list of answers
|
||||
if (!submissions.TryAdd(input, guildUser))
|
||||
{
|
||||
usersWhoSubmitted.TryRemove(guildUser.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
// all good. valid input. answer recorded
|
||||
await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)");
|
||||
|
@ -189,12 +189,12 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
|
||||
public string GetHangman() => $@"\_\_\_\_\_\_\_\_\_
|
||||
| |
|
||||
| |
|
||||
{(Errors > 0 ? "😲" : " ")} |
|
||||
{(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} |
|
||||
{(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} |
|
||||
public string GetHangman() => $@". ┌─────┐
|
||||
.┃...............┋
|
||||
.┃...............┋
|
||||
.┃{(Errors > 0 ? ".............😲" : "")}
|
||||
.┃{(Errors > 1 ? "............./" : "")} {(Errors > 2 ? "|" : "")} {(Errors > 3 ? "\\" : "")}
|
||||
.┃{(Errors > 4 ? "............../" : "")} {(Errors > 5 ? "\\" : "")}
|
||||
/-\";
|
||||
|
||||
public void Dispose()
|
||||
|
@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Games
|
||||
return;
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman() + "\n" + hm.ScrambledWord);
|
||||
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,9 +147,12 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Plant()
|
||||
public async Task Plant(int amount = 1)
|
||||
{
|
||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", 1, false).ConfigureAwait(false);
|
||||
if (amount < 1)
|
||||
return;
|
||||
|
||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false);
|
||||
if (!removed)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You don't have any {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false);
|
||||
@ -160,7 +163,7 @@ namespace NadekoBot.Modules.Games
|
||||
IUserMessage msg;
|
||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
|
||||
|
||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.BotConfig.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
|
||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
|
||||
if (file == null)
|
||||
{
|
||||
msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
@ -169,7 +172,15 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), new FileInfo(file).Name, msgToSend).ConfigureAwait(false);
|
||||
}
|
||||
plantedFlowers.AddOrUpdate(Context.Channel.Id, new List<IUserMessage>() { msg }, (id, old) => { old.Add(msg); return old; });
|
||||
|
||||
var msgs = new IUserMessage[amount];
|
||||
msgs[0] = msg;
|
||||
|
||||
plantedFlowers.AddOrUpdate(Context.Channel.Id, msgs.ToList(), (id, old) =>
|
||||
{
|
||||
old.AddRange(msgs);
|
||||
return old;
|
||||
});
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -76,9 +76,9 @@ namespace NadekoBot.Modules.Games.Trivia
|
||||
|
||||
questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound ||
|
||||
ex.StatusCode == System.Net.HttpStatusCode.Forbidden ||
|
||||
ex.StatusCode == System.Net.HttpStatusCode.BadRequest)
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound ||
|
||||
ex.HttpCode == System.Net.HttpStatusCode.Forbidden ||
|
||||
ex.HttpCode == System.Net.HttpStatusCode.BadRequest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
||||
await questionMessage.ModifyAsync(m => m.Embed = questionEmbed.WithFooter(efb => efb.WithText(CurrentQuestion.GetHint())).Build())
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound || ex.StatusCode == System.Net.HttpStatusCode.Forbidden)
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound || ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games
|
||||
[NadekoModule("Games", ">")]
|
||||
public partial class Games : DiscordModule
|
||||
{
|
||||
private static IEnumerable<string> _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text);
|
||||
private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray();
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -37,7 +37,7 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||
.AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false)));
|
||||
.AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false)));
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -71,6 +71,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
public event Action<bool> OnPauseChanged = delegate { };
|
||||
|
||||
public IVoiceChannel PlaybackVoiceChannel { get; private set; }
|
||||
public ITextChannel OutputTextChannel { get; set; }
|
||||
|
||||
private bool Destroyed { get; set; } = false;
|
||||
public bool RepeatSong { get; private set; } = false;
|
||||
@ -84,10 +85,12 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
public event Action<Song, int> SongRemoved = delegate { };
|
||||
|
||||
public MusicPlayer(IVoiceChannel startingVoiceChannel, float? defaultVolume)
|
||||
public MusicPlayer(IVoiceChannel startingVoiceChannel, ITextChannel outputChannel, float? defaultVolume)
|
||||
{
|
||||
if (startingVoiceChannel == null)
|
||||
throw new ArgumentNullException(nameof(startingVoiceChannel));
|
||||
|
||||
OutputTextChannel = outputChannel;
|
||||
Volume = defaultVolume ?? 1.0f;
|
||||
|
||||
PlaybackVoiceChannel = startingVoiceChannel;
|
||||
|
@ -97,7 +97,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
{
|
||||
Title = video.Title.Substring(0, video.Title.Length - 10), // removing trailing "- You Tube"
|
||||
Provider = "YouTube",
|
||||
Uri = video.Uri,
|
||||
Uri = await video.GetUriAsync().ConfigureAwait(false),
|
||||
Query = link,
|
||||
ProviderType = musicType,
|
||||
});
|
||||
|
@ -211,30 +211,30 @@ namespace NadekoBot.Modules.Music
|
||||
{
|
||||
int startAt = itemsPerPage * (curPage - 1);
|
||||
var number = 0 + startAt;
|
||||
var desc = string.Join("\n", musicPlayer.Playlist
|
||||
.Skip(startAt)
|
||||
.Take(itemsPerPage)
|
||||
.Select(v => $"`{++number}.` {v.PrettyFullName}"));
|
||||
|
||||
if (currentSong != null)
|
||||
desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc;
|
||||
|
||||
if (musicPlayer.RepeatSong)
|
||||
desc = "🔂 Repeating Current Song\n\n" + desc;
|
||||
else if (musicPlayer.RepeatPlaylist)
|
||||
desc = "🔁 Repeating Playlist\n\n" + desc;
|
||||
|
||||
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor(eab => eab.WithName($"Player Queue - Page {curPage}/{lastPage + 1}")
|
||||
.WithMusicIcon())
|
||||
.WithDescription(string.Join("\n", musicPlayer.Playlist
|
||||
.Skip(startAt)
|
||||
.Take(itemsPerPage)
|
||||
.Select(v => $"`{++number}.` {v.PrettyFullName}")))
|
||||
.WithDescription(desc)
|
||||
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
||||
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " +
|
||||
(musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit")))
|
||||
.WithOkColor();
|
||||
|
||||
if (musicPlayer.RepeatSong)
|
||||
{
|
||||
embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}");
|
||||
}
|
||||
else if (musicPlayer.RepeatPlaylist)
|
||||
{
|
||||
embed.WithTitle("🔁 Repeating Playlist");
|
||||
}
|
||||
if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize)
|
||||
{
|
||||
embed.WithTitle("🎵 Song queue is full!");
|
||||
}
|
||||
return embed;
|
||||
};
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, printAction, lastPage, false).ConfigureAwait(false);
|
||||
@ -712,13 +712,10 @@ namespace NadekoBot.Modules.Music
|
||||
|
||||
}
|
||||
|
||||
//todo only author or owner
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task DeletePlaylist([Remainder] int id)
|
||||
{
|
||||
|
||||
|
||||
bool success = false;
|
||||
MusicPlaylist pl = null;
|
||||
try
|
||||
@ -747,7 +744,7 @@ namespace NadekoBot.Modules.Music
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -800,6 +797,23 @@ namespace NadekoBot.Modules.Music
|
||||
await Context.Channel.SendConfirmAsync("✅ Autoplay enabled.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task SetMusicChannel()
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("Music must be playing before you set an ouput channel.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel;
|
||||
|
||||
await Context.Channel.SendConfirmAsync("I will now output playing, finished, paused and removed songs in this channel.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||
{
|
||||
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
||||
@ -818,7 +832,7 @@ namespace NadekoBot.Modules.Music
|
||||
{
|
||||
vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
|
||||
}
|
||||
var mp = new MusicPlayer(voiceCh, vol);
|
||||
var mp = new MusicPlayer(voiceCh, textCh, vol);
|
||||
IUserMessage playingMessage = null;
|
||||
IUserMessage lastFinishedMessage = null;
|
||||
mp.OnCompleted += async (s, song) =>
|
||||
@ -828,7 +842,7 @@ namespace NadekoBot.Modules.Music
|
||||
if (lastFinishedMessage != null)
|
||||
lastFinishedMessage.DeleteAfter(0);
|
||||
|
||||
lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon())
|
||||
.WithDescription(song.PrettyName)
|
||||
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
||||
@ -836,7 +850,14 @@ namespace NadekoBot.Modules.Music
|
||||
|
||||
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.ProviderType == MusicType.Normal)
|
||||
{
|
||||
await QueueSong(await queuer.Guild.GetCurrentUserAsync(), textCh, voiceCh, (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false);
|
||||
var relatedVideos = (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList();
|
||||
if(relatedVideos.Count > 0)
|
||||
await QueueSong(await queuer.Guild.GetCurrentUserAsync(),
|
||||
textCh,
|
||||
voiceCh,
|
||||
relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)],
|
||||
silent,
|
||||
musicType).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
@ -853,7 +874,7 @@ namespace NadekoBot.Modules.Music
|
||||
if (playingMessage != null)
|
||||
playingMessage.DeleteAfter(0);
|
||||
|
||||
playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon())
|
||||
.WithDescription(song.PrettyName)
|
||||
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
||||
@ -867,9 +888,9 @@ namespace NadekoBot.Modules.Music
|
||||
{
|
||||
IUserMessage msg;
|
||||
if (paused)
|
||||
msg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false);
|
||||
msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false);
|
||||
else
|
||||
msg = await textCh.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false);
|
||||
msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false);
|
||||
|
||||
if (msg != null)
|
||||
msg.DeleteAfter(10);
|
||||
@ -877,7 +898,6 @@ namespace NadekoBot.Modules.Music
|
||||
catch { }
|
||||
};
|
||||
|
||||
|
||||
mp.SongRemoved += async (song, index) =>
|
||||
{
|
||||
try
|
||||
@ -888,7 +908,7 @@ namespace NadekoBot.Modules.Music
|
||||
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
||||
.WithErrorColor();
|
||||
|
||||
await textCh.EmbedAsync(embed).ConfigureAwait(false);
|
||||
await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch { }
|
||||
|
@ -289,6 +289,6 @@ namespace NadekoBot.Modules.NSFW
|
||||
|
||||
public static Task<string> GetRule34ImageLink(string tag) =>
|
||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -65,12 +65,12 @@ namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
||||
activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
|
||||
await channel.SendConfirmAsync($"🚮 Command **{command}** has no coooldown now and all existing cooldowns have been cleared.")
|
||||
await channel.SendConfirmAsync($"🚮 Command **{command.Aliases.First()}** has no coooldown now and all existing cooldowns have been cleared.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await channel.SendConfirmAsync($"✅ Command **{command}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.")
|
||||
await channel.SendConfirmAsync($"✅ Command **{command.Aliases.First()}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
using Discord;
|
||||
using AngleSharp;
|
||||
using AngleSharp.Dom.Html;
|
||||
using AngleSharp.Extensions;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
@ -8,6 +11,7 @@ using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -52,6 +56,116 @@ namespace NadekoBot.Modules.Searches
|
||||
}, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29));
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Priority(1)]
|
||||
public async Task Mal([Remainder] string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
|
||||
var fullQueryLink = "https://myanimelist.net/profile/" + name;
|
||||
|
||||
var config = Configuration.Default.WithDefaultLoader();
|
||||
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
|
||||
|
||||
var imageElem = document.QuerySelector("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-left > div.user-profile > div.user-image > img");
|
||||
var imageUrl = ((IHtmlImageElement)imageElem)?.Source ?? "http://icecream.me/uploads/870b03f36b59cc16ebfe314ef2dde781.png";
|
||||
|
||||
var stats = document.QuerySelectorAll("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-right > div#statistics > div.user-statistics-stats > div.stats > div.clearfix > ul.stats-status > li > span").Select(x => x.InnerHtml).ToList();
|
||||
|
||||
var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc");
|
||||
|
||||
var favAnime = "No favorite anime yet";
|
||||
if (favorites[0].QuerySelector("p") == null)
|
||||
favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
|
||||
.Shuffle()
|
||||
.Take(3)
|
||||
.Select(x =>
|
||||
{
|
||||
var elem = (IHtmlAnchorElement)x;
|
||||
return $"[{elem.InnerHtml}]({elem.Href})";
|
||||
}));
|
||||
|
||||
//var favManga = "No favorite manga yet.";
|
||||
//if (favorites[1].QuerySelector("p") == null)
|
||||
// favManga = string.Join("\n", favorites[1].QuerySelectorAll("ul > li > div.di-tc.va-t > a")
|
||||
// .Take(3)
|
||||
// .Select(x =>
|
||||
// {
|
||||
// var elem = (IHtmlAnchorElement)x;
|
||||
// return $"[{elem.InnerHtml}]({elem.Href})";
|
||||
// }));
|
||||
|
||||
var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li")
|
||||
.Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml))
|
||||
.ToList();
|
||||
|
||||
var daysAndMean = document.QuerySelectorAll("div.anime:nth-child(1) > div:nth-child(2) > div")
|
||||
.Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray())
|
||||
.ToArray();
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle($"{name}'s MAL profile")
|
||||
.AddField(efb => efb.WithName("💚 Watching").WithValue(stats[0]).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("💙 Completed").WithValue(stats[1]).WithIsInline(true));
|
||||
if (info.Count < 3)
|
||||
embed.AddField(efb => efb.WithName("💛 On-Hold").WithValue(stats[2]).WithIsInline(true));
|
||||
embed
|
||||
.AddField(efb => efb.WithName("💔 Dropped").WithValue(stats[3]).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("⚪ Plan to watch").WithValue(stats[4]).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("🕐 " + daysAndMean[0][0]).WithValue(daysAndMean[0][1]).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("📊 " + daysAndMean[1][0]).WithValue(daysAndMean[1][1]).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(MalInfoToEmoji(info[0].Item1) + " " + info[0].Item1).WithValue(info[0].Item2.TrimTo(20)).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(MalInfoToEmoji(info[1].Item1) + " " + info[1].Item1).WithValue(info[1].Item2.TrimTo(20)).WithIsInline(true));
|
||||
if (info.Count > 2)
|
||||
embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[2].Item1) + " " + info[2].Item1).WithValue(info[2].Item2.TrimTo(20)).WithIsInline(true));
|
||||
//if(info.Count > 3)
|
||||
// embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[3].Item1) + " " + info[3].Item1).WithValue(info[3].Item2).WithIsInline(true))
|
||||
embed
|
||||
.WithDescription($@"
|
||||
** https://myanimelist.net/animelist/{ name } **
|
||||
|
||||
**Top 3 Favorite Anime:**
|
||||
{favAnime}"
|
||||
|
||||
//**[Manga List](https://myanimelist.net/mangalist/{name})**
|
||||
//💚`Reading:` {stats[5]}
|
||||
//💙`Completed:` {stats[6]}
|
||||
//💔`Dropped:` {stats[8]}
|
||||
//⚪`Plan to read:` {stats[9]}
|
||||
|
||||
//**Top 3 Favorite Manga:**
|
||||
//{favManga}"
|
||||
|
||||
)
|
||||
.WithUrl(fullQueryLink)
|
||||
.WithImageUrl(imageUrl);
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string MalInfoToEmoji(string info) {
|
||||
info = info.Trim().ToLowerInvariant();
|
||||
switch (info)
|
||||
{
|
||||
case "gender":
|
||||
return "🚁";
|
||||
case "location":
|
||||
return "🗺";
|
||||
case "last online":
|
||||
return "👥";
|
||||
case "birthday":
|
||||
return "📆";
|
||||
default:
|
||||
return "❔";
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Priority(0)]
|
||||
public Task Mal(IUser usr) => Mal(usr.Username);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Anime([Remainder] string query)
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Searches
|
||||
MemoryStream ms = new MemoryStream();
|
||||
res.CopyTo(ms);
|
||||
ms.Position = 0;
|
||||
await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link: **https://osu.ppy.sh/u/{Uri.EscapeDataString(usr)}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link:** <https://new.ppy.sh/u/{Uri.EscapeDataString(usr)}>\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -46,11 +46,7 @@ namespace NadekoBot.Modules.Searches
|
||||
.WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png")
|
||||
.AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true))
|
||||
.WithOkColor();
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
@ -64,9 +60,9 @@ namespace NadekoBot.Modules.Searches
|
||||
.WithThumbnailUrl(rankimg)
|
||||
.AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true))
|
||||
@ -96,7 +92,6 @@ namespace NadekoBot.Modules.Searches
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -105,7 +105,7 @@ namespace NadekoBot.Modules.Searches
|
||||
var server = NadekoBot.Client.GetGuild(fs.GuildId);
|
||||
if (server == null)
|
||||
return;
|
||||
var channel = await server.GetTextChannelAsync(fs.ChannelId);
|
||||
var channel = server.GetTextChannel(fs.ChannelId);
|
||||
if (channel == null)
|
||||
return;
|
||||
try
|
||||
|
@ -117,6 +117,23 @@ namespace NadekoBot.Modules.Searches
|
||||
|
||||
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
||||
|
||||
try
|
||||
{
|
||||
var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false);
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
||||
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
|
||||
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
||||
.WithDescription(res.Link)
|
||||
.WithImageUrl(res.Link)
|
||||
.WithTitle(Context.User.Mention);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Falling back to Imgur search.");
|
||||
|
||||
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
|
||||
var config = Configuration.Default.WithDefaultLoader();
|
||||
var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink);
|
||||
@ -143,6 +160,7 @@ namespace NadekoBot.Modules.Searches
|
||||
.WithTitle(Context.User.Mention);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task RandomImage([Remainder] string terms = null)
|
||||
@ -150,7 +168,23 @@ namespace NadekoBot.Modules.Searches
|
||||
terms = terms?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(terms))
|
||||
return;
|
||||
|
||||
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
||||
try
|
||||
{
|
||||
var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false);
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50))
|
||||
.WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch")
|
||||
.WithIconUrl("http://i.imgur.com/G46fm8J.png"))
|
||||
.WithDescription(res.Link)
|
||||
.WithImageUrl(res.Link)
|
||||
.WithTitle(Context.User.Mention);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Falling back to Imgur");
|
||||
terms = WebUtility.UrlEncode(terms).Replace(' ', '+');
|
||||
|
||||
var fullQueryLink = $"http://imgur.com/search?q={ terms }";
|
||||
@ -179,6 +213,7 @@ namespace NadekoBot.Modules.Searches
|
||||
.WithTitle(Context.User.Mention);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Lmgtfy([Remainder] string ffs = null)
|
||||
@ -285,10 +320,10 @@ namespace NadekoBot.Modules.Searches
|
||||
.ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var items = JArray.Parse(response).Shuffle().ToList();
|
||||
if (items == null)
|
||||
var items = JArray.Parse(response).ToArray();
|
||||
if (items == null || items.Length == 0)
|
||||
throw new KeyNotFoundException("Cannot find a card by that name");
|
||||
var item = items[0];
|
||||
var item = items[new NadekoRandom().Next(0, items.Length)];
|
||||
var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString());
|
||||
var cost = item["cost"].ToString();
|
||||
var desc = item["text"].ToString();
|
||||
@ -343,6 +378,8 @@ namespace NadekoBot.Modules.Searches
|
||||
if (items == null)
|
||||
throw new KeyNotFoundException("Cannot find a card by that name");
|
||||
foreach (var item in items.Where(item => item.HasValues && item["img"] != null).Take(4))
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
using (var sr = await http.GetStreamAsync(item["img"].ToString()))
|
||||
{
|
||||
@ -351,6 +388,7 @@ namespace NadekoBot.Modules.Searches
|
||||
imgStream.Position = 0;
|
||||
images.Add(new ImageSharp.Image(imgStream));
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
string msg = null;
|
||||
if (items.Count > 4)
|
||||
@ -358,7 +396,7 @@ namespace NadekoBot.Modules.Searches
|
||||
msg = "⚠ Found over 4 images. Showing random 4.";
|
||||
}
|
||||
var ms = new MemoryStream();
|
||||
images.AsEnumerable().Merge().SaveAsPng(ms);
|
||||
await Task.Run(() => images.AsEnumerable().Merge().SaveAsPng(ms));
|
||||
ms.Position = 0;
|
||||
await Context.Channel.SendFileAsync(ms, arg + ".png", msg).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Utility
|
||||
}
|
||||
|
||||
private static string GetText(IGuild server, ITextChannel channel, IGuildUser user, IUserMessage message) =>
|
||||
$"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content;
|
||||
$"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
|
||||
|
||||
public static readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers = new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
|
||||
private static Logger _log { get; }
|
||||
|
@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Utility
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
if (guild.Emojis.Count() > 0)
|
||||
{
|
||||
embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(string.Join(" ", guild.Emojis.Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||
embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(25).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||
}
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
@ -97,8 +97,10 @@ namespace NadekoBot.Modules.Utility
|
||||
.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 - 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);
|
||||
|
||||
if (user.AvatarId != null)
|
||||
embed.WithThumbnailUrl(user.RealAvatarUrl());
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
this.Repeater = repeater;
|
||||
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult();
|
||||
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId);
|
||||
if (Channel == null)
|
||||
return;
|
||||
Task.Run(Run);
|
||||
@ -69,12 +69,12 @@ namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden)
|
||||
catch (HttpException ex) when (ex.HttpCode == 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)
|
||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
_log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id);
|
||||
return;
|
||||
|
@ -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);
|
||||
}
|
||||
@ -93,24 +93,31 @@ namespace NadekoBot.Modules.Utility
|
||||
var isAdmin = ((IGuildUser)Context.Message.Author).GuildPermissions.Administrator;
|
||||
|
||||
keyword = keyword.ToUpperInvariant();
|
||||
var sucess = false;
|
||||
string response;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var qs = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword);
|
||||
var qs = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword)?.Where(elem => isAdmin || elem.AuthorId == Context.Message.Author.Id).ToArray();
|
||||
|
||||
if (qs == null || !qs.Any())
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("No quotes found.").ConfigureAwait(false);
|
||||
return;
|
||||
sucess = false;
|
||||
response = "No quotes found which you can remove.";
|
||||
}
|
||||
|
||||
var q = qs.Shuffle().FirstOrDefault(elem => isAdmin || elem.AuthorId == Context.Message.Author.Id);
|
||||
else
|
||||
{
|
||||
var q = qs[new NadekoRandom().Next(0, qs.Length)];
|
||||
|
||||
uow.Quotes.Remove(q);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
sucess = true;
|
||||
response = "🗑 **Deleted a random quote.**";
|
||||
}
|
||||
}
|
||||
if(sucess)
|
||||
await Context.Channel.SendConfirmAsync(response);
|
||||
else
|
||||
await Context.Channel.SendErrorAsync(response);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -126,7 +133,7 @@ namespace NadekoBot.Modules.Utility
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var quotes = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword);
|
||||
|
||||
//todo kwoth please don't be complete retard
|
||||
uow.Quotes.RemoveRange(quotes.ToArray());//wtf?!
|
||||
|
||||
await uow.CompleteAsync();
|
||||
|
@ -68,9 +68,7 @@ namespace NadekoBot.Modules.Utility
|
||||
}
|
||||
else
|
||||
{
|
||||
var t = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannelAsync(r.ChannelId).ConfigureAwait(false);
|
||||
if (t != null)
|
||||
ch = await t.Value;
|
||||
ch = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannel(r.ChannelId);
|
||||
}
|
||||
if (ch == null)
|
||||
return;
|
||||
|
@ -15,6 +15,8 @@ using System.Threading;
|
||||
using ImageSharp;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
@ -25,6 +27,7 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[OwnerOnly]
|
||||
public async Task RotateRoleColor(int timeout, IRole role, params string[] hexes)
|
||||
{
|
||||
@ -112,19 +115,30 @@ namespace NadekoBot.Modules.Utility
|
||||
game = game.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
var arr = (await (Context.Channel as IGuildChannel).Guild.GetUsersAsync())
|
||||
|
||||
var socketGuild = Context.Guild as SocketGuild;
|
||||
if (socketGuild == null) {
|
||||
_log.Warn("Can't cast guild to socket guild.");
|
||||
return;
|
||||
}
|
||||
var rng = new NadekoRandom();
|
||||
var arr = await Task.Run(() => socketGuild.Users
|
||||
.Where(u => u.Game?.Name?.ToUpperInvariant() == game)
|
||||
.Select(u => u.Username)
|
||||
.ToList();
|
||||
.OrderBy(x => rng.Next())
|
||||
.Take(60)
|
||||
.ToArray()).ConfigureAwait(false);
|
||||
|
||||
int i = 0;
|
||||
if (!arr.Any())
|
||||
if (arr.Length == 0)
|
||||
await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2)
|
||||
.Select(ig => string.Concat(ig.Select(el => $"• {el,-27}")))) + "\n```")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
|
@ -75,7 +75,8 @@ namespace NadekoBot
|
||||
|
||||
//initialize Services
|
||||
CommandService = new CommandService(new CommandServiceConfig() {
|
||||
CaseSensitiveCommands = false
|
||||
CaseSensitiveCommands = false,
|
||||
DefaultRunMode = RunMode.Sync
|
||||
});
|
||||
Google = new GoogleApiService();
|
||||
CommandHandler = new CommandHandler(Client, CommandService);
|
||||
|
199
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
199
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
@ -177,7 +177,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%.
|
||||
/// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds%.
|
||||
/// </summary>
|
||||
public static string addplaying_desc {
|
||||
get {
|
||||
@ -879,7 +879,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet..
|
||||
/// Looks up a localized string similar to Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner..
|
||||
/// </summary>
|
||||
public static string betflip_desc {
|
||||
get {
|
||||
@ -2489,6 +2489,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to divorce.
|
||||
/// </summary>
|
||||
public static string divorce_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("divorce_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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..
|
||||
/// </summary>
|
||||
public static string divorce_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("divorce_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}divorce @CheatingSloot`.
|
||||
/// </summary>
|
||||
public static string divorce_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("divorce_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to donadd.
|
||||
/// </summary>
|
||||
@ -4379,6 +4406,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to mal.
|
||||
/// </summary>
|
||||
public static string mal_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("mal_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows basic info from myanimelist profile..
|
||||
/// </summary>
|
||||
public static string mal_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("mal_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}mal straysocks`.
|
||||
/// </summary>
|
||||
public static string mal_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("mal_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to manga mang mq.
|
||||
/// </summary>
|
||||
@ -5091,7 +5145,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost).
|
||||
/// Looks up a localized string similar to Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost).
|
||||
/// </summary>
|
||||
public static string plant_desc {
|
||||
get {
|
||||
@ -5100,7 +5154,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}plant`.
|
||||
/// Looks up a localized string similar to `{0}plant` or `{0}plant 5`.
|
||||
/// </summary>
|
||||
public static string plant_usage {
|
||||
get {
|
||||
@ -6728,6 +6782,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to setmusicchannel smch.
|
||||
/// </summary>
|
||||
public static string setmusicchannel_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("setmusicchannel_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in..
|
||||
/// </summary>
|
||||
public static string setmusicchannel_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("setmusicchannel_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}smch`.
|
||||
/// </summary>
|
||||
public static string setmusicchannel_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("setmusicchannel_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to setmuterole.
|
||||
/// </summary>
|
||||
@ -8286,7 +8367,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}voice+text`.
|
||||
/// Looks up a localized string similar to `{0}v+t`.
|
||||
/// </summary>
|
||||
public static string voiceplustext_usage {
|
||||
get {
|
||||
@ -8375,6 +8456,114 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to claimwaifu claim.
|
||||
/// </summary>
|
||||
public static string waifuclaim_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuclaim_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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..
|
||||
/// </summary>
|
||||
public static string waifuclaim_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuclaim_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}claim 50 @Himesama`.
|
||||
/// </summary>
|
||||
public static string waifuclaim_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuclaim_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to affinity.
|
||||
/// </summary>
|
||||
public static string waifuclaimeraffinity_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuclaimeraffinity_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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..
|
||||
/// </summary>
|
||||
public static string waifuclaimeraffinity_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuclaimeraffinity_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}affinity @MyHusband` or `{0}affinity`.
|
||||
/// </summary>
|
||||
public static string waifuclaimeraffinity_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuclaimeraffinity_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to waifuinfo waifustats.
|
||||
/// </summary>
|
||||
public static string waifuinfo_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuinfo_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows waifu stats for a target person. Defaults to you if no user is provided..
|
||||
/// </summary>
|
||||
public static string waifuinfo_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuinfo_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}waifuinfo @MyCrush` or `{0}waifuinfo`.
|
||||
/// </summary>
|
||||
public static string waifuinfo_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuinfo_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to waifus waifulb.
|
||||
/// </summary>
|
||||
public static string waifuleaderboard_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuleaderboard_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows top 9 waifus..
|
||||
/// </summary>
|
||||
public static string waifuleaderboard_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuleaderboard_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}waifus`.
|
||||
/// </summary>
|
||||
public static string waifuleaderboard_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("waifuleaderboard_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to weather we.
|
||||
/// </summary>
|
||||
|
@ -292,7 +292,7 @@
|
||||
<value>addplaying adpl</value>
|
||||
</data>
|
||||
<data name="addplaying_desc" xml:space="preserve">
|
||||
<value>Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%</value>
|
||||
<value>Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds%</value>
|
||||
</data>
|
||||
<data name="addplaying_usage" xml:space="preserve">
|
||||
<value>`{0}adpl`</value>
|
||||
@ -340,7 +340,7 @@
|
||||
<value>Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless.</value>
|
||||
</data>
|
||||
<data name="voiceplustext_usage" xml:space="preserve">
|
||||
<value>`{0}voice+text`</value>
|
||||
<value>`{0}v+t`</value>
|
||||
</data>
|
||||
<data name="scsc_cmd" xml:space="preserve">
|
||||
<value>scsc</value>
|
||||
@ -1183,7 +1183,7 @@
|
||||
<value>betflip bf</value>
|
||||
</data>
|
||||
<data name="betflip_desc" xml:space="preserve">
|
||||
<value>Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet.</value>
|
||||
<value>Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner.</value>
|
||||
</data>
|
||||
<data name="betflip_usage" xml:space="preserve">
|
||||
<value>`{0}bf 5 heads` or `{0}bf 3 t`</value>
|
||||
@ -1372,10 +1372,10 @@
|
||||
<value>plant</value>
|
||||
</data>
|
||||
<data name="plant_desc" xml:space="preserve">
|
||||
<value>Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost)</value>
|
||||
<value>Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost)</value>
|
||||
</data>
|
||||
<data name="plant_usage" xml:space="preserve">
|
||||
<value>`{0}plant`</value>
|
||||
<value>`{0}plant` or `{0}plant 5`</value>
|
||||
</data>
|
||||
<data name="gencurrency_cmd" xml:space="preserve">
|
||||
<value>gencurrency gc</value>
|
||||
@ -2979,4 +2979,67 @@
|
||||
<data name="slot_usage" xml:space="preserve">
|
||||
<value>`{0}slot 5`</value>
|
||||
</data>
|
||||
<data name="waifuclaimeraffinity_cmd" xml:space="preserve">
|
||||
<value>affinity</value>
|
||||
</data>
|
||||
<data name="waifuclaimeraffinity_desc" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
<data name="waifuclaimeraffinity_usage" xml:space="preserve">
|
||||
<value>`{0}affinity @MyHusband` or `{0}affinity`</value>
|
||||
</data>
|
||||
<data name="waifuclaim_cmd" xml:space="preserve">
|
||||
<value>claimwaifu claim</value>
|
||||
</data>
|
||||
<data name="waifuclaim_desc" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
<data name="waifuclaim_usage" xml:space="preserve">
|
||||
<value>`{0}claim 50 @Himesama`</value>
|
||||
</data>
|
||||
<data name="waifuleaderboard_cmd" xml:space="preserve">
|
||||
<value>waifus waifulb</value>
|
||||
</data>
|
||||
<data name="waifuleaderboard_desc" xml:space="preserve">
|
||||
<value>Shows top 9 waifus.</value>
|
||||
</data>
|
||||
<data name="waifuleaderboard_usage" xml:space="preserve">
|
||||
<value>`{0}waifus`</value>
|
||||
</data>
|
||||
<data name="divorce_cmd" xml:space="preserve">
|
||||
<value>divorce</value>
|
||||
</data>
|
||||
<data name="divorce_desc" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
<data name="divorce_usage" xml:space="preserve">
|
||||
<value>`{0}divorce @CheatingSloot`</value>
|
||||
</data>
|
||||
<data name="waifuinfo_cmd" xml:space="preserve">
|
||||
<value>waifuinfo waifustats</value>
|
||||
</data>
|
||||
<data name="waifuinfo_desc" xml:space="preserve">
|
||||
<value>Shows waifu stats for a target person. Defaults to you if no user is provided.</value>
|
||||
</data>
|
||||
<data name="waifuinfo_usage" xml:space="preserve">
|
||||
<value>`{0}waifuinfo @MyCrush` or `{0}waifuinfo`</value>
|
||||
</data>
|
||||
<data name="mal_cmd" xml:space="preserve">
|
||||
<value>mal</value>
|
||||
</data>
|
||||
<data name="mal_desc" xml:space="preserve">
|
||||
<value>Shows basic info from myanimelist profile.</value>
|
||||
</data>
|
||||
<data name="mal_usage" xml:space="preserve">
|
||||
<value>`{0}mal straysocks`</value>
|
||||
</data>
|
||||
<data name="setmusicchannel_cmd" xml:space="preserve">
|
||||
<value>setmusicchannel smch</value>
|
||||
</data>
|
||||
<data name="setmusicchannel_desc" xml:space="preserve">
|
||||
<value>Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in.</value>
|
||||
</data>
|
||||
<data name="setmusicchannel_usage" xml:space="preserve">
|
||||
<value>`{0}smch`</value>
|
||||
</data>
|
||||
</root>
|
@ -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)
|
||||
|
@ -159,8 +159,8 @@ namespace NadekoBot.Services
|
||||
|
||||
private async Task<bool> WordFiltered(IGuild guild, SocketUserMessage usrMsg)
|
||||
{
|
||||
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id);
|
||||
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id);
|
||||
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||
{
|
||||
@ -197,8 +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);
|
||||
#endif
|
||||
|
||||
var channel = msg.Channel as SocketTextChannel;
|
||||
var guild = channel?.Guild;
|
||||
@ -215,19 +217,20 @@ 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);
|
||||
// todo log custom reaction executions. return struct with info
|
||||
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)
|
||||
|
@ -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,13 +20,26 @@ namespace NadekoBot.Services
|
||||
return success;
|
||||
}
|
||||
|
||||
public static async Task<bool> RemoveCurrencyAsync(ulong authorId, string reason, long amount)
|
||||
public static async Task<bool> 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)
|
||||
{
|
||||
using (uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
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)
|
||||
@ -36,9 +50,6 @@ namespace NadekoBot.Services
|
||||
Reason = reason,
|
||||
Amount = -amount,
|
||||
});
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -50,23 +61,30 @@ 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));
|
||||
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
uow.Currency.TryUpdateState(receiverId, amount);
|
||||
uow.CurrencyTransactions.Add(new CurrencyTransaction()
|
||||
var transaction = new CurrencyTransaction()
|
||||
{
|
||||
UserId = receiverId,
|
||||
Reason = reason,
|
||||
Amount = amount,
|
||||
});
|
||||
};
|
||||
|
||||
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(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<int> CompleteAsync();
|
||||
|
@ -29,7 +29,7 @@ namespace NadekoBot.Services.Database.Models
|
||||
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<CommandCost> CommandCosts { get; set; } = new HashSet<CommandCost>();
|
||||
|
||||
|
19
src/NadekoBot/Services/Database/Models/DiscordUser.cs
Normal file
19
src/NadekoBot/Services/Database/Models/DiscordUser.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
49
src/NadekoBot/Services/Database/Models/Waifu.cs
Normal file
49
src/NadekoBot/Services/Database/Models/Waifu.cs
Normal file
@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
27
src/NadekoBot/Services/Database/Models/WaifuUpdate.cs
Normal file
27
src/NadekoBot/Services/Database/Models/WaifuUpdate.cs
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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<NadekoContext>
|
||||
{
|
||||
/// <summary>
|
||||
/// :\ Used for migrations
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
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<Quote> Quotes { get; set; }
|
||||
@ -22,6 +39,7 @@ namespace NadekoBot.Services.Database
|
||||
public DbSet<CustomReaction> CustomReactions { get; set; }
|
||||
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
|
||||
public DbSet<UserPokeTypes> PokeGame { get; set; }
|
||||
public DbSet<WaifuUpdate> WaifuUpdates { get; set; }
|
||||
|
||||
//logging
|
||||
public DbSet<LogSetting> LogSettings { get; set; }
|
||||
@ -33,23 +51,15 @@ namespace NadekoBot.Services.Database
|
||||
public DbSet<RaceAnimal> RaceAnimals { get; set; }
|
||||
public DbSet<ModulePrefix> 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<WaifuInfo>();
|
||||
wi.HasOne(x => x.Waifu)
|
||||
.WithOne();
|
||||
// //.HasForeignKey<WaifuInfo>(w => w.WaifuId)
|
||||
// //.IsRequired(true);
|
||||
|
||||
//wi.HasOne(x => x.Claimer)
|
||||
// .WithOne();
|
||||
// //.HasForeignKey<WaifuInfo>(w => w.ClaimerId)
|
||||
// //.IsRequired(false);
|
||||
|
||||
var du = modelBuilder.Entity<DiscordUser>();
|
||||
du.HasAlternateKey(w => w.UserId);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
{
|
||||
DiscordUser GetOrCreate(IUser original);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Services.Database.Repositories
|
||||
{
|
||||
public interface IWaifuRepository : IRepository<WaifuInfo>
|
||||
{
|
||||
IList<WaifuInfo> GetTop(int count);
|
||||
WaifuInfo ByWaifuUserId(ulong userId);
|
||||
IList<WaifuInfo> ByClaimerUserId(ulong userId);
|
||||
}
|
||||
}
|
@ -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<DiscordUser>, 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<WaifuInfo>, 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<WaifuInfo> 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<WaifuInfo> GetTop(int count)
|
||||
{
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
if (count == 0)
|
||||
return new List<WaifuInfo>();
|
||||
|
||||
return _set.Include(wi => wi.Waifu)
|
||||
.Include(wi => wi.Affinity)
|
||||
.Include(wi => wi.Claimer)
|
||||
.OrderByDescending(wi => wi.Price)
|
||||
.Take(count)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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,10 +35,16 @@ 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() =>
|
||||
|
@ -8,13 +8,19 @@ using System.Text.RegularExpressions;
|
||||
using Google.Apis.Urlshortener.v1;
|
||||
using Google.Apis.Urlshortener.v1.Data;
|
||||
using NLog;
|
||||
using Google.Apis.Customsearch.v1;
|
||||
using Google.Apis.Customsearch.v1.Data;
|
||||
|
||||
namespace NadekoBot.Services.Impl
|
||||
{
|
||||
public class GoogleApiService : IGoogleApiService
|
||||
{
|
||||
const string search_engine_id = "018084019232060951019:hs5piey28-e";
|
||||
|
||||
private YouTubeService yt;
|
||||
private UrlshortenerService sh;
|
||||
private CustomsearchService cs;
|
||||
|
||||
private Logger _log { get; }
|
||||
|
||||
public GoogleApiService()
|
||||
@ -22,13 +28,14 @@ namespace NadekoBot.Services.Impl
|
||||
var bcs = new BaseClientService.Initializer
|
||||
{
|
||||
ApplicationName = "Nadeko Bot",
|
||||
ApiKey = NadekoBot.Credentials.GoogleApiKey
|
||||
ApiKey = NadekoBot.Credentials.GoogleApiKey,
|
||||
};
|
||||
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
yt = new YouTubeService(bcs);
|
||||
sh = new UrlshortenerService(bcs);
|
||||
cs = new CustomsearchService(bcs);
|
||||
}
|
||||
public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
|
||||
{
|
||||
@ -179,5 +186,34 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public struct ImageResult
|
||||
{
|
||||
public Result.ImageData Image { get; }
|
||||
public string Link { get; }
|
||||
|
||||
public ImageResult(Result.ImageData image, string link)
|
||||
{
|
||||
this.Image = image;
|
||||
this.Link = link;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ImageResult> GetImageAsync(string query, int start = 1)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
var req = cs.Cse.List(query);
|
||||
req.Cx = search_engine_id;
|
||||
req.Num = 1;
|
||||
req.Fields = "items(image(contextLink,thumbnailLink),link)";
|
||||
req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image;
|
||||
req.Start = start;
|
||||
|
||||
var search = await req.ExecuteAsync().ConfigureAwait(false);
|
||||
|
||||
return new ImageResult(search.Items[0].Image, search.Items[0].Link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl
|
||||
private DiscordShardedClient client;
|
||||
private DateTime started;
|
||||
|
||||
public const string BotVersion = "1.1.3";
|
||||
public const string BotVersion = "1.1.5a";
|
||||
|
||||
public string Author => "Kwoth#2560";
|
||||
public string Library => "Discord.Net";
|
||||
|
@ -103,6 +103,9 @@ namespace NadekoBot.Extensions
|
||||
http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
}
|
||||
|
||||
public static string GetInitials(this string txt, string glue = "") =>
|
||||
string.Join(glue, txt.Split(' ').Select(x => x.FirstOrDefault()));
|
||||
|
||||
public static DateTime ToUnixTimestamp(this double number) => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(number);
|
||||
|
||||
public static EmbedBuilder WithOkColor(this EmbedBuilder eb) =>
|
||||
|
BIN
src/NadekoBot/_libs/32/libsodium.dll
Normal file
BIN
src/NadekoBot/_libs/32/libsodium.dll
Normal file
Binary file not shown.
BIN
src/NadekoBot/_libs/32/opus.dll
Normal file
BIN
src/NadekoBot/_libs/32/opus.dll
Normal file
Binary file not shown.
BIN
src/NadekoBot/_libs/64/libsodium.dll
Normal file
BIN
src/NadekoBot/_libs/64/libsodium.dll
Normal file
Binary file not shown.
BIN
src/NadekoBot/_libs/64/opus.dll
Normal file
BIN
src/NadekoBot/_libs/64/opus.dll
Normal file
Binary file not shown.
@ -237,7 +237,7 @@
|
||||
},
|
||||
{
|
||||
"Title":"Careers in Psychology: Opportunities in a Changing World",
|
||||
"Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelorâs and graduate level."
|
||||
"Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level."
|
||||
},
|
||||
{
|
||||
"Title":"Philosophy of Psychology",
|
||||
|
@ -18,7 +18,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"AngleSharp": "0.9.9",
|
||||
"VideoLibrary": "1.3.4",
|
||||
"libvideo": "1.0.0",
|
||||
"CoreCLR-NCalc": "2.1.2",
|
||||
"Google.Apis.Urlshortener.v1": "1.19.0.138",
|
||||
"Google.Apis.YouTube.v3": "1.20.0.701",
|
||||
|
Loading…
Reference in New Issue
Block a user