chaosbot/ChaosBot/Discord/Services/ExperienceHandler.cs

118 lines
4.6 KiB
C#

using System;
using System.Linq;
using System.Reflection;
using System.Threading.Channels;
using System.Threading.Tasks;
using ChaosBot.Models;
using ChaosBot.Repositories;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using NLog;
namespace ChaosBot.Discord.Services
{
public class ExperienceHandler
{
private static readonly ILogger _logger = Program.Logger;
public static async void AddXp(SocketCommandContext context)
{
try
{
using (ChaosbotContext dbContext = new ChaosbotContext())
{
IQueryable<Experience> ctxUser = dbContext.ExperiencePoints;
IQueryable<Experience> usrXp = ctxUser
.Where(p => p.DiscordGuildId.Equals(context.Guild.Id))
.Where(p => p.DiscordUserId.Equals(context.User.Id));
Experience usrNewXp;
// Ensure there's an entry in the database, even if this is the first message ever sent
if (!usrXp.Any())
{
usrNewXp = new Experience
{
Amount = 0,
DiscordGuildId = context.Guild.Id,
DiscordUserId = context.User.Id,
LastUpdated = DateTime.UnixEpoch,
Level = 0
};
await dbContext.ExperiencePoints.Upsert(usrNewXp)
.On(x => new {x.DiscordGuildId, x.DiscordUserId}).RunAsync();
}
else
{
usrNewXp = usrXp.First();
}
// We want to throttle gaining experience
if (DateTime.Now < usrNewXp.LastUpdated.AddMinutes(1)) return;
usrNewXp.LastUpdated = DateTime.Now;
usrNewXp.Amount += Convert.ToUInt64(new Random().Next(15, 26));
ulong oldLevel = usrNewXp.Level;
ulong newLevel = CheckLevel(usrNewXp);
if (newLevel > oldLevel)
usrNewXp.Level = newLevel;
await dbContext.ExperiencePoints.Upsert(usrNewXp)
.On(x => new {x.DiscordGuildId, x.DiscordUserId}).RunAsync();
if (newLevel > oldLevel)
{
// The user has leveled up, we can send a message
string channelToSendIn =
ConfigurationRepository.GetValue<string>("LevelUp:Channel", context.Guild.Id, "false");
string mentionString = $"<@{context.User.Id}>";
if (!ConfigurationRepository.GetValue<bool>("LevelUp:MentionUser", context.Guild.Id, true))
{
mentionString = context.User.Username;
if (context.User is IGuildUser guildUser)
{
mentionString = guildUser.Nickname ?? mentionString;
}
}
ISocketMessageChannel messageChannel;
if (channelToSendIn != "false")
{
ulong channelId = Convert.ToUInt64(channelToSendIn.Substring(2, channelToSendIn.Length - 3));
messageChannel = context.Guild.GetTextChannel(channelId);
}
else
{
messageChannel = context.Channel;
}
await messageChannel.SendMessageAsync(
$"Grats {mentionString}! You have reached level {newLevel}! <:wot:740387232514572310>");
}
}
}
catch (Exception ex)
{
_logger.Error(
$"{MethodBase.GetCurrentMethod().ReflectedType.FullName}: Exception [{ex}] thrown, <[{ex.Message}]>.");
}
}
private static ulong CheckLevel(Experience usrExperience)
{
ulong curLevel = usrExperience.Level;
ulong curXP = usrExperience.Amount;
var nextLevelXP = 5 * usrExperience.Level ^ 3 + 95 * usrExperience.Level;
if (curXP > nextLevelXP)
return curLevel + 1;
return curLevel;
}
}
}