Ejemplo n.º 1
0
        public async Task <ActionResult> AnswerGameQuestions([FromRoute] long gameId, [FromBody] AnswerGameQuestionsInputModel inputModel,
                                                             CancellationToken cancellationToken)
        {
            using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                var game = await _dataContext.Games
                           .Include(q => q.GameQuestions)
                           .ThenInclude(q => q.Question)
                           .ThenInclude(q => q.QuestionCategories)
                           .FirstOrDefaultAsync(q => q.Id == gameId, cancellationToken);

                #region Game Validation


                if (game == null)
                {
                    return(NotFound());
                }

                if (game.GameState == GameStateIds.Completed || game.GameState == GameStateIds.SelectCategory)
                {
                    return(BadRequest("invalid_gameState", "invalid_gameState"));
                }

                if (game.CurrentTurnPlayerId != AccountId)
                {
                    return(BadRequest("invalid_turn", "invalid_turn"));
                }

                var playerStat = await _dataContext.AccountStatsSummaries.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId, cancellationToken);

                if (playerStat == null)
                {
                    playerStat = new AccountStatsSummary
                    {
                        AccountId = game.CurrentTurnPlayerId.Value
                    };

                    _dataContext.AccountStatsSummaries.Add(playerStat);
                }

                if (inputModel.Answers.Count() != game.GameQuestions.Count)
                {
                    return(BadRequest("invalid_answersCount", "invalid_answersCount"));
                }

                #endregion


                var changedCategoryStats = new List <AccountCategoryStat>();

                foreach (var answer in inputModel.Answers)
                {
                    var gq = game.GameQuestions.FirstOrDefault(q => q.QuestionId == answer.QuestionId);

                    if (gq == null)
                    {
                        return(BadRequest("invalid_answers", "no such question in this game."));
                    }

                    var selectedAnswer = answer.SelectedAnswer;

                    if (game.GameState == GameStateIds.Player1AnswerQuestions)
                    {
                        if (gq.Player1SelectedAnswer.HasValue)
                        {
                            return(BadRequest("invalid_answers", "question already answered."));
                        }

                        gq.Player1SelectedAnswer = selectedAnswer;
                    }

                    else
                    {
                        if (gq.Player2SelectedAnswer.HasValue)
                        {
                            return(BadRequest("invalid_answers", "question already answered."));
                        }

                        gq.Player2SelectedAnswer = selectedAnswer;
                    }

                    var score = gq.Question.CorrectAnswerNumber == selectedAnswer ? 1 : 0;

                    switch (selectedAnswer)
                    {
                    case 1:
                        gq.Question.Answer1ChooseHistory++;
                        break;

                    case 2:
                        gq.Question.Answer2ChooseHistory++;
                        break;

                    case 3:
                        gq.Question.Answer3ChooseHistory++;
                        break;

                    case 4:
                        gq.Question.Answer4ChooseHistory++;
                        break;
                    }

                    // Process Category stats for player
                    foreach (var category in gq.Question.QuestionCategories)
                    {
                        var playerCategoryStat = await _dataContext.AccountCategoryStats.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId && q.CategoryId == category.Id, cancellationToken);

                        if (playerCategoryStat == null)
                        {
                            playerCategoryStat = new AccountCategoryStat
                            {
                                AccountId  = game.CurrentTurnPlayerId.Value,
                                CategoryId = category.CategoryId
                            };

                            _dataContext.AccountCategoryStats.Add(playerCategoryStat);
                            changedCategoryStats.Add(playerCategoryStat);
                        }

                        playerCategoryStat.TotalQuestionsCount += 1;
                        playerCategoryStat.CorrectAnswersCount += score;
                    }

                    if (answer.UsedAnswersHistoryHelper)
                    {
                        var accountCoin = await _dataContext.AccountItems.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId && q.ShopItemId == ShopItemTypeIds.Coin, cancellationToken);

                        if (accountCoin == null || accountCoin.Quantity < _gameSettingsOptions.AnswersHistoryHelperPrice)
                        {
                            // TODO: cheat detected
                            return(BadRequest("insufficient_funds", "insufficient funds to use this helper"));
                        }

                        accountCoin.Quantity -= _gameSettingsOptions.AnswersHistoryHelperPrice;
                    }

                    if (answer.UsedRemoveTwoAnswersHelper)
                    {
                        var accountCoin = await _dataContext.AccountItems.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId && q.ItemTypeId == ShopItemTypeIds.Coin, cancellationToken);

                        if (accountCoin == null || accountCoin.Quantity < _gameSettingsOptions.RemoveTwoAnswersHelperPrice)
                        {
                            // TODO: cheat detected
                            return(BadRequest("insufficient_funds", "insufficient funds to use this helper"));
                        }

                        accountCoin.Quantity -= _gameSettingsOptions.RemoveTwoAnswersHelperPrice;
                        playerStat.RemoveTwoAnswersHelperUsageCount += 1;
                    }

                    if (answer.UsedAskMergenHelper)
                    {
                        var accountCoin = await _dataContext.AccountItems.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId && q.ItemTypeId == ShopItemTypeIds.Coin, cancellationToken);

                        if (accountCoin == null || accountCoin.Quantity < _gameSettingsOptions.AskMergenHelperPrice)
                        {
                            // TODO: cheat detected
                            return(BadRequest("insufficient_funds", "insufficient funds to use this helper"));
                        }

                        accountCoin.Quantity -= _gameSettingsOptions.AskMergenHelperPrice;
                        playerStat.AskMergenHelperUsageCount += 1;
                    }

                    if (answer.UsedDoubleChanceHelper)
                    {
                        var accountCoin = await _dataContext.AccountItems.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId && q.ItemTypeId == ShopItemTypeIds.Coin, cancellationToken);

                        if (accountCoin == null || accountCoin.Quantity < _gameSettingsOptions.DoubleChanceHelperPrice)
                        {
                            // TODO: cheat detected
                            return(BadRequest("insufficient_funds", "insufficient funds to use this helper"));
                        }

                        accountCoin.Quantity -= _gameSettingsOptions.DoubleChanceHelperPrice;
                        playerStat.DoubleChanceHelperUsageCount += 1;
                    }

                    if (answer.TimeExtenderHelperUsageCount > 0)
                    {
                        var accountCoin = await _dataContext.AccountItems.FirstOrDefaultAsync(q => q.AccountId == game.CurrentTurnPlayerId && q.ItemTypeId == ShopItemTypeIds.Coin, cancellationToken);

                        if (accountCoin == null || accountCoin.Quantity < _gameSettingsOptions.TimeExtenderHelperPrice * answer.TimeExtenderHelperUsageCount)
                        {
                            // TODO: cheat detected
                            return(BadRequest("insufficient_funds", "insufficient funds to use this helper"));
                        }

                        accountCoin.Quantity -= _gameSettingsOptions.TimeExtenderHelperPrice * answer.TimeExtenderHelperUsageCount;
                        playerStat.TimeExtenderHelperUsageCount += 1;
                    }
                }

                await _achievementService.ProcessAnswerTimeAchievementsAsync(playerStat, changedCategoryStats, cancellationToken);

                var gameBattleId = game.BattleId;
                if (game.GameQuestions.All(q => q.Player1SelectedAnswer.HasValue && q.Player2SelectedAnswer.HasValue))
                {
                    game.GameState = GameStateIds.Completed;

                    var battle = await _dataContext.OneToOneBattles
                                 .Include(q => q.Games).ThenInclude(q => q.GameQuestions).ThenInclude(q => q.Question)
                                 .Include(q => q.Player1)
                                 .Include(q => q.Player2)
                                 .FirstOrDefaultAsync(q => q.Id == gameBattleId, cancellationToken);

                    if (battle.Games.Count != 6)
                    {
                        battle.Round += 1;
                    }



                    if (battle.Games.Count == 6 && battle.Games.All(q => q.GameState == GameStateIds.Completed))
                    {
                        // Battle Completed

                        battle.BattleStateId = BattleStateIds.Completed;
                        int player1CorrectAnswersCount = 0;
                        int player2CorrectAnswersCount = 0;
                        foreach (var battleGame in battle.Games)
                        {
                            player1CorrectAnswersCount += battleGame.GameQuestions.Sum(q => q.Player1SelectedAnswer == q.Question.CorrectAnswerNumber ? 1 : 0);

                            player2CorrectAnswersCount += battleGame.GameQuestions.Sum(q => q.Player2SelectedAnswer == q.Question.CorrectAnswerNumber ? 1 : 0);
                        }

                        battle.Player1CorrectAnswersCount = player1CorrectAnswersCount;
                        battle.Player2CorrectAnswersCount = player2CorrectAnswersCount;

                        if (player1CorrectAnswersCount > player2CorrectAnswersCount)
                        {
                            battle.WinnerPlayerId = battle.Player1Id;
                        }

                        else if (player2CorrectAnswersCount > player1CorrectAnswersCount)
                        {
                            battle.WinnerPlayerId = battle.Player2Id;
                        }

                        var playersStats = await _dataContext.AccountStatsSummaries
                                           .Where(q => q.AccountId == battle.Player1Id || q.AccountId == battle.Player2Id)
                                           .ToDictionaryAsync(q => q.AccountId, q => q, cancellationToken);

                        var player1Stats = playersStats[battle.Player1Id];
                        var player2Stats = playersStats[battle.Player2Id.Value];

                        player1Stats.TotalBattlesPlayed += 1;
                        player2Stats.TotalBattlesPlayed += 1;

                        if (battle.WinnerPlayerId == battle.Player1Id)
                        {
                            player1Stats.WinCount        += 1;
                            player2Stats.LoseCount       += 1;
                            player1Stats.LastPlayDateTime = DateTime.Now;
                            player2Stats.LastPlayDateTime = DateTime.Now;

                            if (await _battleManager.HasPlayedYesterday(player1Stats.AccountId, cancellationToken))
                            {
                                player1Stats.ContinuousActiveDaysCount += 1;
                            }

                            if (await _battleManager.HasPlayedYesterday(player2Stats.AccountId, cancellationToken))
                            {
                                player2Stats.ContinuousActiveDaysCount += 1;
                            }


                            if (player1CorrectAnswersCount == 18)
                            {
                                player1Stats.AceWinCount += 1;
                            }
                            // Experience for win
                            player1Stats.Score += player1CorrectAnswersCount + ExperienceBase * WinExperienceMultiplier;
                            player1Stats.Coins += player1CorrectAnswersCount + CoinBase * WinCoinMultiplier;

                            // Experience for lose
                            player2Stats.Score += player2CorrectAnswersCount + ExperienceBase * LoseExperienceMultiplier;
                            player2Stats.Coins += player2CorrectAnswersCount + CoinBase * LoseCoinMultiplier;
                        }
                        else if (battle.WinnerPlayerId == battle.Player2Id)
                        {
                            player1Stats.LoseCount += 1;
                            player2Stats.WinCount  += 1;

                            if (player2CorrectAnswersCount == 18)
                            {
                                player2Stats.AceWinCount += 1;
                            }

                            // Experience for win
                            player2Stats.Score += player2CorrectAnswersCount + ExperienceBase * WinExperienceMultiplier;
                            player2Stats.Coins += player2CorrectAnswersCount + CoinBase * WinCoinMultiplier;

                            // Experience for lose
                            player1Stats.Score += player1CorrectAnswersCount + ExperienceBase * LoseExperienceMultiplier;
                            player1Stats.Coins += player1CorrectAnswersCount + CoinBase * LoseCoinMultiplier;
                        }
                        else
                        {
                            // Exprience for draw (drop)

                            player1Stats.Score += player1CorrectAnswersCount + ExperienceBase * DrawExperienceMultiplier;
                            player2Stats.Score += player2CorrectAnswersCount + ExperienceBase * DrawExperienceMultiplier;
                        }

                        player1Stats.Level = _levelManager.GetLevel(player1Stats.Score)?.LevelNumber ?? 0;
                        player2Stats.Level = _levelManager.GetLevel(player2Stats.Score)?.LevelNumber ?? 0;

                        player1Stats.WinRatio = player1Stats.WinCount / (float)player1Stats.TotalBattlesPlayed;
                        player2Stats.WinRatio = player2Stats.WinCount / (float)player2Stats.TotalBattlesPlayed;

                        player1Stats.LoseRatio = player1Stats.LoseCount / (float)player1Stats.TotalBattlesPlayed;
                        player2Stats.LoseRatio = player2Stats.LoseCount / (float)player2Stats.TotalBattlesPlayed;

                        await _achievementService.ProcessBattleAchievementsAsync(battle, player1Stats, player2Stats,
                                                                                 cancellationToken);

                        var account = await _accountManager.GetAsync(game.CurrentTurnPlayerId.Value, cancellationToken);

                        var accountNotifId = game.CurrentTurnPlayerId == player1Stats.AccountId
                            ? player2Stats.AccountId
                            : player1Stats.AccountId;

                        await _notificationManager.SaveAsync(
                            new Core.Entities.Notification
                        {
                            AccountId          = accountNotifId,
                            Body               = $"Your battle Finish with{account.Email}",
                            NotificationTypeId = NotificationTypeIds.BattleCompleted,
                            Title              = "Battle Completed"
                        }, cancellationToken);

                        await _dataContext.SaveChangesAsync(cancellationToken);

                        // Calculate Sky
                        player1Stats.Sky = await CalculatePlayerSkyAsync(battle.Player1Id, cancellationToken);

                        player2Stats.Sky = await CalculatePlayerSkyAsync(battle.Player2Id.Value, cancellationToken);
                    }

                    else
                    {
                        var nextPlayer = game.CurrentTurnPlayerId == battle.Player1Id ? battle.Player1 : battle.Player2;
                        var newGame    = await _gamingService.CreateGameAsync(battle, nextPlayer.Id, cancellationToken);

                        battle.LastGame = newGame;
                    }
                }

                else
                {
                    var battle = await _dataContext.OneToOneBattles
                                 .Include(q => q.Player1)
                                 .Include(q => q.Player2)
                                 .FirstOrDefaultAsync(q => q.Id == gameBattleId, cancellationToken);

                    var nextPlayer = game.CurrentTurnPlayerId == battle.Player1Id ? battle.Player2 : battle.Player1;
                    game.CurrentTurnPlayerId = nextPlayer?.Id;
                    game.GameState           = game.CurrentTurnPlayerId == battle.Player1Id ? GameStateIds.Player1AnswerQuestions : GameStateIds.Player2AnswerQuestions;
                }

                await _dataContext.SaveChangesAsync(cancellationToken);

                transaction.Complete();
            }

            return(Ok());
        }