public virtual ActionResult AdvanceTurn()
        {
            var myMembershipId = User.Identity.GetUserId();
            var me             = PlayerProcedures.GetPlayerFromMembership(myMembershipId);

            if (me.InDuel <= 0)
            {
                TempData["Error"] = "You are not in a duel.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            var duel = DuelProcedures.GetDuel(me.InDuel);

            var combatants = DuelProcedures.GetPlayerViewModelsInDuel(duel.Id);

            if (!PvPStatics.ChaosMode)
            {
                foreach (var p in combatants)
                {
                    if (p.Player.TimesAttackingThisUpdate < PvPStatics.MaxAttacksPerUpdate)
                    {
                        TempData["Error"] = "Cannot advance this turn." + p.Player.GetFullName() + " has not used up all of their attacks.";
                        return(RedirectToAction(MVC.PvP.Play()));
                    }
                }
            }

            foreach (var p in combatants)
            {
                PlayerProcedures.SetAttackCount(p.Player.ToDbPlayer(), 0);
                PlayerProcedures.SetCleanseMeditateCount(p.Player.ToDbPlayer(), 0);
                var message = "<b>" + me.GetFullName() + " has advanced the duel turn.  Attacks and cleanse/meditate limits have been reset.  Attacks may resume in 20 seconds.</b>";
                PlayerLogProcedures.AddPlayerLog(p.Player.Id, message, true);
                NoticeService.PushNotice(p.Player.Id, message, NoticeService.PushType__PlayerLog);
            }

            DuelProcedures.SetLastDuelAttackTimestamp(duel.Id);

            TempData["Result"] = "Duel turn advanced.  All combatants have had their attack and cleanse/meditate limits reset.  Attacks may resume in 20 seconds.";
            return(RedirectToAction(MVC.PvP.Play()));
        }
        public virtual ActionResult DuelDetail(int id)
        {
            var myMembershipId = User.Identity.GetUserId();
            var me             = PlayerProcedures.GetPlayerFromMembership(myMembershipId);
            var duel           = DuelProcedures.GetDuel(id);

            if (me.InDuel != duel.Id)
            {
                TempData["Error"] = "You are not in this duel.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            var output = new DuelPlayersViewModel
            {
                Duel       = duel,
                Combatants = DuelProcedures.GetPlayerViewModelsInDuel(duel.Id)
            };

            ViewBag.CurrentTurn    = PvPWorldStatProcedures.GetWorldTurnNumber();
            ViewBag.TurnsRemaining = PvPStatics.MaximumDuelTurnLength - (ViewBag.CurrentTurn - duel.StartTurn);

            return(View(MVC.Duel.Views.DuelDetail, output));
        }
        public virtual ActionResult AcceptChallenge(int id)
        {
            var myMembershipId = User.Identity.GetUserId();

            if (PvPStatics.AnimateUpdateInProgress)
            {
                TempData["Error"]    = "Player update portion of the world update is still in progress.";
                TempData["SubError"] = "Try again a bit later when the update has progressed farther along.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            var duel = DuelProcedures.GetDuel(id);
            var me   = PlayerProcedures.GetPlayerFromMembership(myMembershipId);

            // assert duel challenge is not too old
            if (duel.ProposalTurn > PvPWorldStatProcedures.GetWorldTurnNumber() + 1)
            {
                TempData["Error"]    = "This challenge to a duel has expired.";
                TempData["SubError"] = "Offers for a duel must be accpted within the same turn or in the next.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert duel is still active
            if (duel.Status != DuelProcedures.PENDING)
            {
                TempData["Error"] = "This duel has already started, has been completed, or was rejected.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            var participants = DuelProcedures.GetPlayerViewModelsInDuel(duel.Id);
            var duelLocation = participants.First().Player.dbLocationName;

            var errorMessages = new List <string>();

            foreach (var p in participants)
            {
                // assert player is not a bot... somehow
                if (p.Player.BotId < AIStatics.ActivePlayerBotId)
                {
                    errorMessages.Add(p.Player.GetFullName() + " is an NPC and thus cannot engage in a duel.");
                }

                // assert player is animate
                if (p.Player.Mobility != PvPStatics.MobilityFull)
                {
                    errorMessages.Add("Duel cannot start yet.  " + p.Player.GetFullName() + " must be animate in order to challenge someone to a duel.");
                }

                // assert player is not already in a duel
                if (p.Player.InDuel > 0)
                {
                    errorMessages.Add("Duel cannot start yet.  " + p.Player.GetFullName() + " is already participating in a duel.  Each player must not be in an active duel in order to start a new one.");
                }

                // assert player is at the duel location
                if (p.Player.dbLocationName != duelLocation)
                {
                    errorMessages.Add("Duel cannot start yet.  All players must be in the same location to begin a duel.");
                }

                // assert player has sufficient WP to start
                if (p.Player.Health < p.Player.MaxHealth * .8M)
                {
                    errorMessages.Add("Duel cannot start yet.  " + p.Player.GetFullName() + " has too low willpower.  Each player must be at least 80% willpower in order to begin dueling.");
                }

                // assert player has sufficient Mana to start
                if (p.Player.Mana < p.Player.MaxMana * .8M)
                {
                    errorMessages.Add("Duel cannot start yet.  " + p.Player.GetFullName() + " has too low mana.  Each player must be at least 80% mana in order to begin dueling.");
                }

                // assert all players are in an okay game mode
                var weAreFriends = FriendProcedures.PlayerIsMyFriend(me, p.Player.ToDbPlayer());
                if (!weAreFriends)
                {
                    // player is in PvP; target is not
                    if (me.GameMode == (int)GameModeStatics.GameModes.PvP && p.Player.GameMode < (int)GameModeStatics.GameModes.PvP)
                    {
                        errorMessages.Add("You must either be friends with " + p.Player.GetFullName() + " or in the same game mode to challenge them to a duel.");
                    }

                    // player is not in PvP; target is
                    else if (me.GameMode < (int)GameModeStatics.GameModes.PvP && p.Player.GameMode == (int)GameModeStatics.GameModes.PvP)
                    {
                        errorMessages.Add("You must either be friends with " + p.Player.GetFullName() + " or in the same game mode to challenge them to a duel.");
                    }
                }

                // assert that the player has not been in recent combat
                var minutesAgo = Math.Abs(Math.Floor(p.Player.GetLastCombatTimestamp().Subtract(DateTime.UtcNow).TotalMinutes));
                if (minutesAgo < TurnTimesStatics.GetMinutesSinceLastCombatBeforeQuestingOrDuelling())
                {
                    errorMessages.Add("Duel cannot start yet.  " + p.Player.GetFullName() + " must wait another " + (TurnTimesStatics.GetMinutesSinceLastCombatBeforeQuestingOrDuelling() - minutesAgo) + " minutes without being in combat in order accept this challenge to a duel.");
                }

                // assert that both players are still online
                minutesAgo = Math.Abs(Math.Floor(p.Player.LastActionTimestamp.Subtract(DateTime.UtcNow).TotalMinutes));
                if (minutesAgo > TurnTimesStatics.GetMinutesSinceLastCombatBeforeQuestingOrDuelling())
                {
                    errorMessages.Add("Duel cannot start yet.  " + p.Player.GetFullName() + " has been inactive for " + (TurnTimesStatics.GetMinutesSinceLastCombatBeforeQuestingOrDuelling() - minutesAgo) + " minutes.  " + p.Player.GetFullName() + " can become active again and eligible for the duel performing any action which takes AP.  Do not attack as this will reset their no combat timer.");
                }
            }

            if (errorMessages.Any())
            {
                var errors = "";
                foreach (var s in errorMessages)
                {
                    errors += s + "<br>";
                }
                TempData["Error"] = errors;
                return(RedirectToAction(MVC.PvP.Play()));
            }

            TempData["Result"] = "Your duel has started!";
            DuelProcedures.BeginDuel(duel.Id);

            return(RedirectToAction(MVC.PvP.Play()));
        }