elliebot/src/EllieBot/Modules/Games/Fish/FishCommands.cs

279 lines
8.7 KiB
C#
Raw Normal View History

using System.ComponentModel.DataAnnotations;
using System.Text;
using EllieBot.Modules.Games.Fish;
2025-01-14 19:03:59 +13:00
using Format = Discord.Format;
namespace EllieBot.Modules.Games;
public partial class Games
{
public class FishCommands(
FishService fs,
FishConfigService fcs,
IBotCache cache,
CaptchaService captchaService) : EllieModule
2025-01-14 19:03:59 +13:00
{
private static readonly EllieRandom _rng = new();
2025-01-14 19:03:59 +13:00
private TypedKey<bool> FishingWhitelistKey(ulong userId)
=> new($"fishingwhitelist:{userId}");
[Cmd]
public async Task Fish()
{
var cRes = await cache.GetAsync(FishingWhitelistKey(ctx.User.Id));
if (cRes.TryPickT1(out _, out _))
{
string? password = null;
if (fcs.Data.RequireCaptcha)
password = await captchaService.GetUserCaptcha(ctx.User.Id);
if (password is not null)
2025-01-14 19:03:59 +13:00
{
var img = captchaService.GetPasswordImage(password);
using var stream = await img.ToStreamAsync();
var toSend = Response()
.File(stream, "timely.png");
#if GLOBAL_ELLIE
if (_rng.Next(0, 8) == 0)
toSend = toSend
.Text("*[Sub on Patreon](https://patreon.com/elliebot) to remove captcha.*");
#endif
var captcha = await toSend.SendAsync();
try
2025-01-14 19:03:59 +13:00
{
var userInput = await GetUserInputAsync(ctx.User.Id, ctx.Channel.Id);
if (userInput?.ToLowerInvariant() != password?.ToLowerInvariant())
{
return;
}
// whitelist the user for 30 minutes
await cache.AddAsync(FishingWhitelistKey(ctx.User.Id), true, TimeSpan.FromMinutes(30));
// reset the password
await captchaService.ClearUserCaptcha(ctx.User.Id);
}
finally
{
_ = captcha.DeleteAsync();
2025-01-14 19:03:59 +13:00
}
}
}
var fishResult = await fs.FishAsync(ctx.User.Id, ctx.Channel.Id);
if (fishResult.TryPickT1(out _, out var fishTask))
{
return;
}
var currentWeather = fs.GetCurrentWeather();
var currentTod = fs.GetTime();
var spot = fs.GetSpot(ctx.Channel.Id);
var msg = await Response()
.Embed(CreateEmbed()
.WithPendingColor()
.WithAuthor(ctx.User)
.WithDescription(GetText(strs.fish_waiting))
.AddField(GetText(strs.fish_spot), GetSpotEmoji(spot) + " " + spot.ToString(), true)
.AddField(GetText(strs.fish_weather),
GetWeatherEmoji(currentWeather) + " " + currentWeather,
true)
.AddField(GetText(strs.fish_tod), GetTodEmoji(currentTod) + " " + currentTod, true))
.SendAsync();
2025-01-14 19:03:59 +13:00
var res = await fishTask;
if (res is null)
{
await Response().Error(strs.fish_nothing).SendAsync();
return;
}
var desc = GetText(strs.fish_caught(res.Fish.Emoji + " " + Format.Bold(res.Fish.Name)));
if (res.IsSkillUp)
{
desc += "\n" + GetText(strs.fish_skill_up(res.Skill, res.MaxSkill));
}
2025-01-14 19:03:59 +13:00
await Response()
.Embed(CreateEmbed()
.WithOkColor()
.WithAuthor(ctx.User)
.WithDescription(desc)
.AddField(GetText(strs.fish_quality), GetStarText(res.Stars, res.Fish.Stars), true)
.AddField(GetText(strs.desc), res.Fish.Fluff, true)
.WithThumbnailUrl(res.Fish.Image))
.SendAsync();
2025-01-14 19:03:59 +13:00
await msg.DeleteAsync();
}
[Cmd]
public async Task FishSpot()
{
var ws = fs.GetWeatherForPeriods(7);
var spot = fs.GetSpot(ctx.Channel.Id);
var time = fs.GetTime();
await Response()
.Embed(CreateEmbed()
.WithOkColor()
.WithDescription(GetText(strs.fish_weather_duration(fs.GetWeatherPeriodDuration())))
.AddField(GetText(strs.fish_spot), GetSpotEmoji(spot) + " " + spot, true)
.AddField(GetText(strs.fish_tod), GetTodEmoji(time) + " " + time, true)
.AddField(GetText(strs.fish_weather_forecast),
ws.Select(x => GetWeatherEmoji(x)).Join(""),
true))
.SendAsync();
2025-01-14 19:03:59 +13:00
}
[Cmd]
public async Task Fishlist(int page = 1)
{
if (--page < 0)
return;
var fishes = await fs.GetAllFish();
var catches = await fs.GetUserCatches(ctx.User.Id);
var (skill, maxSkill) = await fs.GetSkill(ctx.User.Id);
2025-01-14 19:03:59 +13:00
var catchDict = catches.ToDictionary(x => x.FishId, x => x);
await Response()
.Paginated()
.Items(fishes)
.PageSize(9)
.CurrentPage(page)
.Page((fs, i) =>
{
var eb = CreateEmbed()
.WithDescription($"🧠 **Skill:** {skill} / {maxSkill}")
.WithAuthor(ctx.User)
.WithTitle(GetText(strs.fish_list_title))
.WithOkColor();
foreach (var f in fs)
{
if (catchDict.TryGetValue(f.Id, out var c))
{
eb.AddField(f.Name,
GetFishEmoji(f, c.Count)
+ " "
+ GetSpotEmoji(f.Spot)
+ GetTodEmoji(f.Time)
+ GetWeatherEmoji(f.Weather)
+ "\n"
+ GetStarText(c.MaxStars, f.Stars)
+ "\n"
+ Format.Italics(f.Fluff),
true);
}
else
{
eb.AddField("?", GetFishEmoji(null, 0) + "\n" + GetStarText(0, f.Stars), true);
}
}
return eb;
})
.SendAsync();
2025-01-14 19:03:59 +13:00
}
private string GetFishEmoji(FishData? fish, int count)
{
if (fish is null)
return "";
return fish.Emoji + " x" + count;
}
private string GetSpotEmoji(FishingSpot? spot)
{
if (spot is not FishingSpot fs)
return string.Empty;
var conf = fcs.Data;
return conf.SpotEmojis[(int)fs];
}
private string GetTodEmoji(FishingTime? fishTod)
{
return fishTod switch
{
FishingTime.Night => "🌑",
FishingTime.Dawn => "🌅",
FishingTime.Dusk => "🌆",
FishingTime.Day => "☀️",
_ => ""
};
}
private string GetWeatherEmoji(FishingWeather? w)
=> w switch
{
FishingWeather.Rain => "🌧️",
FishingWeather.Snow => "❄️",
FishingWeather.Storm => "⛈️",
FishingWeather.Clear => "☀️",
_ => ""
};
private string GetStarText(int resStars, int fishStars)
{
if (resStars == fishStars)
{
return MultiplyStars(fcs.Data.StarEmojis[^1], fishStars);
}
var c = fcs.Data;
var starsp1 = MultiplyStars(c.StarEmojis[resStars], resStars);
var starsp2 = MultiplyStars(c.StarEmojis[0], fishStars - resStars);
return starsp1 + starsp2;
}
private string MultiplyStars(string starEmoji, int count)
{
var sb = new StringBuilder();
for (var i = 0; i < count; i++)
{
sb.Append(starEmoji);
}
return sb.ToString();
}
}
}
public enum FishingSpot
{
Ocean,
River,
Lake,
Swamp,
Reef
}
public enum FishingTime
{
Night,
Dawn,
Day,
Dusk
}
public enum FishingWeather
{
Clear,
Rain,
Storm,
Snow
}