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;
|
2016-11-27 02:51:10 +00:00
|
|
|
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;
|
2017-02-13 10:12:13 +00:00
|
|
|
using NadekoBot.Modules;
|
|
|
|
using NadekoBot.Resources;
|
2016-11-26 00:52:27 +00:00
|
|
|
|
2016-11-25 00:20:18 +00:00
|
|
|
namespace NadekoBot.Modules.Pokemon
|
|
|
|
{
|
2016-12-04 21:28:31 +00:00
|
|
|
[NadekoModule("Pokemon", ">")]
|
2017-02-13 09:29:57 +00:00
|
|
|
public partial class Pokemon : NadekoModule
|
2016-11-26 00:52:27 +00:00
|
|
|
{
|
2016-11-27 02:51:10 +00:00
|
|
|
private static List<PokemonType> PokemonTypes = new List<PokemonType>();
|
|
|
|
private static ConcurrentDictionary<ulong, PokeStats> Stats = new ConcurrentDictionary<ulong, PokeStats>();
|
|
|
|
|
|
|
|
public const string PokemonTypesFile = "data/pokemon_types.json";
|
|
|
|
|
2017-01-01 12:57:38 +00:00
|
|
|
private static new Logger _log { get; }
|
2016-11-27 02:51:10 +00:00
|
|
|
|
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();
|
2016-11-27 02:51:10 +00:00
|
|
|
if (File.Exists(PokemonTypesFile))
|
2016-11-26 00:52:27 +00:00
|
|
|
{
|
2016-11-27 02:51: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();
|
|
|
|
int damage = rng.Next(40, 60);
|
|
|
|
foreach (PokemonMultiplier Multiplier in usertype.Multipliers)
|
|
|
|
{
|
|
|
|
if (Multiplier.Type == targetType.Name)
|
|
|
|
{
|
|
|
|
var multiplier = Multiplier.Multiplication;
|
|
|
|
damage = (int)(damage * multiplier);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return damage;
|
|
|
|
}
|
2016-11-27 02:51:10 +00:00
|
|
|
|
2016-11-25 00:20:18 +00:00
|
|
|
|
|
|
|
private PokemonType GetPokeType(ulong id)
|
|
|
|
{
|
|
|
|
|
2016-12-04 20:28:49 +00:00
|
|
|
Dictionary<ulong, string> setTypes;
|
2016-11-27 02:51:10 +00:00
|
|
|
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
|
|
|
}
|
2016-11-27 02:51:10 +00:00
|
|
|
int count = PokemonTypes.Count;
|
2016-11-25 00:20:18 +00:00
|
|
|
|
|
|
|
int remainder = Math.Abs((int)(id % (ulong)count));
|
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
return PokemonTypes[remainder];
|
2016-11-25 00:20:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-12-04 20:28:49 +00:00
|
|
|
private PokemonType StringToPokemonType(string v)
|
2016-11-25 00:20:18 +00:00
|
|
|
{
|
2016-12-04 20:28:49 +00:00
|
|
|
var str = v?.ToUpperInvariant();
|
2016-11-27 02:51:10 +00:00
|
|
|
var list = PokemonTypes;
|
2016-11-25 00:20:18 +00:00
|
|
|
foreach (PokemonType p in list)
|
|
|
|
{
|
|
|
|
if (str == p.Name)
|
|
|
|
{
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
|
|
|
|
[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;
|
2016-11-27 02:51:10 +00:00
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(move)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (targetUser == null)
|
2016-11-25 00:20:18 +00:00
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-02-13 12:24:11 +00:00
|
|
|
if (targetUser == user)
|
2016-11-27 02:51:10 +00:00
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("cant_attack_yourself").ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
|
|
|
|
// Checking stats first, then move
|
|
|
|
//Set up the userstats
|
|
|
|
PokeStats userStats;
|
|
|
|
userStats = Stats.GetOrAdd(user.Id, new PokeStats());
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//Check if able to move
|
|
|
|
//User not able if HP < 0, has made more than 4 attacks
|
|
|
|
if (userStats.Hp < 0)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("you_fainted").ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (userStats.MovesMade >= 5)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("too_many_moves").ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (userStats.LastAttacked.Contains(targetUser.Id))
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("cant_attack_again").ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
//get target stats
|
|
|
|
PokeStats targetStats;
|
|
|
|
targetStats = Stats.GetOrAdd(targetUser.Id, new PokeStats());
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//If target's HP is below 0, no use attacking
|
|
|
|
if (targetStats.Hp <= 0)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("too_many_moves", targetUser).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//Check whether move can be used
|
|
|
|
PokemonType userType = GetPokeType(user.Id);
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
var enabledMoves = userType.Moves;
|
|
|
|
if (!enabledMoves.Contains(move.ToLowerInvariant()))
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("invalid_move", move, _prefix).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//get target type
|
|
|
|
PokemonType targetType = GetPokeType(targetUser.Id);
|
|
|
|
//generate damage
|
|
|
|
int damage = GetDamage(userType, targetType);
|
|
|
|
//apply damage to target
|
|
|
|
targetStats.Hp -= damage;
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
var response = $"{user.Mention} used **{move}**{userType.Icon} on {targetUser.Mention}{targetType.Icon} for **{damage}** damage";
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//Damage type
|
|
|
|
if (damage < 40)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
response += "\nIt's not effective.";
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
|
|
|
else if (damage > 60)
|
|
|
|
{
|
|
|
|
response += "\nIt's super effective!";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
response += "\nIt's somewhat effective";
|
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//check fainted
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
if (targetStats.Hp <= 0)
|
|
|
|
{
|
2016-12-04 20:28:49 +00:00
|
|
|
response += $"\n**{targetUser.Mention}** has fainted!";
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-04 20:28:49 +00:00
|
|
|
response += $"\n**{targetUser.Mention}** has {targetStats.Hp} HP remaining";
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +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
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//update dictionary
|
|
|
|
//This can stay the same right?
|
|
|
|
Stats[user.Id] = userStats;
|
|
|
|
Stats[targetUser.Id] = targetStats;
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-12-17 00:16:14 +00:00
|
|
|
await Context.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
[NadekoCommand, Usage, Description, Aliases]
|
|
|
|
[RequireContext(ContextType.Guild)]
|
2016-12-16 18:43:57 +00:00
|
|
|
public async Task Movelist()
|
2016-11-27 02:51:10 +00:00
|
|
|
{
|
2016-12-16 18:43:57 +00:00
|
|
|
IGuildUser user = (IGuildUser)Context.User;
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
var userType = GetPokeType(user.Id);
|
|
|
|
var movesList = userType.Moves;
|
|
|
|
var str = $"**Moves for `{userType.Name}` type.**";
|
|
|
|
foreach (string m in movesList)
|
|
|
|
{
|
|
|
|
str += $"\n{userType.Icon}{m}";
|
|
|
|
}
|
2016-12-17 00:16:14 +00:00
|
|
|
await Context.Channel.SendMessageAsync(str).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +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-11-27 02:51:10 +00:00
|
|
|
{
|
2016-12-16 18:43:57 +00:00
|
|
|
IGuildUser user = (IGuildUser)Context.User;
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
if (targetUser == null) {
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
if (Stats.ContainsKey(targetUser.Id))
|
|
|
|
{
|
|
|
|
var targetStats = Stats[targetUser.Id];
|
|
|
|
if (targetStats.Hp == targetStats.MaxHp)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("already_full", targetUser).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
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;
|
2016-11-27 02:51:10 +00:00
|
|
|
if (amount > 0)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
|
|
|
|
{
|
|
|
|
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
|
|
|
return;
|
|
|
|
}
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
//healing
|
|
|
|
targetStats.Hp = targetStats.MaxHp;
|
|
|
|
if (targetStats.Hp < 0)
|
|
|
|
{
|
|
|
|
//Could heal only for half HP?
|
|
|
|
Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
|
|
|
|
if (target == "yourself")
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
|
|
|
return;
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2017-02-13 12:24:11 +00:00
|
|
|
|
|
|
|
await ReplyErrorLocalized("revive_other", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("healed", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ErrorLocalized("already_full", targetUser);
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
|
|
|
|
|
2016-11-27 02:51:10 +00:00
|
|
|
[NadekoCommand, Usage, Description, Aliases]
|
|
|
|
[RequireContext(ContextType.Guild)]
|
2016-12-17 00:16:14 +00:00
|
|
|
public async Task Type(IGuildUser targetUser = null)
|
2016-11-27 02:51:10 +00:00
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
targetUser = targetUser ?? (IGuildUser)Context.User;
|
2016-11-27 02:51:10 +00:00
|
|
|
var pType = GetPokeType(targetUser.Id);
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyConfirmLocalized("type_of_user", targetUser.Mention, pType.Name.ToLowerInvariant() + pType.Icon).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
|
2016-11-25 00:20:18 +00:00
|
|
|
}
|
2016-11-27 02:51:10 +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-11-27 02:51:10 +00:00
|
|
|
{
|
2016-12-16 18:43:57 +00:00
|
|
|
IGuildUser user = (IGuildUser)Context.User;
|
2016-11-27 02:51:10 +00:00
|
|
|
|
2016-12-04 20:28:49 +00:00
|
|
|
var targetType = StringToPokemonType(typeTargeted);
|
2016-11-27 02:51:10 +00:00
|
|
|
if (targetType == null)
|
|
|
|
{
|
2016-12-17 00:16:14 +00:00
|
|
|
await Context.Channel.EmbedAsync(PokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"),
|
|
|
|
(eb, pt) => eb.AddField(efb => efb.WithName(pt.Name)
|
|
|
|
.WithValue(pt.Icon)
|
|
|
|
.WithIsInline(true)))
|
|
|
|
.WithColor(NadekoBot.OkColor)).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (targetType == GetPokeType(user.Id))
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("already_that_type", targetType.Name.ToLowerInvariant() + targetType.Icon).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Payment~
|
|
|
|
var amount = 1;
|
|
|
|
if (amount > 0)
|
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
|
2016-11-27 02:51:10 +00:00
|
|
|
{
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Actually changing the type here
|
2016-12-04 20:28:49 +00:00
|
|
|
Dictionary<ulong, string> setTypes;
|
2016-11-27 02:51:10 +00:00
|
|
|
|
|
|
|
using (var uow = DbHandler.UnitOfWork())
|
|
|
|
{
|
2016-11-28 01:15:08 +00:00
|
|
|
var pokeUsers = uow.PokeGame.GetAll();
|
|
|
|
setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
|
2016-11-27 02:51:10 +00:00
|
|
|
var pt = new UserPokeTypes
|
|
|
|
{
|
2016-12-04 20:28:49 +00:00
|
|
|
UserId = user.Id,
|
2016-11-27 02:51:10 +00:00
|
|
|
type = targetType.Name,
|
|
|
|
};
|
2016-12-04 20:28:49 +00:00
|
|
|
if (!setTypes.ContainsKey(user.Id))
|
2016-11-27 02:51:10 +00:00
|
|
|
{
|
|
|
|
//create user in db
|
|
|
|
uow.PokeGame.Add(pt);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//update user in db
|
2016-12-04 20:28:49 +00:00
|
|
|
var pokeUserCmd = pokeUsers.Where(p => p.UserId == user.Id).FirstOrDefault();
|
2016-11-28 01:15:08 +00:00
|
|
|
pokeUserCmd.type = targetType.Name;
|
|
|
|
uow.PokeGame.Update(pokeUserCmd);
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
|
|
|
await uow.CompleteAsync();
|
|
|
|
}
|
|
|
|
|
|
|
|
//Now for the response
|
2017-02-13 12:24:11 +00:00
|
|
|
await ReplyConfirmLocalized("settype_success",
|
|
|
|
typeTargeted + targetType.Icon,
|
|
|
|
NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
2016-11-27 02:51:10 +00:00
|
|
|
}
|
2016-11-25 00:20:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|