NadekoBot/src/NadekoBot/Modules/Permissions/Pokemon/Pokemon.cs

355 lines
12 KiB
C#
Raw Normal View History

2016-11-25 00:20:18 +00:00
using Discord.Commands;
2016-11-26 00:52:27 +00:00
using NadekoBot.Attributes;
2016-11-25 00:20:18 +00:00
using NadekoBot.Extensions;
2016-11-26 00:52:27 +00:00
using System.Linq;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
2016-11-25 00:20:18 +00:00
using System.Collections.Generic;
using System.Threading.Tasks;
using Discord;
using NLog;
using System;
using Newtonsoft.Json;
using System.IO;
2016-11-26 00:52:27 +00:00
using System.Collections.Concurrent;
2016-11-25 00:20:18 +00:00
namespace NadekoBot.Modules.Pokemon
{
2016-12-04 21:28:31 +00:00
[NadekoModule("Pokemon", ">")]
public class Pokemon : NadekoTopLevelModule
2016-11-26 00:52:27 +00:00
{
2017-02-14 23:59:10 +00:00
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
public const string PokemonTypesFile = "data/pokemon_types.json";
2017-02-14 23:59:10 +00:00
private new static Logger _log { get; }
2017-01-01 12:57:38 +00:00
static Pokemon()
2016-11-26 00:52:27 +00:00
{
2017-01-01 12:57:38 +00:00
_log = LogManager.GetCurrentClassLogger();
if (File.Exists(PokemonTypesFile))
2016-11-26 00:52:27 +00:00
{
2017-02-14 23:59:10 +00:00
_pokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText(PokemonTypesFile));
}
else
{
2017-01-01 12:57:38 +00:00
_log.Warn(PokemonTypesFile + " is missing. Pokemon types not loaded.");
2016-11-26 00:52:27 +00:00
}
}
2016-11-25 00:20:18 +00:00
private int GetDamage(PokemonType usertype, PokemonType targetType)
{
var rng = new Random();
2017-02-14 23:59:10 +00:00
var damage = rng.Next(40, 60);
foreach (var multiplierObj in usertype.Multipliers)
2016-11-25 00:20:18 +00:00
{
2017-02-14 23:59:10 +00:00
if (multiplierObj.Type != targetType.Name) continue;
damage = (int)(damage * multiplierObj.Multiplication);
2016-11-25 00:20:18 +00:00
}
return damage;
}
2016-11-25 00:20:18 +00:00
2017-02-14 23:59:10 +00:00
private static PokemonType GetPokeType(ulong id)
2016-11-25 00:20:18 +00:00
{
2016-12-04 20:28:49 +00:00
Dictionary<ulong, string> setTypes;
using (var uow = DbHandler.UnitOfWork())
{
setTypes = uow.PokeGame.GetAll().ToDictionary(x => x.UserId, y => y.type);
}
2016-12-04 20:28:49 +00:00
if (setTypes.ContainsKey(id))
2016-11-25 00:20:18 +00:00
{
2016-12-04 20:28:49 +00:00
return StringToPokemonType(setTypes[id]);
2016-11-25 00:20:18 +00:00
}
2017-02-14 23:59:10 +00:00
var count = _pokemonTypes.Count;
2016-11-25 00:20:18 +00:00
2017-02-14 23:59:10 +00:00
var remainder = Math.Abs((int)(id % (ulong)count));
2016-11-25 00:20:18 +00:00
2017-02-14 23:59:10 +00:00
return _pokemonTypes[remainder];
2016-11-25 00:20:18 +00:00
}
2017-02-14 23:59:10 +00:00
private static PokemonType StringToPokemonType(string v)
2016-11-25 00:20:18 +00:00
{
2016-12-04 20:28:49 +00:00
var str = v?.ToUpperInvariant();
2017-02-14 23:59:10 +00:00
var list = _pokemonTypes;
foreach (var p in list)
2016-11-25 00:20:18 +00:00
{
if (str == p.Name)
{
return p;
}
}
return null;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-17 00:16:14 +00:00
public async Task Attack(string move, IGuildUser targetUser = null)
2016-11-25 00:20:18 +00:00
{
2016-12-16 18:43:57 +00:00
IGuildUser user = (IGuildUser)Context.User;
if (string.IsNullOrWhiteSpace(move)) {
return;
}
if (targetUser == null)
2016-11-25 00:20:18 +00:00
{
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
return;
}
if (targetUser == user)
{
await ReplyErrorLocalized("cant_attack_yourself").ConfigureAwait(false);
return;
}
2016-11-25 00:20:18 +00:00
// Checking stats first, then move
//Set up the userstats
2017-02-14 23:59:10 +00:00
var userStats = _stats.GetOrAdd(user.Id, new PokeStats());
2016-11-25 00:20:18 +00:00
//Check if able to move
//User not able if HP < 0, has made more than 4 attacks
if (userStats.Hp < 0)
{
await ReplyErrorLocalized("you_fainted").ConfigureAwait(false);
return;
}
if (userStats.MovesMade >= 5)
{
await ReplyErrorLocalized("too_many_moves").ConfigureAwait(false);
return;
}
if (userStats.LastAttacked.Contains(targetUser.Id))
{
await ReplyErrorLocalized("cant_attack_again").ConfigureAwait(false);
return;
}
//get target stats
2017-02-14 23:59:10 +00:00
var targetStats = _stats.GetOrAdd(targetUser.Id, new PokeStats());
2016-11-25 00:20:18 +00:00
//If target's HP is below 0, no use attacking
if (targetStats.Hp <= 0)
{
await ReplyErrorLocalized("too_many_moves", targetUser).ConfigureAwait(false);
return;
}
2016-11-25 00:20:18 +00:00
//Check whether move can be used
PokemonType userType = GetPokeType(user.Id);
2016-11-25 00:20:18 +00:00
var enabledMoves = userType.Moves;
if (!enabledMoves.Contains(move.ToLowerInvariant()))
{
await ReplyErrorLocalized("invalid_move", Format.Bold(move), Prefix).ConfigureAwait(false);
return;
}
2016-11-25 00:20:18 +00:00
//get target type
PokemonType targetType = GetPokeType(targetUser.Id);
//generate damage
int damage = GetDamage(userType, targetType);
//apply damage to target
targetStats.Hp -= damage;
2017-02-13 12:44:21 +00:00
var response = GetText("attack", Format.Bold(move), userType.Icon, Format.Bold(targetUser.ToString()), targetType.Icon, Format.Bold(damage.ToString()));
2016-11-25 00:20:18 +00:00
//Damage type
if (damage < 40)
{
2017-02-13 12:44:21 +00:00
response += "\n" + GetText("not_effective");
}
else if (damage > 60)
{
2017-02-13 12:44:21 +00:00
response += "\n" + GetText("super_effective");
}
else
{
2017-02-13 12:44:21 +00:00
response += "\n" + GetText("somewhat_effective");
}
2016-11-25 00:20:18 +00:00
//check fainted
2016-11-25 00:20:18 +00:00
if (targetStats.Hp <= 0)
{
2017-02-14 23:59:10 +00:00
response += "\n" + GetText("fainted", Format.Bold(targetUser.ToString()));
}
else
{
2017-02-14 23:59:10 +00:00
response += "\n" + GetText("hp_remaining", Format.Bold(targetUser.ToString()), targetStats.Hp);
}
2016-11-25 00:20:18 +00:00
//update other stats
userStats.LastAttacked.Add(targetUser.Id);
userStats.MovesMade++;
targetStats.MovesMade = 0;
if (targetStats.LastAttacked.Contains(user.Id))
{
targetStats.LastAttacked.Remove(user.Id);
}
2016-11-25 00:20:18 +00:00
//update dictionary
//This can stay the same right?
2017-02-14 23:59:10 +00:00
_stats[user.Id] = userStats;
_stats[targetUser.Id] = targetStats;
2016-11-25 00:20:18 +00:00
2017-02-13 12:44:21 +00:00
await Context.Channel.SendConfirmAsync(Context.User.Mention + " " + response).ConfigureAwait(false);
}
2016-11-25 00:20:18 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
public async Task Movelist()
{
2016-12-16 18:43:57 +00:00
IGuildUser user = (IGuildUser)Context.User;
2016-11-25 00:20:18 +00:00
var userType = GetPokeType(user.Id);
var movesList = userType.Moves;
2017-02-13 12:44:21 +00:00
var embed = new EmbedBuilder().WithOkColor()
.WithTitle(GetText("moves", userType))
.WithDescription(string.Join("\n", movesList.Select(m => userType.Icon + " " + m)));
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
}
2016-11-25 00:20:18 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-17 00:16:14 +00:00
public async Task Heal(IGuildUser targetUser = null)
{
2016-12-16 18:43:57 +00:00
IGuildUser user = (IGuildUser)Context.User;
2016-11-25 00:20:18 +00:00
if (targetUser == null)
{
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
return;
}
2016-11-25 00:20:18 +00:00
2017-02-14 23:59:10 +00:00
if (_stats.ContainsKey(targetUser.Id))
{
2017-02-14 23:59:10 +00:00
var targetStats = _stats[targetUser.Id];
if (targetStats.Hp == targetStats.MaxHp)
{
await ReplyErrorLocalized("already_full", Format.Bold(targetUser.ToString())).ConfigureAwait(false);
return;
}
//Payment~
var amount = 1;
2016-11-25 00:20:18 +00:00
2016-12-04 20:28:49 +00:00
var target = (targetUser.Id == user.Id) ? "yourself" : targetUser.Mention;
if (amount > 0)
{
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
{
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
return;
}
}
2016-11-25 00:20:18 +00:00
//healing
targetStats.Hp = targetStats.MaxHp;
if (targetStats.Hp < 0)
{
//Could heal only for half HP?
2017-02-14 23:59:10 +00:00
_stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
if (target == "yourself")
{
2017-02-13 12:44:21 +00:00
await ReplyConfirmLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
return;
}
await ReplyConfirmLocalized("revive_other", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
}
await ReplyConfirmLocalized("healed", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
}
else
{
await ErrorLocalized("already_full", Format.Bold(targetUser.ToString()));
}
}
2016-11-25 00:20:18 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-17 00:16:14 +00:00
public async Task Type(IGuildUser targetUser = null)
{
targetUser = targetUser ?? (IGuildUser)Context.User;
var pType = GetPokeType(targetUser.Id);
await ReplyConfirmLocalized("type_of_user", Format.Bold(targetUser.ToString()), pType).ConfigureAwait(false);
2016-11-25 00:20:18 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-17 00:16:14 +00:00
public async Task Settype([Remainder] string typeTargeted = null)
{
2016-12-16 18:43:57 +00:00
IGuildUser user = (IGuildUser)Context.User;
2016-12-04 20:28:49 +00:00
var targetType = StringToPokemonType(typeTargeted);
if (targetType == null)
{
2017-02-14 23:59:10 +00:00
await Context.Channel.EmbedAsync(_pokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"),
2016-12-17 00:16:14 +00:00
(eb, pt) => eb.AddField(efb => efb.WithName(pt.Name)
.WithValue(pt.Icon)
.WithIsInline(true)))
.WithColor(NadekoBot.OkColor)).ConfigureAwait(false);
return;
}
if (targetType == GetPokeType(user.Id))
{
await ReplyErrorLocalized("already_that_type", targetType).ConfigureAwait(false);
return;
}
//Payment~
var amount = 1;
if (amount > 0)
{
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
{
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
return;
}
}
//Actually changing the type here
using (var uow = DbHandler.UnitOfWork())
{
2017-02-14 23:59:10 +00:00
var pokeUsers = uow.PokeGame.GetAll().ToArray();
var setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
var pt = new UserPokeTypes
{
2016-12-04 20:28:49 +00:00
UserId = user.Id,
type = targetType.Name,
};
2016-12-04 20:28:49 +00:00
if (!setTypes.ContainsKey(user.Id))
{
//create user in db
uow.PokeGame.Add(pt);
}
else
{
//update user in db
2017-02-14 23:59:10 +00:00
var pokeUserCmd = pokeUsers.FirstOrDefault(p => p.UserId == user.Id);
pokeUserCmd.type = targetType.Name;
uow.PokeGame.Update(pokeUserCmd);
}
await uow.CompleteAsync();
}
//Now for the response
await ReplyConfirmLocalized("settype_success",
targetType,
NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
}
2016-11-25 00:20:18 +00:00
}
}