private async Task <EncounterData> Encounter(string enemyPath, int enemyLevel, string enemyName) { try { var path = ImageGenerator.CreateOrGetImage(enemyPath, BackgroundPath, CurrentHP / MaxHP); var url = await ImageGenerator.GetImageURL(path); var currentUserIds = UserIds.ToList(); var maxHPEnemy = enemyLevel * 50 * random.Range(0.8f, 1.5f); var currentHPEnemy = maxHPEnemy; DiscordMessage msg = null; var actions = Actions.ActionBase.GetAllActions(); var turnCount = 0; var additional = ""; while (true) { turnCount++; var healthPercentage = CurrentHP / MaxHP; var healthPercentageEnemy = currentHPEnemy / maxHPEnemy; var embed = Bot.GetDefaultEmbed() .WithImageUrl(url) .AddField("Quest", QuestName) .WithColor(new DiscordColor(1f, healthPercentage, healthPercentage)) .AddField("__Encounter__", $"{enemyName} - LVL {enemyLevel}") .AddField($"HP - {CurrentHP.ToString("0.00")} / {MaxHP.ToString("0.00")}", $"`{ProgressBar.GetProcessBar(healthPercentage)}`") .AddField($"Enemy - {currentHPEnemy.ToString("0.00")} / {maxHPEnemy.ToString("0.00")}", $"`{ProgressBar.GetProcessBar(healthPercentageEnemy)}`"); if (!string.IsNullOrEmpty(additional)) { embed.AddField("Info", additional); } if (msg != null) { await msg.DeleteAsync(); await Task.Delay(500); } msg = await Channel.SendMessageAsync(embed : embed); await Task.Delay(500); #region Get Reactions var currentPlayerActions = currentUserIds.ToDictionary(x => x, k => - 1); async Task CollectActions(CancellationToken token) { while (currentPlayerActions.Values.Any(x => x == -1)) { try { if (token.IsCancellationRequested) { return; } await Task.Delay(1000); foreach (var action in actions) { if (token.IsCancellationRequested) { return; } var reactions = await msg.GetReactionsAsync(action.GetEmoji()); await Task.Delay(500); foreach (var user in reactions) { if (user.IsBot) { continue; } if (currentUserIds.Contains(user.Id)) { Logger.Info($"Found {user.Id} with action {action.GetType().Name}"); currentPlayerActions[user.Id] = action.Id; } } } } catch (System.Exception ex) { Logger.Error(ex); } } } #region Add Reactions foreach (var action in actions) { await msg.CreateReactionAsync(action.GetEmoji()); await Task.Delay(500); } #endregion Add Reactions using (var timeout = new CancellationTokenSource()) { var task = CollectActions(timeout.Token); var completed = await Task.WhenAny(Task.Delay(TimeSpan.FromMinutes(1), timeout.Token), task); if (completed == task) { timeout.Cancel(); await task; } else { Logger.Info("TIMEOUT"); } } #endregion Get Reactions #region Handle Actions var totalAttacked = 0f; var totalBlocked = 0f; var ranPlayers = new List <ulong>(); foreach (var kv in currentPlayerActions) { if (kv.Value == -1) { continue; } var action = actions.First(x => x.Id == kv.Value); if (action != null) { var playerId = kv.Key; var type = action.GetType(); if (type == typeof(Flee)) { //remove from current party ranPlayers.Add(playerId); _ = currentUserIds.Remove(playerId); } else if (type == typeof(Attack)) { var player = Player.GetPlayer(Channel.GuildId, playerId); totalAttacked += player.GetAttack(); } else if (type == typeof(Defend)) { var player = Player.GetPlayer(Channel.GuildId, playerId); totalBlocked += player.GetAttack(); } } } //LEAVE IF NO PLAYERS REMAIN if (currentUserIds.Count == 0) { await msg.DeleteAsync(); await Task.Delay(500); var exp = CalculateExp(enemyLevel, currentHPEnemy, maxHPEnemy); var gold = CalculateGold(enemyLevel, currentHPEnemy, maxHPEnemy); foreach (var id in ranPlayers) { var player = Player.GetPlayer(Channel.GuildId, id); player.AddExperience(exp); player.AddGold(gold); MaxHP -= player.GetTotalHP(); player.Update(); } return(new EncounterData { Message = $"The remaining party ran away safely, and received {exp} exp and {gold} gold." }); } currentHPEnemy -= totalAttacked; if (currentHPEnemy <= 0f) { //victory await msg.DeleteAsync(); var players = Player.GetPlayers(Channel.GuildId, currentUserIds); var exp = CalculateExp(enemyLevel, 0, 1); var gold = CalculateGold(enemyLevel, 0, 1); foreach (var player in players) { player.Victory(exp, gold); player.Update(); } await Task.Delay(500); return(new EncounterData() { Ids = currentPlayerActions.Keys, Message = $"Everyone pulled together, and defeated the enemy in {turnCount} turns!\nReceived a total of {exp} exp and {gold} gold.", }); } var damage = CalculateDamage(enemyLevel); CurrentHP -= Math.Max(0, damage - totalBlocked); additional = $"Dealt {totalAttacked.ToString("0.00")} damage, and received {Math.Max(0, damage - totalBlocked).ToString("0.00")} damage"; if (CurrentHP <= 0f) { //dead await msg.DeleteAsync(); var players = Player.GetPlayers(Channel.GuildId, currentUserIds); var exp = (long)Math.Round(CalculateExp(enemyLevel, 0, 1) * 0.75f); foreach (var player in players) { player.CurrentMercenaries = 0; player.AddExperience(-exp); player.Update(); } await Task.Delay(500); return(new EncounterData { Ids = null, Message = $"Everyone died in {turnCount} turns and lost {exp} exp." }); } #endregion Handle Actions } } catch (System.Exception ex) { Logger.Error(ex); return(new EncounterData()); } }