NadekoBot/src/NadekoBot/Modules/Pokemon/PokemonModule.cs

390 lines
14 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-11-26 00:52:27 +00:00
[NadekoModule("PokeGame", ">")]
public partial class PokemonModule : DiscordModule
{
public static string CurrencyName { get; set; }
public static string CurrencyPluralName { get; set; }
public static string CurrencySign { get; set; }
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";
private Logger _pokelog { get; }
public PokemonModule(ILocalization loc, CommandService cmds, ShardedDiscordClient client) : base(loc, cmds, client)
2016-11-26 00:52:27 +00:00
{
_pokelog = LogManager.GetCurrentClassLogger();
if (File.Exists(PokemonTypesFile))
2016-11-26 00:52:27 +00:00
{
PokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText(PokemonTypesFile));
}
else
{
_pokelog.Warn(PokemonTypesFile + " is missing. Pokemon types not loaded.");
2016-11-26 00:52:27 +00:00
}
using (var uow = DbHandler.UnitOfWork())
{
var conf = uow.BotConfig.GetOrCreate();
CurrencyName = conf.CurrencyName;
CurrencySign = conf.CurrencySign;
CurrencyPluralName = conf.CurrencyPluralName;
}
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-25 00:20:18 +00:00
private PokemonType GetPokeType(ulong id)
{
Dictionary<long, string> setTypes;
using (var uow = DbHandler.UnitOfWork())
{
setTypes = uow.PokeGame.GetAll().ToDictionary(x => x.UserId, y => y.type);
}
2016-11-25 00:20:18 +00:00
if (setTypes.ContainsKey((long)id))
{
return stringToPokemonType(setTypes[(long)id]);
}
int count = PokemonTypes.Count;
2016-11-25 00:20:18 +00:00
int remainder = Math.Abs((int)(id % (ulong)count));
return PokemonTypes[remainder];
2016-11-25 00:20:18 +00:00
}
private PokemonType stringToPokemonType(string v)
{
var str = v.ToUpperInvariant();
var list = PokemonTypes;
2016-11-25 00:20:18 +00:00
foreach (PokemonType p in list)
{
if (str == p.Name)
{
return p;
}
}
return null;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Attack(IUserMessage umsg, string move, IGuildUser targetUser = null)
2016-11-25 00:20:18 +00:00
{
var channel = (ITextChannel)umsg.Channel;
IGuildUser user = (IGuildUser)umsg.Author;
if (string.IsNullOrWhiteSpace(move)) {
return;
}
if (targetUser == null)
2016-11-25 00:20:18 +00:00
{
await channel.SendMessageAsync("No such person.").ConfigureAwait(false);
return;
}
else if (targetUser == user)
{
await channel.SendMessageAsync("You can't attack yourself.").ConfigureAwait(false);
return;
}
2016-11-25 00:20:18 +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
//Check if able to move
//User not able if HP < 0, has made more than 4 attacks
if (userStats.Hp < 0)
{
await channel.SendMessageAsync($"{user.Mention} has fainted and was not able to move!").ConfigureAwait(false);
return;
}
if (userStats.MovesMade >= 5)
{
await channel.SendMessageAsync($"{user.Mention} has used too many moves in a row and was not able to move!").ConfigureAwait(false);
return;
}
if (userStats.LastAttacked.Contains(targetUser.Id))
{
await channel.SendMessageAsync($"{user.Mention} can't attack again without retaliation!").ConfigureAwait(false);
return;
}
//get target stats
PokeStats targetStats;
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 channel.SendMessageAsync($"{targetUser.Mention} has already fainted!").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 channel.SendMessageAsync($"{user.Mention} is not able to use **{move}**. Type {NadekoBot.ModulePrefixes[typeof(PokemonModule).Name]}ml to see moves").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;
2016-11-25 00:20:18 +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
//Damage type
if (damage < 40)
{
response += "\nIt's not effective..";
}
else if (damage > 60)
{
response += "\nIt's super effective!";
}
else
{
response += "\nIt's somewhat effective";
}
2016-11-25 00:20:18 +00:00
//check fainted
2016-11-25 00:20:18 +00:00
if (targetStats.Hp <= 0)
{
response += $"\n**{targetUser.Nickname}** has fainted!";
}
else
{
response += $"\n**{targetUser.Nickname}** has {targetStats.Hp} HP remaining";
}
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?
Stats[user.Id] = userStats;
Stats[targetUser.Id] = targetStats;
2016-11-25 00:20:18 +00:00
await channel.SendMessageAsync(response).ConfigureAwait(false);
}
2016-11-25 00:20:18 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Movelist(IUserMessage umsg)
{
var channel = (ITextChannel)umsg.Channel;
IGuildUser user = (IGuildUser)umsg.Author;
2016-11-25 00:20:18 +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}";
}
await channel.SendMessageAsync(str).ConfigureAwait(false);
}
2016-11-25 00:20:18 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Heal(IUserMessage umsg, IGuildUser targetUser = null)
{
var channel = (ITextChannel)umsg.Channel;
IGuildUser user = (IGuildUser)umsg.Author;
2016-11-25 00:20:18 +00:00
if (targetUser == null) {
await channel.SendMessageAsync("No such person.").ConfigureAwait(false);
return;
}
2016-11-25 00:20:18 +00:00
if (Stats.ContainsKey(targetUser.Id))
{
var targetStats = Stats[targetUser.Id];
if (targetStats.Hp == targetStats.MaxHp)
{
await channel.SendMessageAsync($"{targetUser.Nickname} already has full HP!").ConfigureAwait(false);
return;
}
//Payment~
var amount = 1;
2016-11-25 00:20:18 +00:00
var target = (targetUser.Id == user.Id) ? "yourself" : targetUser.Nickname;
if (amount > 0)
{
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
2016-11-25 00:20:18 +00:00
{
try { await channel.SendMessageAsync($"{user.Mention} You don't have enough {CurrencyName}s.").ConfigureAwait(false); } catch { }
2016-11-25 00:20:18 +00:00
return;
}
}
2016-11-25 00:20:18 +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")
{
await channel.SendMessageAsync($"You revived yourself with one {CurrencySign}").ConfigureAwait(false);
}
else
{
await channel.SendMessageAsync($"{user.Nickname} revived {targetUser.Nickname} with one {CurrencySign}").ConfigureAwait(false);
}
return;
}
await channel.SendMessageAsync($"{user.Nickname} healed {targetUser.Nickname} with one {CurrencySign}").ConfigureAwait(false);
return;
}
else
{
await channel.SendMessageAsync($"{targetUser.Nickname} already has full HP!").ConfigureAwait(false);
}
}
2016-11-25 00:20:18 +00:00
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Type(IUserMessage umsg, IGuildUser targetUser = null)
{
var channel = (ITextChannel)umsg.Channel;
IGuildUser user = (IGuildUser)umsg.Author;
if (targetUser == null)
{
return;
}
var pType = GetPokeType(targetUser.Id);
await channel.SendMessageAsync($"Type of {targetUser.Nickname} is **{pType.Name.ToLowerInvariant()}**{pType.Icon}").ConfigureAwait(false);
2016-11-25 00:20:18 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task Settype(IUserMessage umsg, [Remainder] string typeTargeted = null)
{
var channel = (ITextChannel)umsg.Channel;
IGuildUser user = (IGuildUser)umsg.Author;
if (string.IsNullOrWhiteSpace(typeTargeted))
return;
var targetType = stringToPokemonType(typeTargeted);
if (targetType == null)
{
await channel.SendMessageAsync("Invalid type specified. Type must be one of:\n" + string.Join(", ", PokemonTypes.Select(t => t.Name.ToUpperInvariant()))).ConfigureAwait(false);
return;
}
if (targetType == GetPokeType(user.Id))
{
await channel.SendMessageAsync($"Your type is already {targetType.Name.ToLowerInvariant()}{targetType.Icon}").ConfigureAwait(false);
return;
}
//Payment~
var amount = 1;
if (amount > 0)
{
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user.Nickname} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
{
try { await channel.SendMessageAsync($"{user.Mention} You don't have enough {CurrencyName}s.").ConfigureAwait(false); } catch { }
return;
}
}
//Actually changing the type here
Dictionary<long, string> setTypes;
using (var uow = DbHandler.UnitOfWork())
{
var pokeUsers = uow.PokeGame.GetAll();
setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
var pt = new UserPokeTypes
{
UserId = (long)user.Id,
type = targetType.Name,
};
if (!setTypes.ContainsKey((long)user.Id))
{
//create user in db
uow.PokeGame.Add(pt);
}
else
{
//update user in db
var pokeUserCmd = pokeUsers.Where(p => p.UserId == (long)user.Id).FirstOrDefault();
pokeUserCmd.type = targetType.Name;
uow.PokeGame.Update(pokeUserCmd);
}
await uow.CompleteAsync();
}
//Now for the response
await channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {CurrencySign}").ConfigureAwait(false);
}
2016-11-25 00:20:18 +00:00
}
}