Esempio n. 1
0
        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());
            }
        }