Compare commits
5 commits
8ed26e11d3
...
d171b92989
Author | SHA1 | Date | |
---|---|---|---|
d171b92989 | |||
172b1ed5e6 | |||
8f6ecff5af | |||
94aee4ad10 | |||
d910683d78 |
12 changed files with 230 additions and 99 deletions
CHANGELOG.md
src/EllieBot
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -2,6 +2,21 @@
|
||||||
|
|
||||||
*a,c,f,r,o*
|
*a,c,f,r,o*
|
||||||
|
|
||||||
|
## [6.1.2] - 03.04.2025
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed `.feed` not adding new feeds to the database
|
||||||
|
|
||||||
|
## [6.1.1] - 03.04.2025
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added some config options for .conf fish
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed a typo in fish shop
|
||||||
|
- .fishlb will now compare unique fish caught, instead of total catches
|
||||||
|
- hangman category now appears in .hangman output
|
||||||
|
|
||||||
## [6.1.0] - 30.03.2025
|
## [6.1.0] - 30.03.2025
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>true</ImplicitUsings>
|
<ImplicitUsings>true</ImplicitUsings>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
<Version>6.1.0</Version>
|
<Version>6.1.2</Version>
|
||||||
|
|
||||||
<!-- Output/build -->
|
<!-- Output/build -->
|
||||||
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
|
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
|
||||||
|
|
|
@ -15,17 +15,91 @@ public sealed class FishConfigService : ConfigServiceBase<FishConfig>
|
||||||
IPubSub pubSub)
|
IPubSub pubSub)
|
||||||
: base(FILE_PATH, serializer, pubSub, _changeKey)
|
: base(FILE_PATH, serializer, pubSub, _changeKey)
|
||||||
{
|
{
|
||||||
|
AddParsedProp("captcha",
|
||||||
|
static (conf) => conf.RequireCaptcha,
|
||||||
|
bool.TryParse,
|
||||||
|
ConfigPrinters.ToString);
|
||||||
|
|
||||||
|
AddParsedProp("chance.nothing",
|
||||||
|
static (conf) => conf.Chance.Nothing,
|
||||||
|
int.TryParse,
|
||||||
|
ConfigPrinters.ToString);
|
||||||
|
|
||||||
|
AddParsedProp("chance.fish",
|
||||||
|
static (conf) => conf.Chance.Fish,
|
||||||
|
int.TryParse,
|
||||||
|
ConfigPrinters.ToString);
|
||||||
|
|
||||||
|
AddParsedProp("chance.trash",
|
||||||
|
static (conf) => conf.Chance.Trash,
|
||||||
|
int.TryParse,
|
||||||
|
ConfigPrinters.ToString);
|
||||||
|
|
||||||
Migrate();
|
Migrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Migrate()
|
private void Migrate()
|
||||||
{
|
{
|
||||||
if (data.Version < 2)
|
if (data.Version < 11)
|
||||||
{
|
{
|
||||||
ModifyConfig(c =>
|
ModifyConfig(c =>
|
||||||
{
|
{
|
||||||
c.Version = 2;
|
c.Version = 11;
|
||||||
c.RequireCaptcha = true;
|
if (c.Items is { Count: > 0 })
|
||||||
|
return;
|
||||||
|
c.Items =
|
||||||
|
[
|
||||||
|
new FishItem
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
ItemType = FishItemType.Pole,
|
||||||
|
Name = "Wooden Rod",
|
||||||
|
Description = "Better than catching it with bare hands.",
|
||||||
|
Price = 1000,
|
||||||
|
FishMultiplier = 1.2
|
||||||
|
},
|
||||||
|
new FishItem
|
||||||
|
{
|
||||||
|
Id = 11,
|
||||||
|
ItemType = FishItemType.Pole,
|
||||||
|
Name = "Magnet on a Stick",
|
||||||
|
Description = "Attracts all trash, not just metal.",
|
||||||
|
Price = 3000,
|
||||||
|
FishMultiplier = 0.9,
|
||||||
|
TrashMultiplier = 2
|
||||||
|
},
|
||||||
|
new FishItem
|
||||||
|
{
|
||||||
|
Id = 21,
|
||||||
|
ItemType = FishItemType.Bait,
|
||||||
|
Name = "Corn",
|
||||||
|
Description = "Just some cooked corn.",
|
||||||
|
Price = 100,
|
||||||
|
Uses = 100,
|
||||||
|
RareMultiplier = 1.1
|
||||||
|
},
|
||||||
|
new FishItem
|
||||||
|
{
|
||||||
|
Id = 31,
|
||||||
|
ItemType = FishItemType.Potion,
|
||||||
|
Name = "A Cup of Tea",
|
||||||
|
Description = "Helps you focus.",
|
||||||
|
Price = 12000,
|
||||||
|
DurationMinutes = 30,
|
||||||
|
MaxStarMultiplier = 1.1,
|
||||||
|
FishingSpeedMultiplier = 1.01
|
||||||
|
},
|
||||||
|
new FishItem
|
||||||
|
{
|
||||||
|
Id = 41,
|
||||||
|
ItemType = FishItemType.Boat,
|
||||||
|
Name = "Canoe",
|
||||||
|
Description = "Lets you fish a little faster.",
|
||||||
|
Price = 3000,
|
||||||
|
FishingSpeedMultiplier = 1.201,
|
||||||
|
MaxStarMultiplier = 1.1
|
||||||
|
}
|
||||||
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public sealed class DefaultHangmanSource : IHangmanSource
|
||||||
public IReadOnlyCollection<string> GetCategories()
|
public IReadOnlyCollection<string> GetCategories()
|
||||||
=> termsDict.Keys.ToList();
|
=> termsDict.Keys.ToList();
|
||||||
|
|
||||||
public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term)
|
public bool GetTerm(string? category, [NotNullWhen(true)] out (HangmanTerm Term, string Category)? term)
|
||||||
{
|
{
|
||||||
if (category is null)
|
if (category is null)
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ public sealed class DefaultHangmanSource : IHangmanSource
|
||||||
|
|
||||||
if (termsDict.TryGetValue(category, out var terms))
|
if (termsDict.TryGetValue(category, out var terms))
|
||||||
{
|
{
|
||||||
term = terms[_rng.Next(0, terms.Length)];
|
term = (terms[_rng.Next(0, terms.Length)], category);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@ public partial class Games
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Hangmanlist()
|
public async Task Hangmanlist()
|
||||||
=> await Response().Confirm(GetText(strs.hangman_types(prefix)), _service.GetHangmanTypes().Join('\n'))
|
=> await Response()
|
||||||
|
.Confirm(GetText(strs.hangman_types(prefix)), _service.GetHangmanTypes().Join('\n'))
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
|
|
||||||
private static string Draw(HangmanGame.State state)
|
private static string Draw(HangmanGame.State state)
|
||||||
|
@ -35,29 +36,25 @@ public partial class Games
|
||||||
|
|
||||||
public static EmbedBuilder GetEmbed(IMessageSenderService sender, HangmanGame.State state)
|
public static EmbedBuilder GetEmbed(IMessageSenderService sender, HangmanGame.State state)
|
||||||
{
|
{
|
||||||
|
var eb = sender.CreateEmbed()
|
||||||
|
.WithOkColor()
|
||||||
|
.AddField("Hangman", Draw(state))
|
||||||
|
.AddField("Guess", Format.Code(state.Word));
|
||||||
|
|
||||||
if (state.Phase == HangmanGame.Phase.Running)
|
if (state.Phase == HangmanGame.Phase.Running)
|
||||||
{
|
{
|
||||||
return sender.CreateEmbed()
|
return eb
|
||||||
.WithOkColor()
|
.WithFooter(state.MissedLetters.Join(' '))
|
||||||
.AddField("Hangman", Draw(state))
|
.WithAuthor(state.Category);
|
||||||
.AddField("Guess", Format.Code(state.Word))
|
|
||||||
.WithFooter(state.MissedLetters.Join(' '));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.Phase == HangmanGame.Phase.Ended && state.Failed)
|
if (state.Phase == HangmanGame.Phase.Ended && state.Failed)
|
||||||
{
|
{
|
||||||
return sender.CreateEmbed()
|
return eb
|
||||||
.WithErrorColor()
|
|
||||||
.AddField("Hangman", Draw(state))
|
|
||||||
.AddField("Guess", Format.Code(state.Word))
|
|
||||||
.WithFooter(state.MissedLetters.Join(' '));
|
.WithFooter(state.MissedLetters.Join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sender.CreateEmbed()
|
return eb.WithFooter(state.MissedLetters.Join(' '));
|
||||||
.WithOkColor()
|
|
||||||
.AddField("Hangman", Draw(state))
|
|
||||||
.AddField("Guess", Format.Code(state.Word))
|
|
||||||
.WithFooter(state.MissedLetters.Join(' '));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
|
|
@ -4,9 +4,20 @@ namespace EllieBot.Modules.Games.Hangman;
|
||||||
|
|
||||||
public sealed class HangmanGame
|
public sealed class HangmanGame
|
||||||
{
|
{
|
||||||
public enum GuessResult { NoAction, AlreadyTried, Incorrect, Guess, Win }
|
public enum GuessResult
|
||||||
|
{
|
||||||
|
NoAction,
|
||||||
|
AlreadyTried,
|
||||||
|
Incorrect,
|
||||||
|
Guess,
|
||||||
|
Win
|
||||||
|
}
|
||||||
|
|
||||||
public enum Phase { Running, Ended }
|
public enum Phase
|
||||||
|
{
|
||||||
|
Running,
|
||||||
|
Ended
|
||||||
|
}
|
||||||
|
|
||||||
private Phase CurrentPhase { get; set; }
|
private Phase CurrentPhase { get; set; }
|
||||||
|
|
||||||
|
@ -17,16 +28,21 @@ public sealed class HangmanGame
|
||||||
private readonly string _word;
|
private readonly string _word;
|
||||||
private readonly string _imageUrl;
|
private readonly string _imageUrl;
|
||||||
|
|
||||||
public HangmanGame(HangmanTerm term)
|
public string Category { get; }
|
||||||
|
|
||||||
|
public HangmanGame(HangmanTerm term, string cat)
|
||||||
{
|
{
|
||||||
_word = term.Word;
|
_word = term.Word;
|
||||||
_imageUrl = term.ImageUrl;
|
_imageUrl = term.ImageUrl;
|
||||||
|
Category = cat;
|
||||||
|
|
||||||
_remaining = _word.ToLowerInvariant().Where(x => char.IsLetter(x)).Select(char.ToLowerInvariant).ToHashSet();
|
_remaining = _word.ToLowerInvariant().Where(x => char.IsLetter(x)).Select(char.ToLowerInvariant).ToHashSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public State GetState(GuessResult guessResult = GuessResult.NoAction)
|
public State GetState(GuessResult guessResult = GuessResult.NoAction)
|
||||||
=> new(_incorrect.Count,
|
=> new(
|
||||||
|
Category,
|
||||||
|
_incorrect.Count,
|
||||||
CurrentPhase,
|
CurrentPhase,
|
||||||
CurrentPhase == Phase.Ended ? _word : GetScrambledWord(),
|
CurrentPhase == Phase.Ended ? _word : GetScrambledWord(),
|
||||||
guessResult,
|
guessResult,
|
||||||
|
@ -99,6 +115,7 @@ public sealed class HangmanGame
|
||||||
}
|
}
|
||||||
|
|
||||||
public record State(
|
public record State(
|
||||||
|
string Category,
|
||||||
int Errors,
|
int Errors,
|
||||||
Phase Phase,
|
Phase Phase,
|
||||||
string Word,
|
string Word,
|
||||||
|
|
|
@ -36,10 +36,10 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
|
||||||
public bool StartHangman(ulong channelId, string? category, [NotNullWhen(true)] out HangmanGame.State? state)
|
public bool StartHangman(ulong channelId, string? category, [NotNullWhen(true)] out HangmanGame.State? state)
|
||||||
{
|
{
|
||||||
state = null;
|
state = null;
|
||||||
if (!_source.GetTerm(category, out var term))
|
if (!_source.GetTerm(category, out var termData))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var game = new HangmanGame(term);
|
var game = new HangmanGame(termData.Value.Term, termData.Value.Category);
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
var hc = _hangmanGames.GetOrAdd(channelId, game);
|
var hc = _hangmanGames.GetOrAdd(channelId, game);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
namespace EllieBot.Modules.Games.Hangman;
|
namespace EllieBot.Modules.Games.Hangman;
|
||||||
|
|
||||||
public sealed class HangmanTerm
|
public sealed class HangmanTerm
|
||||||
|
|
|
@ -6,5 +6,5 @@ public interface IHangmanSource : IEService
|
||||||
{
|
{
|
||||||
public IReadOnlyCollection<string> GetCategories();
|
public IReadOnlyCollection<string> GetCategories();
|
||||||
public void Reload();
|
public void Reload();
|
||||||
public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term);
|
public bool GetTerm(string? category, [NotNullWhen(true)] out (HangmanTerm Term, string Category)? term);
|
||||||
}
|
}
|
|
@ -53,6 +53,8 @@ public partial class Searches
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async Task Feed(string url, ITextChannel? channel = null, [Leftover] string? message = null)
|
public async Task Feed(string url, ITextChannel? channel = null, [Leftover] string? message = null)
|
||||||
{
|
{
|
||||||
|
await ctx.Channel.TriggerTypingAsync();
|
||||||
|
|
||||||
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)
|
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)
|
||||||
|| (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
|
|| (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
|
||||||
{
|
{
|
||||||
|
@ -61,7 +63,7 @@ public partial class Searches
|
||||||
}
|
}
|
||||||
|
|
||||||
channel ??= (ITextChannel)ctx.Channel;
|
channel ??= (ITextChannel)ctx.Channel;
|
||||||
|
|
||||||
if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone)
|
if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone)
|
||||||
message = message?.SanitizeAllMentions();
|
message = message?.SanitizeAllMentions();
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ public partial class Searches
|
||||||
if (ctx.User is not IGuildUser gu || !gu.GuildPermissions.Administrator)
|
if (ctx.User is not IGuildUser gu || !gu.GuildPermissions.Administrator)
|
||||||
message = message?.SanitizeMentions(true);
|
message = message?.SanitizeMentions(true);
|
||||||
|
|
||||||
var result = _service.AddFeed(ctx.Guild.Id, channel.Id, url, message);
|
var result = await _service.AddFeedAsync(ctx.Guild.Id, channel.Id, url, message);
|
||||||
if (result == FeedAddResult.Success)
|
if (result == FeedAddResult.Success)
|
||||||
{
|
{
|
||||||
await Response().Confirm(strs.feed_added).SendAsync();
|
await Response().Confirm(strs.feed_added).SendAsync();
|
||||||
|
@ -117,32 +119,32 @@ public partial class Searches
|
||||||
{
|
{
|
||||||
if (--page < 0)
|
if (--page < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var feeds = _service.GetFeeds(ctx.Guild.Id);
|
var feeds = _service.GetFeeds(ctx.Guild.Id);
|
||||||
|
|
||||||
if (!feeds.Any())
|
if (!feeds.Any())
|
||||||
{
|
{
|
||||||
await Response()
|
await Response()
|
||||||
.Embed(CreateEmbed().WithOkColor().WithDescription(GetText(strs.feed_no_feed)))
|
.Embed(CreateEmbed().WithOkColor().WithDescription(GetText(strs.feed_no_feed)))
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Response()
|
await Response()
|
||||||
.Paginated()
|
.Paginated()
|
||||||
.Items(feeds)
|
.Items(feeds)
|
||||||
.PageSize(10)
|
.PageSize(10)
|
||||||
.CurrentPage(page)
|
.CurrentPage(page)
|
||||||
.Page((items, cur) =>
|
.Page((items, cur) =>
|
||||||
{
|
{
|
||||||
var embed = CreateEmbed().WithOkColor();
|
var embed = CreateEmbed().WithOkColor();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var fs = string.Join("\n",
|
var fs = string.Join("\n",
|
||||||
items.Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}"));
|
items.Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}"));
|
||||||
|
|
||||||
return embed.WithDescription(fs);
|
return embed.WithDescription(fs);
|
||||||
})
|
})
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,13 +40,13 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
await using (var uow = _db.GetDbContext())
|
await using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
var subs = await uow.Set<FeedSub>()
|
var subs = await uow.Set<FeedSub>()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
|
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
|
||||||
.ToListAsyncLinqToDB();
|
.ToListAsyncLinqToDB();
|
||||||
_subs = subs
|
_subs = subs
|
||||||
.GroupBy(x => x.Url.ToLower())
|
.GroupBy(x => x.Url.ToLower())
|
||||||
.ToDictionary(x => x.Key, x => x.ToList())
|
.ToDictionary(x => x.Key, x => x.ToList())
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
await TrackFeeds();
|
await TrackFeeds();
|
||||||
|
@ -66,7 +66,7 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
// remove from db
|
// remove from db
|
||||||
await using var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
await ctx.GetTable<FeedSub>()
|
await ctx.GetTable<FeedSub>()
|
||||||
.DeleteAsync(x => ids.Contains(x.Id));
|
.DeleteAsync(x => ids.Contains(x.Id));
|
||||||
|
|
||||||
// remove from the local cache
|
// remove from the local cache
|
||||||
_subs.TryRemove(url, out _);
|
_subs.TryRemove(url, out _);
|
||||||
|
@ -163,12 +163,12 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
if (!gotImage && feedItem.SpecificItem is AtomFeedItem afi)
|
if (!gotImage && feedItem.SpecificItem is AtomFeedItem afi)
|
||||||
{
|
{
|
||||||
var previewElement = afi.Element.Elements()
|
var previewElement = afi.Element.Elements()
|
||||||
.FirstOrDefault(x => x.Name.LocalName == "preview");
|
.FirstOrDefault(x => x.Name.LocalName == "preview");
|
||||||
|
|
||||||
if (previewElement is null)
|
if (previewElement is null)
|
||||||
{
|
{
|
||||||
previewElement = afi.Element.Elements()
|
previewElement = afi.Element.Elements()
|
||||||
.FirstOrDefault(x => x.Name.LocalName == "thumbnail");
|
.FirstOrDefault(x => x.Name.LocalName == "thumbnail");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previewElement is not null)
|
if (previewElement is not null)
|
||||||
|
@ -201,11 +201,11 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var sendTask = _sender.Response(ch)
|
var sendTask = _sender.Response(ch)
|
||||||
.Embed(embed)
|
.Embed(embed)
|
||||||
.Text(string.IsNullOrWhiteSpace(val.Message)
|
.Text(string.IsNullOrWhiteSpace(val.Message)
|
||||||
? string.Empty
|
? string.Empty
|
||||||
: val.Message)
|
: val.Message)
|
||||||
.SendAsync();
|
.SendAsync();
|
||||||
tasks.Add(sendTask);
|
tasks.Add(sendTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,12 +236,14 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
|
|
||||||
return uow.GetTable<FeedSub>()
|
return uow.GetTable<FeedSub>()
|
||||||
.Where(x => x.GuildId == guildId)
|
.Where(x => x.GuildId == guildId)
|
||||||
.OrderBy(x => x.Id)
|
.OrderBy(x => x.Id)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedAddResult AddFeed(
|
private const int MAX_FEEDS = 10;
|
||||||
|
|
||||||
|
public async Task<FeedAddResult> AddFeedAsync(
|
||||||
ulong guildId,
|
ulong guildId,
|
||||||
ulong channelId,
|
ulong channelId,
|
||||||
string rssFeed,
|
string rssFeed,
|
||||||
|
@ -249,25 +251,24 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed));
|
ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed));
|
||||||
|
|
||||||
var fs = new FeedSub
|
await using var uow = _db.GetDbContext();
|
||||||
{
|
var feedUrl = rssFeed.Trim();
|
||||||
ChannelId = channelId,
|
if (await uow.GetTable<FeedSub>().AnyAsyncLinqToDB(x => x.GuildId == guildId &&
|
||||||
Url = rssFeed.Trim(),
|
x.Url.ToLower() == feedUrl.ToLower()))
|
||||||
Message = message
|
|
||||||
};
|
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
var feeds = uow.GetTable<FeedSub>()
|
|
||||||
.Where(x => x.GuildId == guildId)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if (feeds.Any(x => x.Url.ToLower() == fs.Url.ToLower()))
|
|
||||||
return FeedAddResult.Duplicate;
|
return FeedAddResult.Duplicate;
|
||||||
if (feeds.Length >= 10)
|
|
||||||
|
var count = await uow.GetTable<FeedSub>().CountAsyncLinqToDB(x => x.GuildId == guildId);
|
||||||
|
if (count >= MAX_FEEDS)
|
||||||
return FeedAddResult.LimitReached;
|
return FeedAddResult.LimitReached;
|
||||||
|
|
||||||
uow.Add(fs);
|
var fs = await uow.GetTable<FeedSub>()
|
||||||
uow.SaveChanges();
|
.InsertWithOutputAsync(() => new FeedSub
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
ChannelId = channelId,
|
||||||
|
Url = feedUrl,
|
||||||
|
Message = message,
|
||||||
|
});
|
||||||
|
|
||||||
_subs.AddOrUpdate(fs.Url.ToLower(),
|
_subs.AddOrUpdate(fs.Url.ToLower(),
|
||||||
[fs],
|
[fs],
|
||||||
|
@ -293,10 +294,7 @@ public class FeedsService : IEService, IReadyExecutor
|
||||||
var toRemove = items[index];
|
var toRemove = items[index];
|
||||||
_subs.AddOrUpdate(toRemove.Url.ToLower(),
|
_subs.AddOrUpdate(toRemove.Url.ToLower(),
|
||||||
[],
|
[],
|
||||||
(_, old) =>
|
(_, old) => { return old.Where(x => x.Id != toRemove.Id).ToList(); });
|
||||||
{
|
|
||||||
return old.Where(x => x.Id != toRemove.Id).ToList();
|
|
||||||
});
|
|
||||||
uow.Remove(toRemove);
|
uow.Remove(toRemove);
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# DO NOT CHANGE
|
# DO NOT CHANGE
|
||||||
version: 2
|
version: 11
|
||||||
weatherSeed: w%29';^eGE)9oWHM(aI9I;%1[.r^z2ZS7ShV,l')o(e%#"hVzb>oxQq^`.&/7srh
|
weatherSeed: w%29';^eGE)9oWHM(aI9I;%1[.r^z2ZS7ShV,l')o(e%#"hVzb>oxQq^`.&/7srh
|
||||||
requireCaptcha: true
|
requireCaptcha: true
|
||||||
starEmojis:
|
starEmojis:
|
||||||
|
@ -45,40 +45,66 @@ trash:
|
||||||
items:
|
items:
|
||||||
- id: 1
|
- id: 1
|
||||||
itemType: Pole
|
itemType: Pole
|
||||||
name: "Wooden Rod"
|
name: Wooden Rod
|
||||||
description: "Better than catching it with bare hands."
|
emoji: ''
|
||||||
|
description: Better than catching it with bare hands.
|
||||||
price: 1000
|
price: 1000
|
||||||
|
uses:
|
||||||
|
durationMinutes:
|
||||||
fishMultiplier: 1.2
|
fishMultiplier: 1.2
|
||||||
|
trashMultiplier:
|
||||||
|
maxStarMultiplier:
|
||||||
|
rareMultiplier:
|
||||||
|
fishingSpeedMultiplier:
|
||||||
- id: 11
|
- id: 11
|
||||||
itemType: Pole
|
itemType: Pole
|
||||||
name: Magnet on a Stick
|
name: Magnet on a Stick
|
||||||
description: "Attracts all trash, not just metal."
|
emoji: ''
|
||||||
|
description: Attracts all trash, not just metal.
|
||||||
price: 3000
|
price: 3000
|
||||||
|
uses:
|
||||||
|
durationMinutes:
|
||||||
fishMultiplier: 0.9
|
fishMultiplier: 0.9
|
||||||
trashMultiplier: 2
|
trashMultiplier: 2
|
||||||
|
maxStarMultiplier:
|
||||||
|
rareMultiplier:
|
||||||
|
fishingSpeedMultiplier:
|
||||||
- id: 21
|
- id: 21
|
||||||
itemType: Bait
|
itemType: Bait
|
||||||
name: "Corn"
|
name: Corn
|
||||||
description: "Just some cooked corn."
|
emoji: ''
|
||||||
|
description: Just some cooked corn.
|
||||||
price: 100
|
price: 100
|
||||||
uses: 100
|
uses: 100
|
||||||
|
durationMinutes:
|
||||||
|
fishMultiplier:
|
||||||
|
trashMultiplier:
|
||||||
|
maxStarMultiplier:
|
||||||
rareMultiplier: 1.1
|
rareMultiplier: 1.1
|
||||||
|
fishingSpeedMultiplier:
|
||||||
- id: 31
|
- id: 31
|
||||||
itemType: Potion
|
itemType: Potion
|
||||||
name: "A Cup of Tea"
|
name: A Cup of Tea
|
||||||
description: "Helps you focus."
|
emoji: ''
|
||||||
|
description: Helps you focus.
|
||||||
price: 12000
|
price: 12000
|
||||||
|
uses:
|
||||||
durationMinutes: 30
|
durationMinutes: 30
|
||||||
|
fishMultiplier:
|
||||||
|
trashMultiplier:
|
||||||
maxStarMultiplier: 1.1
|
maxStarMultiplier: 1.1
|
||||||
|
rareMultiplier:
|
||||||
fishingSpeedMultiplier: 1.01
|
fishingSpeedMultiplier: 1.01
|
||||||
|
|
||||||
- id: 41
|
- id: 41
|
||||||
itemType: Boat
|
itemType: Boat
|
||||||
name: "Canoe"
|
name: Canoe
|
||||||
description: "Lets you fish a little faster."
|
emoji: ''
|
||||||
|
description: Lets you fish a little faster.
|
||||||
price: 3000
|
price: 3000
|
||||||
|
uses:
|
||||||
|
durationMinutes:
|
||||||
|
fishMultiplier:
|
||||||
|
trashMultiplier:
|
||||||
|
maxStarMultiplier: 1.1
|
||||||
|
rareMultiplier:
|
||||||
fishingSpeedMultiplier: 1.201
|
fishingSpeedMultiplier: 1.201
|
||||||
maxStarMultiplier: 1.1
|
|
Loading…
Add table
Add a link
Reference in a new issue