NadekoBot/NadekoBot.Core/Modules/Gambling/WaifuClaimCommands.cs

617 lines
25 KiB
C#

using Discord;
using Discord.Commands;
using NadekoBot.Extensions;
using NadekoBot.Core.Services;
using NadekoBot.Core.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Common;
using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Gambling.Services;
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 : NadekoSubmodule<WaifuService>
{
enum WaifuClaimResult
{
Success,
NotEnoughFunds,
InsufficientAmount
}
public WaifuClaimCommands(IBotConfigProvider bc, CurrencyService cs, DbService db)
{
_bc = bc;
_cs = cs;
_db = db;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task WaifuClaim(int amount, [Remainder]IUser target)
{
if (amount < 50)
{
await ReplyErrorLocalized("waifu_isnt_cheap", 50 + _bc.BotConfig.CurrencySign).ConfigureAwait(false);
return;
}
if (target.Id == Context.User.Id)
{
await ReplyErrorLocalized("waifu_not_yourself").ConfigureAwait(false);
return;
}
WaifuClaimResult result;
WaifuInfo w;
bool isAffinity;
using (var uow = _db.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 _cs.RemoveAsync(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 _cs.RemoveAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false))
{
result = WaifuClaimResult.NotEnoughFunds;
}
else
{
var oldClaimer = w.Claimer;
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
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 _cs.RemoveAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false))
{
result = WaifuClaimResult.NotEnoughFunds;
}
else
{
var oldClaimer = w.Claimer;
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
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 ReplyErrorLocalized("waifu_not_enough", Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))).ConfigureAwait(false);
return;
}
if (result == WaifuClaimResult.NotEnoughFunds)
{
await ReplyErrorLocalized("not_enough", _bc.BotConfig.CurrencySign).ConfigureAwait(false);
return;
}
var msg = GetText("waifu_claimed",
Format.Bold(target.ToString()),
amount + _bc.BotConfig.CurrencySign);
if (w.Affinity?.UserId == Context.User.Id)
msg += "\n" + GetText("waifu_fulfilled", target, w.Price + _bc.BotConfig.CurrencySign);
else
msg = " " + msg;
await Context.Channel.SendConfirmAsync(Context.User.Mention + 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)]
[Priority(0)]
public Task Divorce([Remainder]IGuildUser target) => Divorce(target.Id);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[Priority(1)]
public async Task Divorce([Remainder]ulong targetId)
{
if (targetId == Context.User.Id)
return;
DivorceResult result;
var difference = TimeSpan.Zero;
var amount = 0;
WaifuInfo w = null;
using (var uow = _db.UnitOfWork)
{
w = uow.Waifus.ByWaifuUserId(targetId);
var now = DateTime.UtcNow;
if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id)
result = DivorceResult.NotYourWife;
else if (_service.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 _cs.AddAsync(w.Waifu.UserId, "Waifu Compensation", amount, uow).ConfigureAwait(false);
w.Price = (int)Math.Floor(w.Price * 0.75f);
result = DivorceResult.SucessWithPenalty;
}
else
{
await _cs.AddAsync(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 ReplyConfirmLocalized("waifu_divorced_like", Format.Bold(w.Waifu.ToString()), amount + _bc.BotConfig.CurrencySign).ConfigureAwait(false);
}
else if (result == DivorceResult.Success)
{
await ReplyConfirmLocalized("waifu_divorced_notlike", amount + _bc.BotConfig.CurrencySign).ConfigureAwait(false);
}
else if (result == DivorceResult.NotYourWife)
{
await ReplyErrorLocalized("waifu_not_yours").ConfigureAwait(false);
}
else
{
var remaining = _divorceLimit.Subtract(difference);
await ReplyErrorLocalized("waifu_recent_divorce",
Format.Bold(((int)remaining.TotalHours).ToString()),
Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false);
}
}
private static readonly TimeSpan _affinityLimit = TimeSpan.FromMinutes(30);
private readonly IBotConfigProvider _bc;
private readonly CurrencyService _cs;
private readonly DbService _db;
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task WaifuClaimerAffinity([Remainder]IGuildUser u = null)
{
if (u?.Id == Context.User.Id)
{
await ReplyErrorLocalized("waifu_egomaniac").ConfigureAwait(false);
return;
}
DiscordUser oldAff = null;
var sucess = false;
var cooldown = false;
var difference = TimeSpan.Zero;
using (var uow = _db.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)
{
}
else if (_service.AffinityCooldowns.AddOrUpdate(Context.User.Id,
now,
(key, old) => ((difference = now.Subtract(old)) > _affinityLimit) ? now : old) != now)
{
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 ReplyErrorLocalized("waifu_affinity_cooldown",
Format.Bold(((int)remaining.TotalHours).ToString()),
Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false);
}
else
{
await ReplyErrorLocalized("waifu_affinity_already").ConfigureAwait(false);
}
return;
}
if (u == null)
{
await ReplyConfirmLocalized("waifu_affinity_reset").ConfigureAwait(false);
}
else if (oldAff == null)
{
await ReplyConfirmLocalized("waifu_affinity_set", Format.Bold(u.ToString())).ConfigureAwait(false);
}
else
{
await ReplyConfirmLocalized("waifu_affinity_changed", Format.Bold(oldAff.ToString()), Format.Bold(u.ToString())).ConfigureAwait(false);
}
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task WaifuLeaderboard(int page = 1)
{
page--;
if (page < 0)
return;
IList<WaifuInfo> waifus;
using (var uow = _db.UnitOfWork)
{
waifus = uow.Waifus.GetTop(9, page * 9);
}
if (waifus.Count == 0)
{
await ReplyConfirmLocalized("waifus_none").ConfigureAwait(false);
return;
}
var embed = new EmbedBuilder()
.WithTitle(GetText("waifus_top_waifus"))
.WithOkColor();
for (var i = 0; i < waifus.Count; i++)
{
var w = waifus[i];
var j = i;
embed.AddField(efb => efb.WithName("#" + ((page * 9) + j + 1) + " - " + w.Price + _bc.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]IGuildUser target = null)
{
if (target == null)
target = (IGuildUser)Context.User;
WaifuInfo w;
IList<WaifuInfo> claims;
int divorces;
using (var uow = _db.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),
});
}
w.Waifu.Username = target.Username;
w.Waifu.Discriminator = target.Discriminator;
await uow.CompleteAsync().ConfigureAwait(false);
}
var claimInfo = GetClaimTitle(target.Id);
var affInfo = GetAffinityTitle(target.Id);
var rng = new NadekoRandom();
var nobody = GetText("nobody");
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle("Waifu " + w.Waifu + " - \"the " + claimInfo.Title + "\"")
.AddField(efb => efb.WithName(GetText("price")).WithValue(w.Price.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("claimed_by")).WithValue(w.Claimer?.ToString() ?? nobody).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("likes")).WithValue(w.Affinity?.ToString() ?? nobody).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("changes_of_heart")).WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true))
.AddField(efb => efb.WithName(GetText("divorces")).WithValue(divorces.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("gifts")).WithValue(!w.Items.Any() ? "-" : string.Join("\n", w.Items.OrderBy(x => x.Price).GroupBy(x => x.ItemEmoji).Select(x => $"{x.Key} x{x.Count()}"))).WithIsInline(false))
.AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? nobody : string.Join("\n", claims.OrderBy(x => rng.Next()).Take(30).Select(x => x.Waifu))).WithIsInline(false));
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[Priority(1)]
public async Task WaifuGift()
{
var embed = new EmbedBuilder()
.WithTitle(GetText("waifu_gift_shop"))
.WithOkColor();
Enum.GetValues(typeof(WaifuItem.ItemName))
.Cast<WaifuItem.ItemName>()
.Select(x => WaifuItem.GetItem(x))
.ForEach(x => embed.AddField(f => f.WithName(x.ItemEmoji + " " + x.Item).WithValue(x.Price).WithIsInline(true)));
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[Priority(0)]
public async Task WaifuGift(WaifuItem.ItemName item, [Remainder] IUser waifu)
{
if (waifu.Id == Context.User.Id)
return;
var itemObj = WaifuItem.GetItem(item);
using (var uow = _db.UnitOfWork)
{
var w = uow.Waifus.ByWaifuUserId(waifu.Id);
//try to buy the item first
if (!await _cs.RemoveAsync(Context.User.Id, "Bought waifu item", itemObj.Price, uow))
{
await ReplyErrorLocalized("not_enough", _bc.BotConfig.CurrencySign).ConfigureAwait(false);
return;
}
if (w == null)
{
uow.Waifus.Add(w = new WaifuInfo()
{
Affinity = null,
Claimer = null,
Price = 1,
Waifu = uow.DiscordUsers.GetOrCreate(waifu),
});
w.Waifu.Username = waifu.Username;
w.Waifu.Discriminator = waifu.Discriminator;
}
w.Items.Add(itemObj);
if (w.Claimer?.UserId == Context.User.Id)
{
w.Price += itemObj.Price;
}
else
w.Price += itemObj.Price / 2;
await uow.CompleteAsync().ConfigureAwait(false);
}
await ReplyConfirmLocalized("waifu_gift", Format.Bold(item.ToString() + " " +itemObj.ItemEmoji), Format.Bold(waifu.ToString())).ConfigureAwait(false);
}
public struct WaifuProfileTitle
{
public int Count { get; }
public string Title { get; }
public WaifuProfileTitle(int count, string title)
{
Count = count;
Title = title;
}
}
private WaifuProfileTitle GetClaimTitle(ulong userId)
{
int count;
using (var uow = _db.UnitOfWork)
{
count = uow.Waifus.ByClaimerUserId(userId).Count;
}
ClaimTitles title;
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 WaifuProfileTitle GetAffinityTitle(ulong userId)
{
int count;
using (var uow = _db.UnitOfWork)
{
count = uow._context.WaifuUpdates
.Where(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged && w.New != null)
.GroupBy(x => x.New)
.Count();
}
AffinityTitles title;
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('_', ' '));
}
}
}
}