예제 #1
0
        public static void EndDuel(int duelId, string endStatus)
        {
            IDuelRepository duelRepo = new EFDuelRepository();
            var             duel     = duelRepo.Duels.FirstOrDefault(d => d.Id == duelId);

            duel.CompletionTurn = PvPWorldStatProcedures.GetWorldTurnNumber();
            duel.Status         = endStatus;

            duelRepo.SaveDuel(duel);

            foreach (var d in duel.Combatants)
            {
                PlayerProcedures.EnterDuel(d.PlayerId, 0);

                var message = "";

                if (endStatus == TIMEOUT)
                {
                    message = "<b class='bad'>Your duel has timed out, ending in a disappointing draw.  You feel as if some frustrated spirits have left you weakened by a curse...</b>";
                    EffectProcedures.GivePerkToPlayer(TimeoutCurseEffectSourceId, d.PlayerId);
                }
                else
                {
                    message = "<b>Your duel has ended.</b>";
                }

                PlayerLogProcedures.AddPlayerLog(d.PlayerId, message, true);
            }
        }
예제 #2
0
        private static void EngageMindControl(Player target, Player attacker, DbStaticForm targetForm, LogBox output)
        {
            //Player attacker = playerRepo.Players.FirstOrDefault(p => p.Id == attackerId);
            MindControlProcedures.AddMindControl(attacker, target, targetForm.Id);

            output.LocationLog += $"<br><b>{target.GetFullName()} was partially mind controlled by {attacker.GetFullName()} here.</b>";
            output.AttackerLog += $"<br><b>You have seized the mind of {target.GetFullName()}!  You can now force them into performing certain actions.</b>";
            output.VictimLog   += $"<br><b>You are now being partially mind controlled by {targetForm.FriendlyName}!</b>";

            TFEnergyProcedures.DeleteAllPlayerTFEnergiesOfFormSourceId(target.Id, targetForm.Id);
            // Remove any Self Restore entires.
            RemoveSelfRestore(target);

            // give curse debuff
            if (targetForm.Id == MindControlStatics.MindControl__MovementFormSourceId)
            {
                EffectProcedures.GivePerkToPlayer(MindControlStatics.MindControl__Movement_DebuffEffectSourceId, target);
            }
            else if (targetForm.Id == MindControlStatics.MindControl__StripFormSourceId)
            {
                EffectProcedures.GivePerkToPlayer(MindControlStatics.MindControl__Strip_DebuffEffectSourceId, target);
            }
            else if (targetForm.Id == MindControlStatics.MindControl__MeditateFormSourceId)
            {
                EffectProcedures.GivePerkToPlayer(MindControlStatics.MindControl__Strip_DebuffEffectSourceId, target);
            }
        }
예제 #3
0
        public static string UseFurniture(int furnitureId, Player user)
        {
            IFurnitureRepository furnRepo = new EFFurnitureRepository();
            var dbFurniture = furnRepo.Furnitures.FirstOrDefault(f => f.Id == furnitureId);

            dbFurniture.LastUseTimestamp = DateTime.UtcNow;
            dbFurniture.LastUsersIds     = user.Id.ToString();
            furnRepo.SaveFurniture(dbFurniture);

            var furnitureStatic = furnRepo.DbStaticFurniture.FirstOrDefault(f => f.dbType == dbFurniture.dbType);

            var logMessage = "<b>" + user.GetFullName() + "</b> used <b>" + dbFurniture.HumanName + "</b>.";

            CovenantProcedures.WriteCovenantLog(logMessage, (int)user.Covenant, false);

            // furniture gives AP reserve bonus
            if (furnitureStatic.APReserveRefillAmount > 0)
            {
                IPlayerRepository playerRepo = new EFPlayerRepository();
                var dbPlayer = playerRepo.Players.FirstOrDefault(p => p.Id == user.Id);
                dbPlayer.ActionPoints_Refill += furnitureStatic.APReserveRefillAmount;
                if (dbPlayer.ActionPoints_Refill > TurnTimesStatics.GetActionPointReserveLimit())
                {
                    dbPlayer.ActionPoints_Refill = TurnTimesStatics.GetActionPointReserveLimit();
                }
                dbPlayer.LastActionTimestamp = DateTime.UtcNow;
                playerRepo.SavePlayer(dbPlayer);

                return("You used " + dbFurniture.HumanName + ", a human voluntarily transformed into furniture and leased by your covenant, and gained " + furnitureStatic.APReserveRefillAmount + " reserve action points.");
            }

            // furniture gives effect
            else if (furnitureStatic.GivesEffectSourceId != null)
            {
                EffectProcedures.GivePerkToPlayer(furnitureStatic.GivesEffectSourceId.Value, user);
                PlayerProcedures.SetTimestampToNow(user);
                return("You used " + dbFurniture.HumanName + ", a human voluntarily transformed into furniture and leased by your covenant, and gained the " + EffectStatics.GetDbStaticEffect(furnitureStatic.GivesEffectSourceId.Value).FriendlyName + " effect.");
            }

            //furniture gives item
            else if (furnitureStatic.GivesItemSourceId != null)
            {
                ItemProcedures.GiveNewItemToPlayer(user, furnitureStatic.GivesItemSourceId.Value);
                PlayerProcedures.SetTimestampToNow(user);
                var itemGained = ItemStatics.GetStaticItem(furnitureStatic.GivesItemSourceId.Value);
                return("You used " + dbFurniture.HumanName + ", a human voluntarily transformed into furniture and leased by your covenant, gaining a " + itemGained.FriendlyName + ".");
            }

            return("ERROR");
        }
예제 #4
0
        public static void EquipDefeatedPlayer(Player owner, Player defeatedPlayer)
        {
            var playerIsBot = owner.BotId <= AIStatics.PsychopathBotId;

            if (owner.BotId == AIStatics.PsychopathBotId && EffectProcedures.PlayerHasActiveEffect(owner.Id, JokeShopProcedures.PSYCHOTIC_EFFECT))
            {
                // Do not apply to temporary psychos to avoid circumventing inventory rules
                playerIsBot = false;
            }

            if (playerIsBot)
            {
                // have the bot equip any new item they are carrying (psychos take off duplicates later in world update)
                var item = ItemProcedures.GetAllPlayerItems(owner.Id)
                           .FirstOrDefault(i => i.dbItem.FormerPlayerId == defeatedPlayer.Id);

                if (item != null)
                {
                    ItemProcedures.EquipItem(item.dbItem.Id, true);
                }
            }
        }
예제 #5
0
        public static string PlayerEndQuest(Player player, int endType)
        {
            var message = "";
            IPlayerRepository playerRepo = new EFPlayerRepository();
            var dbPlayer = playerRepo.Players.FirstOrDefault(p => p.Id == player.Id);

            dbPlayer.InQuest      = 0;
            dbPlayer.InQuestState = 0;
            playerRepo.SavePlayer(dbPlayer);

            IQuestRepository questRepo = new EFQuestRepository();
            var questPlayerStatus      = questRepo.QuestPlayerStatuses.FirstOrDefault(q => q.PlayerId == player.Id && q.QuestId == player.InQuest);

            if (questPlayerStatus == null)
            {
                questPlayerStatus = new QuestPlayerStatus
                {
                    PlayerId = player.Id,
                    QuestId  = player.InQuest,
                };
            }
            questPlayerStatus.LastEndedTurn = PvPWorldStatProcedures.GetWorldTurnNumber();
            questPlayerStatus.Outcome       = endType;

            questRepo.SaveQuestPlayerStatus(questPlayerStatus);

            // assing completion bonuses
            if (endType == (int)QuestStatics.QuestOutcomes.Completed)
            {
                var questState = GetQuestState(player.InQuestState);

                decimal xpGain = 0;

                foreach (var q in questState.QuestEnds)
                {
                    // experience gain
                    if (q.RewardType == (int)QuestStatics.RewardType.Experience)
                    {
                        xpGain += Int32.Parse(q.RewardAmount);
                    }

                    // item gain
                    else if (q.RewardType == (int)QuestStatics.RewardType.Item)
                    {
                        var item = ItemStatics.GetStaticItem(System.Convert.ToInt32(q.RewardAmount));
                        ItemProcedures.GiveNewItemToPlayer(player, item);
                        message += " <br>You received a <b>" + item.FriendlyName + "</b>.";
                    }

                    // effect gain
                    else if (q.RewardType == (int)QuestStatics.RewardType.Effect)
                    {
                        var effect = EffectStatics.GetDbStaticEffect(System.Convert.ToInt32(q.RewardAmount));
                        EffectProcedures.GivePerkToPlayer(effect.Id, player.Id);
                        message += "<br>You received the effect <b>" + effect.FriendlyName + "</b>.";
                    }

                    // spell gain
                    else if (q.RewardType == (int)QuestStatics.RewardType.Spell)
                    {
                        var spell = SkillStatics.GetStaticSkill(System.Convert.ToInt32(q.RewardAmount));
                        SkillProcedures.GiveSkillToPlayer(player.Id, spell.Id);
                        message += "<br>You learned the spell <b>" + spell.FriendlyName + "</b>.";
                    }
                }

                if (xpGain > 0)
                {
                    message += "<br>You earned <b>" + xpGain + "</b> XP.";
                }

                PlayerProcedures.GiveXP(player, xpGain);
            }

            // delete all of the player's quest variables
            var vars = QuestProcedures.GetAllQuestPlayerVariablesFromQuest(player.InQuest, player.Id).ToList();

            foreach (var v in vars)
            {
                questRepo.DeleteQuestPlayerVariable(v.Id);
            }

            return(message);
        }
예제 #6
0
        public static void SpawnAIPsychopaths(int count)
        {
            var rand = new Random();
            IPlayerRepository playerRepo = new EFPlayerRepository();
            var turnNumber = PvPWorldStatProcedures.GetWorldTurnNumber();
            var botCount   = playerRepo.Players.Count(b => b.BotId == AIStatics.PsychopathBotId);

            for (var i = (0 + botCount); i < (count + botCount); i++)
            {
                var cmd = new CreatePlayer
                {
                    FirstName          = "Psychopath",
                    Location           = LocationsStatics.GetRandomLocationNotInDungeon(),
                    Health             = 100000,
                    MaxHealth          = 100000,
                    Mana               = 100000,
                    MaxMana            = 100000,
                    BotId              = AIStatics.PsychopathBotId,
                    UnusedLevelUpPerks = 0,
                    XP       = 0,
                    Money    = 100,
                    LastName = NameService.GetRandomLastName(),
                    Gender   = i % 2 == 1 ? PvPStatics.GenderMale : PvPStatics.GenderFemale,
                };


                var strength = GetPsychopathLevel(turnNumber);

                if (strength == 1)
                {
                    cmd.Level = 1;
                }
                else if (strength == 3)
                {
                    cmd.FirstName = "Fierce " + cmd.FirstName;
                    cmd.Level     = 3;
                }
                else if (strength == 5)
                {
                    cmd.FirstName = "Wrathful " + cmd.FirstName;
                    cmd.Level     = 5;
                }
                else if (strength == 7)
                {
                    cmd.FirstName = "Loathful " + cmd.FirstName;
                    cmd.Level     = 7;
                }
                else if (strength == 9)
                {
                    cmd.FirstName = "Soulless " + cmd.FirstName;
                    cmd.Level     = 9;
                }

                var idAndFormName = GetPsychoFormFromLevelAndSex(cmd.Level, cmd.Gender);
                cmd.FormSourceId = idAndFormName.Item1;

                // assert this name isn't already taken
                var ghost = playerRepo.Players.FirstOrDefault(p => p.FirstName == cmd.FirstName && p.LastName == cmd.LastName);
                if (ghost != null)
                {
                    continue;
                }

                var id = DomainRegistry.Repository.Execute(cmd);

                // give this bot a random skill
                var eligibleSkills = SkillStatics.GetLearnablePsychopathSkills().ToList();

                double max       = eligibleSkills.Count;
                var    randIndex = Convert.ToInt32(Math.Floor(rand.NextDouble() * max));

                var skillToLearn = eligibleSkills.ElementAt(randIndex);
                SkillProcedures.GiveSkillToPlayer(id, skillToLearn.Id);

                // give this bot the Psychpathic perk
                if (strength == 1)
                {
                    EffectProcedures.GivePerkToPlayer(PsychopathicForLevelOneEffectSourceId, id);
                }
                else if (strength == 3)
                {
                    EffectProcedures.GivePerkToPlayer(PsychopathicForLevelThreeEffectSourceId, id);
                }
                else if (strength == 5)
                {
                    EffectProcedures.GivePerkToPlayer(PsychopathicForLevelFiveEffectSourceId, id);
                }
                else if (strength == 7)
                {
                    EffectProcedures.GivePerkToPlayer(PsychopathicForLevelSevenEffectSourceId, id);
                }
                else if (strength == 9)
                {
                    EffectProcedures.GivePerkToPlayer(PsychopathicForLevelNineEffectSourceId, id);
                }

                // give this psycho a new rune with some random chance it is a higher level than they are, to a max of level 13
                var random = new Random(Guid.NewGuid().GetHashCode());
                var roll   = random.NextDouble();

                if (roll < .1)
                {
                    strength += 4;
                }
                else if (roll < .3)
                {
                    strength += 2;
                }

                var quantity = Math.Floor(random.NextDouble() * 2) + 1; // 1 or 2

                for (var c = 0; c < quantity; c++)
                {
                    var runeId = DomainRegistry.Repository.FindSingle(new GetRandomRuneAtLevel {
                        RuneLevel = strength, Random = random
                    });
                    DomainRegistry.Repository.Execute(new GiveRune {
                        ItemSourceId = runeId, PlayerId = id
                    });
                }

                var psychoEF = playerRepo.Players.FirstOrDefault(p => p.Id == id);
                psychoEF.ReadjustMaxes(ItemProcedures.GetPlayerBuffs(psychoEF));
                playerRepo.SavePlayer(psychoEF);
            }
        }
예제 #7
0
        public static List <Exception> RunPsychopathActions(WorldDetail worldDetail)
        {
            var rand = new Random(DateTime.Now.Millisecond);

            var errors = new List <Exception>();

            IPlayerRepository playerRepo = new EFPlayerRepository();


            //spawn in more bots if there are less than the default
            var botCount = playerRepo.Players.Count(b => b.BotId == AIStatics.PsychopathBotId && b.Mobility == PvPStatics.MobilityFull);

            if (botCount < PvPStatics.PsychopathDefaultAmount)
            {
                SpawnAIPsychopaths(PvPStatics.PsychopathDefaultAmount - botCount);
            }

            var bots = playerRepo.Players.Where(p => p.BotId == AIStatics.PsychopathBotId && p.Mobility == PvPStatics.MobilityFull).ToList();

            foreach (var bot in bots)
            {
                try
                {
                    // if bot is no longer fully animate or is null, skip them
                    if (bot == null || bot.Mobility != PvPStatics.MobilityFull)
                    {
                        continue;
                    }

                    bot.LastActionTimestamp = DateTime.UtcNow;

                    if (!EffectProcedures.PlayerHasActiveEffect(bot.Id, JokeShopProcedures.PSYCHOTIC_EFFECT))
                    {
                        #region drop excess items

                        var botItems = DomainRegistry.Repository.Find(new GetItemsOwnedByPsychopath {
                            OwnerId = bot.Id
                        }).ToList();

                        string[] itemTypes =
                        {
                            PvPStatics.ItemType_Hat,        PvPStatics.ItemType_Accessory, PvPStatics.ItemType_Pants,
                            PvPStatics.ItemType_Pet,        PvPStatics.ItemType_Shirt,     PvPStatics.ItemType_Shoes,
                            PvPStatics.ItemType_Underpants, PvPStatics.ItemType_Undershirt
                        };

                        foreach (var typeToDrop in itemTypes)
                        {
                            if (botItems.Count(i => i.ItemSource.ItemType == typeToDrop) > 1)
                            {
                                var dropList = botItems.Where(i => i.ItemSource.ItemType == typeToDrop).Skip(1);

                                foreach (var i in dropList)
                                {
                                    ItemProcedures.DropItem(i.Id);

                                    var name = "a";

                                    if (i.FormerPlayer != null)
                                    {
                                        name = "<b>" + i.FormerPlayer.FullName + "</b> the";
                                    }

                                    if (i.ItemSource.ItemType == PvPStatics.ItemType_Pet)
                                    {
                                        LocationLogProcedures.AddLocationLog(bot.dbLocationName,
                                                                             "<b>" + bot.GetFullName() + "</b> released " + name + " pet <b>" + i.ItemSource.FriendlyName + "</b> here.");
                                    }
                                    else
                                    {
                                        LocationLogProcedures.AddLocationLog(bot.dbLocationName,
                                                                             "<b>" + bot.GetFullName() + "</b> dropped " + name + " <b>" + i.ItemSource.FriendlyName + "</b> here.");
                                    }
                                }
                            }
                        }

                        #endregion
                    }

                    var botbuffs = ItemProcedures.GetPlayerBuffs(bot);

                    var meditates = 0;

                    // meditate if needed
                    if (bot.Mana < bot.MaxMana * .5M)
                    {
                        var manaroll = (int)Math.Floor(rand.NextDouble() * 4.0D);
                        for (var i = 0; i < manaroll; i++)
                        {
                            DomainRegistry.Repository.Execute(new Meditate
                            {
                                PlayerId   = bot.Id,
                                Buffs      = botbuffs,
                                NoValidate = true
                            });
                            meditates++;
                        }
                    }

                    // cleanse if needed, less if psycho has cleansed lately
                    if (bot.Health < bot.MaxHealth * .5M)
                    {
                        var healthroll = (int)Math.Floor(rand.NextDouble() * 4.0D);
                        for (var i = meditates; i < healthroll; i++)
                        {
                            DomainRegistry.Repository.Execute(new Cleanse
                            {
                                PlayerId   = bot.Id,
                                Buffs      = botbuffs,
                                NoValidate = true
                            });
                        }
                    }


                    var directive = AIDirectiveProcedures.GetAIDirective(bot.Id);

                    // the bot has an attack target, so go chase it
                    if (directive.State == "attack")
                    {
                        var myTarget = PlayerProcedures.GetPlayer(directive.TargetPlayerId);
                        var(mySkills, weakenSkill, inanimateSkill) = GetPsychopathSkills(bot);

                        // if the target is offline, no longer animate, in the dungeon, or in the same form as the spells' target, go into idle mode
                        if (PlayerProcedures.PlayerIsOffline(myTarget) ||
                            myTarget.Mobility != PvPStatics.MobilityFull ||
                            mySkills.IsEmpty() || inanimateSkill == null ||
                            myTarget.FormSourceId == inanimateSkill.StaticSkill.FormSourceId ||
                            myTarget.IsInDungeon() ||
                            myTarget.InDuel > 0 ||
                            myTarget.InQuest > 0)
                        {
                            AIDirectiveProcedures.SetAIDirective_Idle(bot.Id);
                        }

                        // the target is okay for attacking
                        else
                        {
                            // the bot must move to its target location.
                            if (myTarget.dbLocationName != bot.dbLocationName)
                            {
                                if (botbuffs.MoveActionPointDiscount() > -100 && CanMove(worldDetail, myTarget))
                                {
                                    var maxSpaces = NumPsychopathMoveSpaces(bot);
                                    var newplace  = MoveTo(bot, myTarget.dbLocationName, maxSpaces);
                                    bot.dbLocationName = newplace;
                                }
                            }

                            // if the bot is now in the same place as the target, attack away, so long as the target is online and animate
                            if (bot.dbLocationName == myTarget.dbLocationName &&
                                !PlayerProcedures.PlayerIsOffline(myTarget) &&
                                myTarget.Mobility == PvPStatics.MobilityFull &&
                                CanAttack(worldDetail, bot, myTarget)
                                )
                            {
                                playerRepo.SavePlayer(bot);

                                var numAttacks = Math.Min(3, (int)(bot.Mana / PvPStatics.AttackManaCost));
                                var complete   = false;
                                for (var attackIndex = 0; attackIndex < numAttacks && !complete; ++attackIndex)
                                {
                                    var skill = SelectPsychopathSkill(myTarget, mySkills, weakenSkill, rand);
                                    (complete, _) = AttackProcedures.Attack(bot, myTarget, skill);
                                }

                                if (complete)
                                {
                                    EquipDefeatedPlayer(bot, myTarget);
                                }
                            }
                        }
                    }

                    // the bot has no target, so wander and try to find new targets and attack them.
                    else
                    {
                        if (botbuffs.MoveActionPointDiscount() > -100)
                        {
                            var newplace = MoveTo(bot, LocationsStatics.GetRandomLocationNotInDungeon(), 5);
                            bot.dbLocationName = newplace;
                        }


                        // attack stage
                        var playersHere = playerRepo.Players.Where
                                              (p => p.dbLocationName == bot.dbLocationName && p.Mobility == PvPStatics.MobilityFull &&
                                              p.Id != bot.Id && p.BotId == AIStatics.PsychopathBotId && p.Level >= bot.Level).ToList();

                        // filter out offline players and Lindella
                        var onlinePlayersHere = playersHere.Where(p => !PlayerProcedures.PlayerIsOffline(p)).ToList();

                        if (onlinePlayersHere.Count > 0)
                        {
                            var roll   = Math.Floor(rand.NextDouble() * onlinePlayersHere.Count);
                            var victim = onlinePlayersHere.ElementAt((int)roll);
                            AIDirectiveProcedures.SetAIDirective_Attack(bot.Id, victim.Id);
                            playerRepo.SavePlayer(bot);

                            var(mySkills, weakenSkill, inanimateSkill) = GetPsychopathSkills(bot);
                            if (!mySkills.IsEmpty())
                            {
                                var numAttacks = Math.Min(3, (int)(bot.Mana / PvPStatics.AttackManaCost));
                                var complete   = false;
                                for (var attackIndex = 0; attackIndex < numAttacks && !complete; ++attackIndex)
                                {
                                    var skill = SelectPsychopathSkill(victim, mySkills, weakenSkill, rand);
                                    (complete, _) = AttackProcedures.Attack(bot, victim, skill);
                                }

                                if (complete)
                                {
                                    EquipDefeatedPlayer(bot, victim);
                                }
                            }
                        }
                    }

                    playerRepo.SavePlayer(bot);
                }
                catch (Exception e)
                {
                    errors.Add(e);
                }
            }

            return(errors);
        }
예제 #8
0
        public static (bool, string) Attack(Player attackingPlayer, Player attackedPlayer, SkillViewModel skillBeingUsed, bool timestamp = true)
        {
            var result = "";

            var attacker = PlayerProcedures.GetPlayer(attackingPlayer.Id);
            var victim   = PlayerProcedures.GetPlayer(attackedPlayer.Id);

            if (victim.Mobility != PvPStatics.MobilityFull ||
                attacker.Mobility != PvPStatics.MobilityFull ||
                victim.GameMode == (int)GameModeStatics.GameModes.Invisible ||
                attacker.GameMode == (int)GameModeStatics.GameModes.Invisible)
            {
                return(false, "");
            }

            var complete = false;
            var logs     = new LogBox();

            // all of our checks seem to be okay.  So let's lower the player's mana and action points
            PlayerProcedures.ChangePlayerActionMana(-PvPStatics.AttackCost, 0, -PvPStatics.AttackManaCost, attacker.Id, timestamp);

            PlayerProcedures.LogCombatTimestampsAndAddAttackCount(victim, attacker);

            var attackerFullName = attacker.GetFullName();
            var victimFullName   = victim.GetFullName();

            // if the spell is a curse, give the effect and that's all
            if (skillBeingUsed.StaticSkill.GivesEffectSourceId != null)
            {
                var effectBeingGiven = EffectStatics.GetDbStaticEffect(skillBeingUsed.StaticSkill.GivesEffectSourceId.Value);

                EffectProcedures.GivePerkToPlayer(skillBeingUsed.StaticSkill.GivesEffectSourceId.Value, victim);

                if (attacker.Gender == PvPStatics.GenderMale && !effectBeingGiven.AttackerWhenHit_M.IsNullOrEmpty())
                {
                    logs.AttackerLog += effectBeingGiven.AttackerWhenHit_M;
                }
                else if (attacker.Gender == PvPStatics.GenderFemale && !effectBeingGiven.AttackerWhenHit_F.IsNullOrEmpty())
                {
                    logs.AttackerLog += effectBeingGiven.AttackerWhenHit_F;
                }
                else
                {
                    logs.AttackerLog += effectBeingGiven.AttackerWhenHit;
                }

                if (!String.IsNullOrEmpty(logs.AttackerLog))
                {
                    logs.AttackerLog += "<br><br>";
                }

                logs.LocationLog  = "<span class='playerAttackNotification'>" + attackerFullName + " cursed " + victimFullName + " with " + skillBeingUsed.StaticSkill.FriendlyName + ".</span>";
                logs.AttackerLog += "You cursed " + victimFullName + " with " + skillBeingUsed.StaticSkill.FriendlyName + ".";
                logs.AttackerLog += "  (+1 XP)  ";
                logs.AttackerLog += PlayerProcedures.GiveXP(attacker, 1);
                logs.VictimLog    = effectBeingGiven.MessageWhenHit;
                logs.VictimLog   += "  <span class='playerAttackNotification'>" + attackerFullName + " cursed you with <b>" + skillBeingUsed.StaticSkill.FriendlyName + "</b>.</b></span>  ";
                result            = logs.AttackerLog;
            }

            // the spell is a regular attack
            else
            {
                logs.LocationLog = "<span class='playerAttackNotification'>" + attackerFullName + " cast " + skillBeingUsed.StaticSkill.FriendlyName + " against " + victimFullName + ".</span>";
                logs.AttackerLog = "You cast " + skillBeingUsed.StaticSkill.FriendlyName + " against " + victimFullName + ".  ";
                logs.VictimLog   = "<span class='playerAttackNotification'>" + attackerFullName + " cast " + skillBeingUsed.StaticSkill.FriendlyName + " against you.</span>  ";

                var meBuffs       = ItemProcedures.GetPlayerBuffs(attacker);
                var targetedBuffs = ItemProcedures.GetPlayerBuffs(victim);

                var rand          = new Random(Guid.NewGuid().GetHashCode());
                var basehitChance = rand.NextDouble() * 100;

                var meDmgExtra = meBuffs.SpellExtraHealthDamagePercent();

                var criticalMissPercentChance = PvPStatics.CriticalMissPercentChance - meBuffs.SpellMisfireChanceReduction();

                var criticalPercentChance = meBuffs.ExtraSkillCriticalPercent() + PvPStatics.CriticalHitPercentChance;
                var evasionPercentChance  = targetedBuffs.EvasionPercent() - meBuffs.EvasionNegationPercent();
                var evasionUpgrade        = false;
                var failedAttack          = false;

                // clamp modifiedEvasion at 50% max
                if (evasionPercentChance > 50)
                {
                    evasionPercentChance = 50;
                }

                // critical miss!  damage caster instead
                if (basehitChance < (double)criticalMissPercentChance)
                {
                    // check if there is a health damage aspect to this spell
                    if (skillBeingUsed.StaticSkill.HealthDamageAmount > 0)
                    {
                        var amountToDamage = skillBeingUsed.StaticSkill.HealthDamageAmount *
                                             (1 + meDmgExtra / 100);
                        PlayerProcedures.DamagePlayerHealth(attacker.Id, amountToDamage);
                        logs.AttackerLog += $"Misfire!  Your spell accidentally lowered your own willpower by {amountToDamage:N2}.  ";
                        logs.VictimLog   += $"Misfire!  {GetPronoun_HisHer(attacker.Gender)} spell accidentally lowered {GetPronoun_hisher(attacker.Gender)} own willpower by {amountToDamage:N2}.";
                        result           += logs.AttackerLog;
                    }
                    failedAttack = true;
                }
                // spell is evaded
                else if (basehitChance < (double)criticalMissPercentChance + (double)evasionPercentChance)
                {
                    // Check for a crit to upgrade the miss to a hit
                    var criticalHitChance = rand.NextDouble() * 100;
                    if (criticalHitChance < (double)criticalPercentChance)
                    {
                        evasionUpgrade = true;
                    }
                    else
                    {
                        logs.AttackerLog += victimFullName + " managed to leap out of the way of your spell.";
                        logs.VictimLog   += "You managed to leap out of the way " + attackerFullName + "'s spell.";
                        result            = logs.AttackerLog;
                        failedAttack      = true;
                    }
                }

                // not a  miss, so let's deal some damage, possibly
                if (!failedAttack)
                {
                    decimal criticalModifier = 1;

                    if (evasionUpgrade)
                    {
                        logs.AttackerLog += "<b>Piercing hit!</b>  ";
                        logs.VictimLog   += "<b>Piercing hit!</b>  ";
                    }
                    else if (rand.NextDouble() * 100 < (double)criticalPercentChance)
                    {
                        criticalModifier  = 2;
                        logs.AttackerLog += "<b>Critical hit!</b>  ";
                        logs.VictimLog   += "<b>Critical hit!</b>  ";
                    }

                    var initialVictimHealth = victim.Health;

                    // check if there is a health damage aspect to this spell
                    if (skillBeingUsed.StaticSkill.HealthDamageAmount > 0)
                    {
                        var targetProt = targetedBuffs.SpellHealthDamageResistance();

                        // calculator the modifier as extra attack - defense.      15 - 20 = -5 modifier
                        var willpowerDamageModifierFromBonuses = 1 + ((meDmgExtra - targetProt) / 100.0M);

                        // cap the modifier at at 50 % IF the target is a human
                        if (willpowerDamageModifierFromBonuses < .5M)
                        {
                            willpowerDamageModifierFromBonuses = .5M;
                        }

                        // cap the modifier at 200 % IF the target is a human
                        if (willpowerDamageModifierFromBonuses > 2 && victim.BotId == AIStatics.ActivePlayerBotId)
                        {
                            willpowerDamageModifierFromBonuses = 2;
                        }

                        var totalHealthDamage = skillBeingUsed.StaticSkill.HealthDamageAmount * willpowerDamageModifierFromBonuses * criticalModifier;

                        // make sure damage is never in the negatives (which would heal instead)
                        if (totalHealthDamage < 0)
                        {
                            totalHealthDamage = 0;
                        }

                        PlayerProcedures.DamagePlayerHealth(victim.Id, totalHealthDamage);

                        // even though it's been done in the db, change the player health here as well
                        victim.Health -= totalHealthDamage;


                        logs.AttackerLog += $"Your spell lowered {GetPronoun_hisher(victim.Gender)} willpower by {Math.Round(totalHealthDamage, 2)}.  ";
                        logs.VictimLog   += $"{GetPronoun_HisHer(attacker.Gender)} spell lowered your willpower by {Math.Round(totalHealthDamage, 2)}.  ";
                        result           += logs.AttackerLog;
                    }

                    // if this skill has any TF power, add energy and check for form change
                    if (skillBeingUsed.StaticSkill.TFPointsAmount > 0)
                    {
                        var TFEnergyDmg   = meBuffs.SpellExtraTFEnergyPercent();
                        var TFEnergyArmor = targetedBuffs.SpellTFEnergyDamageResistance();

                        // calculator the modifier as extra attack - defense.
                        var tfEnergyDamageModifierFromBonuses = 1 + ((TFEnergyDmg - TFEnergyArmor) / 100.0M);

                        // cap the modifier at at 50 % IF the target is a human
                        if (tfEnergyDamageModifierFromBonuses < .5M)
                        {
                            tfEnergyDamageModifierFromBonuses = .5M;
                        }

                        // cap the modifier at at 200 % IF the target is a human
                        if (tfEnergyDamageModifierFromBonuses > 2 && victim.BotId == AIStatics.ActivePlayerBotId)
                        {
                            tfEnergyDamageModifierFromBonuses = 2;
                        }

                        var totalTFEnergyModifier = criticalModifier * tfEnergyDamageModifierFromBonuses;

                        LogBox tfEnergyResult;
                        (complete, tfEnergyResult) = TFEnergyProcedures.AddTFEnergyToPlayer(victim, attacker, skillBeingUsed, totalTFEnergyModifier, initialVictimHealth);
                        logs.Add(tfEnergyResult);

                        result = logs.AttackerLog;
                    }
                }
            }

            LocationLogProcedures.AddLocationLog(attacker.dbLocationName, logs.LocationLog);
            PlayerLogProcedures.AddPlayerLog(attacker.Id, logs.AttackerLog, false);
            PlayerLogProcedures.AddPlayerLog(victim.Id, logs.VictimLog, true);

            DomainRegistry.AttackNotificationBroker.Notify(victim.Id, logs.VictimLog);

            // if this is a psycho-on-psycho battle, have a chance for the victim bot to switch targets to the attacker bot
            if (attacker.BotId == AIStatics.PsychopathBotId && victim.BotId == AIStatics.PsychopathBotId)
            {
                var rand         = new Random(Guid.NewGuid().GetHashCode());
                var botAggroRoll = rand.NextDouble();
                if (botAggroRoll < .08)
                {
                    AIDirectiveProcedures.SetAIDirective_Attack(victim.Id, attacker.Id);
                }
            }

            return(complete, result);
        }
        public static string ReturnToAnimate(Player player, bool dungeonPenalty)
        {
            IInanimateXPRepository inanimXpRepo = new EFInanimateXPRepository();
            IItemRepository        itemRepo     = new EFItemRepository();

            var inanimXP = inanimXpRepo.InanimateXPs.FirstOrDefault(i => i.OwnerId == player.Id);

            var currentGameTurn = PvPWorldStatProcedures.GetWorldTurnNumber();

            if (inanimXP == null)
            {
                inanimXP = new InanimateXP
                {
                    OwnerId = player.Id,
                    Amount  = 0,

                    // set the initial times struggled proportional to how high of a level the player is
                    TimesStruggled      = -6 * player.Level,
                    LastActionTimestamp = DateTime.UtcNow,
                    LastActionTurnstamp = currentGameTurn - 1,
                };
            }

            double strugglebonus = currentGameTurn - inanimXP.LastActionTurnstamp;

            if (strugglebonus > TurnTimesStatics.GetItemMaxTurnsBuildup())
            {
                strugglebonus = TurnTimesStatics.GetItemMaxTurnsBuildup();
            }

            if (strugglebonus < 0)
            {
                strugglebonus = 0;
            }

            if (PvPStatics.ChaosMode)
            {
                strugglebonus = 100;
            }

            // increment the player's attack count.  Also decrease their player XP some.
            IPlayerRepository playerRepo = new EFPlayerRepository();
            var dbPlayer = playerRepo.Players.FirstOrDefault(p => p.Id == player.Id);

            dbPlayer.TimesAttackingThisUpdate++;

            var strugglesMade = Convert.ToDouble(GetStruggleChance(player, dungeonPenalty));

            var rand = new Random();
            var roll = rand.NextDouble() * 100;

            var dbPlayerItem = DomainRegistry.Repository.FindSingle(new GetItemByFormerPlayer {
                PlayerId = player.Id
            });

            if (dbPlayerItem == null)
            {
                return("Cannot struggle - no player item");
            }

            if (dbPlayerItem.Owner != null)
            {
                var owner = PlayerProcedures.GetPlayer(dbPlayerItem.Owner.Id);
                dbPlayer.dbLocationName = owner.dbLocationName;
            }

            var itemPlus = ItemStatics.GetStaticItem(dbPlayerItem.ItemSource.Id);

            if (roll < strugglesMade)
            {
                // assert that the covenant the victim is in is not too full to accept them back in
                if (dbPlayer.Covenant > 0)
                {
                    var victimCov = CovenantProcedures.GetCovenantViewModel((int)dbPlayer.Covenant).dbCovenant;
                    if (victimCov != null && CovenantProcedures.GetPlayerCountInCovenant(victimCov, true) >= PvPStatics.Covenant_MaximumAnimatePlayerCount)
                    {
                        return("Although you had enough energy to break free from your body as a " + itemPlus.FriendlyName + " and restore your regular body, you were unfortunately not able to break free because there is no more room in your covenant for any more animate mages.");
                    }
                }


                // if the item has an owner, notify them via a message.
                if (dbPlayerItem.Owner != null)
                {
                    var message = player.FirstName + " " + player.LastName + ", your " + itemPlus.FriendlyName + ", successfully struggles against your magic and reverses their transformation.  You can no longer claim them as your property, not unless you manage to turn them back again...";
                    PlayerLogProcedures.AddPlayerLog(dbPlayerItem.Owner.Id, message, true);
                }

                // change the player's form and mobility
                DomainRegistry.Repository.Execute(new ChangeForm
                {
                    PlayerId     = dbPlayer.Id,
                    FormSourceId = dbPlayer.OriginalFormSourceId
                });

                dbPlayer.ActionPoints               = TurnTimesStatics.GetActionPointLimit();
                dbPlayer.ActionPoints_Refill        = TurnTimesStatics.GetActionPointReserveLimit();
                dbPlayer.CleansesMeditatesThisRound = PvPStatics.MaxCleansesMeditatesPerUpdate;
                dbPlayer.TimesAttackingThisUpdate   = PvPStatics.MaxAttacksPerUpdate;

                // don't let the player spawn in the dungeon as they will have Back On Your Feet
                // and may not be meet the level and game mode requirements
                if (dbPlayer.IsInDungeon())
                {
                    dbPlayer.dbLocationName = LocationsStatics.GetRandomLocationNotInDungeon();
                }

                dbPlayer        = PlayerProcedures.ReadjustMaxes(dbPlayer, ItemProcedures.GetPlayerBuffs(dbPlayer));
                dbPlayer.Health = dbPlayer.MaxHealth / 3;
                dbPlayer.Mana   = dbPlayer.MaxHealth / 3;
                playerRepo.SavePlayer(dbPlayer);

                // drop any runes embedded on the player-item, or return them to the former owner's inventory
                DomainRegistry.Repository.Execute(new UnbembedRunesOnItem {
                    ItemId = dbPlayerItem.Id
                });

                // delete the item or animal that this player had turned into
                itemRepo.DeleteItem(dbPlayerItem.Id);

                // delete the inanimate XP item
                inanimXpRepo.DeleteInanimateXP(inanimXP.Id);

                // give the player the recovery buff
                EffectProcedures.GivePerkToPlayer(PvPStatics.Effect_BackOnYourFeetSourceId, dbPlayer);

                var msg = "You have managed to break free from your form as " + itemPlus.FriendlyName + " and occupy an animate body once again!";

                if (PvPStatics.ChaosMode)
                {
                    msg += $" [CHAOS MODE:  Struggle value overriden to {strugglebonus:0}% per struggle.]";
                }

                PlayerLogProcedures.AddPlayerLog(dbPlayer.Id, msg, false);

                StatsProcedures.AddStat(dbPlayer.MembershipId, StatsProcedures.Stat__SuccessfulStruggles, 1);

                return(msg);
            }

            // failure to break free; increase time struggles
            else
            {
                // raise the probability of success for next time somewhat proportion to how many turns they missed
                inanimXP.TimesStruggled     += Convert.ToInt32(strugglebonus);
                inanimXP.LastActionTimestamp = DateTime.UtcNow;
                inanimXP.LastActionTurnstamp = currentGameTurn;
                inanimXpRepo.SaveInanimateXP(inanimXP);

                playerRepo.SavePlayer(dbPlayer);

                if (dbPlayerItem.Owner != null)
                {
                    var message = $"{player.FirstName} {player.LastName}, your {itemPlus.FriendlyName}, struggles but fails to return to an animate form.  [Recovery chance next struggle:  {(int)GetStruggleChance(player, dungeonPenalty)}%]";
                    PlayerLogProcedures.AddPlayerLog(dbPlayerItem.Owner.Id, message, true);
                }

                PlayerLogProcedures.AddPlayerLog(dbPlayer.Id, "You struggled to return to a human form.", false);

                return($"Unfortunately you are not able to struggle free from your form as {itemPlus.FriendlyName}.  Keep trying and you might succeed later... [Recovery chance next struggle:  {(int)GetStruggleChance(player, dungeonPenalty)}%]");
            }
        }
예제 #10
0
        private static void PerformInanimateTransformation(Player victim, Player attacker, int skillSourceId, DbStaticForm targetForm, LogBox output)
        {
            SkillProcedures.UpdateFormSpecificSkillsToPlayer(victim, targetForm.Id);
            DomainRegistry.Repository.Execute(new ChangeForm
            {
                PlayerId     = victim.Id,
                FormSourceId = targetForm.Id
            });

            if (targetForm.MobilityType == PvPStatics.MobilityInanimate && victim.BotId != AIStatics.MinibossPlushAngelId) //No reward for monsters that hurt an innocent little plush friend. :(
            {
                StatsProcedures.AddStat(victim.MembershipId, StatsProcedures.Stat__TimesInanimateTFed, 1);
                StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__TimesInanimateTFing, 1);
            }
            else if (targetForm.MobilityType == PvPStatics.MobilityPet && victim.BotId != AIStatics.MinibossPlushAngelId) //No reward for monsters that hurt an innocent little plush friend. :(
            {
                StatsProcedures.AddStat(victim.MembershipId, StatsProcedures.Stat__TimesAnimalTFed, 1);
                StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__TimesAnimalTFing, 1);
            }

            if (targetForm.MobilityType == PvPStatics.MobilityPet || targetForm.MobilityType == PvPStatics.MobilityInanimate)
            {
                if (victim.BotId == AIStatics.PsychopathBotId)
                {
                    StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__PsychopathsDefeated, 1);
                }

                if (victim.BotId == AIStatics.ActivePlayerBotId && attacker.GameMode == (int)GameModeStatics.GameModes.PvP && victim.GameMode == (int)GameModeStatics.GameModes.PvP)
                {
                    StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__PvPPlayerNumberTakedowns, 1);
                    StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__PvPPlayerLevelTakedowns, victim.Level);
                }
            }

            // extra log stuff for turning into item
            var extra = ItemProcedures.PlayerBecomesItem(victim, targetForm, attacker);

            output.AttackerLog += extra.AttackerLog;
            output.VictimLog   += extra.VictimLog;
            output.LocationLog += extra.LocationLog;

            // give some of the victim's money to the attacker, the amount depending on what mode the victim is in
            var moneygain = victim.Money * .35M;

            PlayerProcedures.GiveMoneyToPlayer(attacker, moneygain);
            PlayerProcedures.GiveMoneyToPlayer(victim, -moneygain / 2);

            var levelDifference = attacker.Level - victim.Level;

            // only give the lump sum XP if the victim is not in the same covenant
            if (attacker.Covenant == null || attacker.Covenant != victim.Covenant)
            {
                var xpGain = 100 - (PvPStatics.XP__EndgameTFCompletionLevelBase * levelDifference);

                if (xpGain < 50)
                {
                    xpGain = 50;
                }
                else if (xpGain > 200)
                {
                    xpGain = 200;
                }

                // give the attacker a nice lump sum for having completed the transformation
                output.AttackerLog += $"  <br>For having sealed your opponent into their new form, you gain an extra <b>{xpGain}</b> XP.";
                output.AttackerLog += PlayerProcedures.GiveXP(attacker, xpGain);
            }

            // exclude PvP score for bots
            if (victim.BotId == AIStatics.ActivePlayerBotId)
            {
                var score = PlayerProcedures.GetPvPScoreFromWin(attacker, victim);

                if (score > 0)
                {
                    output.AttackerLog += PlayerProcedures.GivePlayerPvPScore(attacker, victim, score);
                    output.VictimLog   += PlayerProcedures.RemovePlayerPvPScore(victim, attacker, score);

                    StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__DungeonPointsStolen, (float)score);
                }
                else
                {
                    output.AttackerLog += $"  {victim.GetFullName()} unfortunately did not have any dungeon points for you to steal for yourself.";
                }
            }

            // Call out a player for being the monster they are when they defeat the plush angel.
            if (victim.BotId == AIStatics.MinibossPlushAngelId)
            {
                output.AttackerLog += "<br><br>Why did you do that to the poor plush? They just wanted to be a friend!<br>";
                output.LocationLog += $"<br><b>{attacker.GetFullName()}</b> went and bullied <b>{victim.GetFullName()}</b>, like some <b>monster</b>. The angelic plush left some flowers to the 'victor', in hope they would forgive it despite doing no wrong.";

                // Give the dummy a bit of madness for being a bully.
                EffectProcedures.GivePerkToPlayer(198, attacker);
            }

            // Heals the victorious player provided that the target was eligible
            if (attacker.BotId == AIStatics.ActivePlayerBotId)
            {
                // Provide no healing if the victim shared a coven with the attacker
                if (attacker.Covenant != null && attacker.Covenant == victim.Covenant)
                {
                    output.AttackerLog += "  <br>There is no glory to be had in this victory, your willpower & mana are not restored.";
                }
                else
                {
                    // Figure out the modifier to be used
                    double modifier = (levelDifference * 5) / 100;
                    // Cap the modifier to prevent too much / too little healing.
                    if (modifier > 0.3)
                    {
                        modifier = 0.3;
                    }
                    if (modifier < -0.55)
                    {
                        modifier = -0.55;
                    }
                    decimal healingPercent = (decimal)(0.6 + modifier);

                    if (victim.BotId != AIStatics.ActivePlayerBotId)
                    {
                        // The victim is not a player, provide half of the healing.
                        healingPercent /= 2;
                    }

                    // Heal the attacker and restore their Mana
                    var healingTotal      = attacker.MaxHealth * healingPercent;
                    var manaRestoredTotal = attacker.MaxMana * healingPercent;
                    PlayerProcedures.ChangePlayerActionMana(0, healingTotal, manaRestoredTotal, attacker.Id, false);

                    // Remove any Self Restore entires.
                    RemoveSelfRestore(victim);

                    output.AttackerLog += $"<br />Invigorated by your victory and fuelled by the scattered essence that was once your foe, you are healed for {healingTotal:#} willpower and {manaRestoredTotal:#} mana.";
                }
            }

            output.AttackerLog += $"  You collect {Math.Round(moneygain, 0)} Arpeyjis your victim dropped during the transformation.";

            // create inanimate XP for the victim
            InanimateXPProcedures.GetStruggleChance(victim, false);

            // if this victim is a bot, clear out some old stuff that is not needed anymore
            if (victim.BotId < AIStatics.ActivePlayerBotId)
            {
                AIDirectiveProcedures.DeleteAIDirectiveByPlayerId(victim.Id);
                PlayerLogProcedures.ClearPlayerLog(victim.Id);
            }

            TFEnergyProcedures.DeleteAllPlayerTFEnergiesOfFormSourceId(victim.Id, targetForm.Id);

            // if the attacker is a psycho, have them change to a new spell and equip whatever they just earned
            if (attacker.BotId == AIStatics.PsychopathBotId)
            {
                SkillProcedures.DeletePlayerSkill(attacker, skillSourceId);

                if (targetForm.MobilityType == PvPStatics.MobilityInanimate || targetForm.MobilityType == PvPStatics.MobilityPet)
                {
                    if (attacker.MembershipId.IsNullOrEmpty())
                    {
                        // give this bot a random replacement inanimate/pet skill
                        var eligibleSkills = SkillStatics.GetLearnablePsychopathSkills().ToList();
                        var rand           = new Random();
                        var skillToLearn   = eligibleSkills.ElementAt(rand.Next(eligibleSkills.Count));
                        SkillProcedures.GiveSkillToPlayer(attacker.Id, skillToLearn.Id);
                    }
                    else
                    {
                        // Bot is being controlled by a player - re-add the original skill so only the ordering of skills changes
                        SkillProcedures.GiveSkillToPlayer(attacker.Id, skillSourceId);
                    }
                }
            }
        }