コード例 #1
0
        public virtual ActionResult ArchiveSpell(int skillSourceId)
        {
            var myMembershipId = User.Identity.GetUserId();
            var me             = PlayerProcedures.GetPlayerFromMembership(myMembershipId);
            // assert that player does own this skill
            var skill = SkillProcedures.GetSkillViewModel(skillSourceId, me.Id);

            if (skill == null)
            {
                TempData["Error"] = "You don't know this spell yet.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            if (skill.dbSkill.SkillSourceId == PvPStatics.Spell_WeakenId)
            {
                ViewBag.Message = $"You can't archive the {skill.StaticSkill.FriendlyName} skill.";
                return(PartialView(MVC.Settings.Views.partial.ArchiveNotice));
            }

            SkillProcedures.ArchiveSpell(skill.dbSkill.Id);

            if (!skill.dbSkill.IsArchived)
            {
                ViewBag.Message = "You have successfully archived " + skill.StaticSkill.FriendlyName + ".";
            }
            else
            {
                ViewBag.Message = "You have successfully restored " + skill.StaticSkill.FriendlyName + " from your spell archive.";
            }
            ViewBag.Number = skill.dbSkill.Id;
            return(PartialView(MVC.Settings.Views.partial.ArchiveNotice));
        }
コード例 #2
0
        public static string LearnSpell(Player player, Random rand = null)
        {
            rand = rand ?? new Random();
            var num    = rand.Next(3) + 1;
            var learnt = SkillProcedures.GiveRandomFindableSkillsToPlayer(player, num);

            if (learnt.IsEmpty())
            {
                return(null);
            }

            return($"A spellbook flies off the shelf and lands open on the wooden desk in front of you.  As you look at it you discover the secret incantations for the spells {ListifyHelper.Listify(learnt, true)}!");
        }
コード例 #3
0
        public static string ForceAttack(Player attacker, bool strongAttackerAlerts = false, Random rand = null)
        {
            if (attacker.TimesAttackingThisUpdate >= PvPStatics.MaxAttacksPerUpdate)
            {
                return(null);
            }

            if (attacker.GameMode != (int)GameModeStatics.GameModes.PvP)
            {
                return(null);
            }

            rand = rand ?? new Random();
            var candidates = JokeShopProcedures.ActivePlayersInJokeShopApartFrom(attacker)
                             .Where(p => p.GameMode == (int)GameModeStatics.GameModes.PvP &&
                                    JokeShopProcedures.PlayerHasBeenWarned(p)).ToList();

            if (candidates == null || candidates.IsEmpty())
            {
                return(null);
            }

            var victim = candidates[rand.Next(candidates.Count())];

            var spells = SkillProcedures.AvailableSkills(attacker, victim, true);

            if (spells == null || spells.IsEmpty())
            {
                return(null);
            }

            var spellList = spells.ToArray();
            var spell     = spellList[rand.Next(spellList.Count())];

            var message = $"You are compelled to attack {victim.GetFullName()}!";

            PlayerLogProcedures.AddPlayerLog(attacker.Id, message, strongAttackerAlerts);
            PlayerLogProcedures.AddPlayerLog(victim.Id, $"{attacker.GetFullName()} is compelled to attack you!", true);
            LocationLogProcedures.AddLocationLog(attacker.dbLocationName, $"{attacker.GetFullName()} is compelled to attack {victim.GetFullName()}!");

            // Note we do not apply the full gamut of preconditions of a manual attack present in the controller
            var attack = AttackProcedures.AttackSequence(attacker, victim, spell, false);

            if (strongAttackerAlerts)
            {
                PlayerLogProcedures.AddPlayerLog(attacker.Id, attack, true);
            }

            return($"{message}<br />{attack}");
        }
コード例 #4
0
        private static bool Teleport(Player player, string location, bool logLocations)
        {
            if (location == null)
            {
                return(false);
            }

            var destination = LocationsStatics.LocationList.GetLocation.FirstOrDefault(l => l.dbName == location);

            if (destination == null)
            {
                return(false);
            }

            if (player.InDuel > 0 || player.InQuest > 0 || player.MindControlIsActive || player.MoveActionPointDiscount < -TurnTimesStatics.GetActionPointReserveLimit())
            {
                return(false);
            }

            if (ItemProcedures.GetAllPlayerItems(player.Id).Count(i => !i.dbItem.IsEquipped) > PvPStatics.MaxCarryableItemCountBase + player.ExtraInventory)
            {
                // Carryiing too much
                return(false);
            }

            if (destination.dbName.Contains("dungeon_"))
            {
                SkillProcedures.GiveSkillToPlayer(player.Id, PvPStatics.Dungeon_VanquishSpellSourceId);
            }

            PlayerProcedures.MovePlayer_InstantNoLog(player.Id, location);

            if (logLocations)
            {
                LocationLogProcedures.AddLocationLog(player.dbLocationName, $"Strange forces propel {player.GetFullName()} off to {destination.Name}!");
            }
            else
            {
                LocationLogProcedures.AddLocationLog(player.dbLocationName, $"{player.GetFullName()} is whisked off to a faraway place!");
            }
            LocationLogProcedures.AddLocationLog(location, $"{player.GetFullName()} is surprised to find they are suddenly here!");
            PlayerLogProcedures.AddPlayerLog(player.Id, $"You are sent to {destination.Name}", false);

            return(true);
        }
コード例 #5
0
        public virtual ActionResult ArchiveAllMySpells(string archive)
        {
            var myMembershipId = User.Identity.GetUserId();
            var me             = PlayerProcedures.GetPlayerFromMembership(myMembershipId);

            if (archive == "true")
            {
                SkillProcedures.ArchiveAllSpells(me.Id, true);
                TempData["Result"] = "You have archived all of your known spells.  They will not appear on the attack modal until you unarchive them.";
            }
            else
            {
                SkillProcedures.ArchiveAllSpells(me.Id, false);
                TempData["Result"] = "You have unarchived all of your known spells.  They will all now appear on the attack modal again.";
            }


            return(RedirectToAction(MVC.PvP.Play()));
        }
コード例 #6
0
        public static string UnlearnSpell(Player player, Random rand = null, int number = 1)
        {
            rand = rand ?? new Random();

            var skills = SkillProcedures.GetSkillViewModelsOwnedByPlayer(player.Id)
                         .Where(s => s.StaticSkill.IsPlayerLearnable &&
                                !s.StaticSkill.ExclusiveToFormSourceId.HasValue &&
                                !s.StaticSkill.ExclusiveToItemSourceId.HasValue &&
                                s.StaticSkill.Id != PvPStatics.Spell_WeakenId &&
                                s.StaticSkill.Id != PvPStatics.Dungeon_VanquishSpellSourceId &&
                                s.StaticSkill.Id != BossProcedures_FaeBoss.SpellUsedAgainstNarcissaSourceId &&
                                (s.StaticSkill.LearnedAtLocation ?? s.StaticSkill.LearnedAtRegion) != null);

            if (skills.IsEmpty())
            {
                return(null);
            }

            var toRemove  = new List <int>();
            var numSkills = skills.Count();

            while (toRemove.Count() < number && toRemove.Count() < numSkills)
            {
                var index = rand.Next(numSkills);

                if (!toRemove.Contains(index))
                {
                    toRemove.Add(index);
                }
            }

            var skillsToRemove = ListifyHelper.Listify(toRemove.Select(s => skills.ElementAt(s).StaticSkill.FriendlyName).ToList(), true);
            var message        = $"The strange aura of the Joke Shop causes you to forget how to cast {skillsToRemove}!";

            ISkillRepository skillRepo = new EFSkillRepository();

            toRemove.ForEach(s => skillRepo.DeleteSkill(skills.ElementAt(s).dbSkill.Id));

            return(message);
        }
コード例 #7
0
        public static string TeleportToHostileNPC(Player player, bool attack, Random rand = null)
        {
            var targetFormSourceId = -1;
            var minLevel           = 4;

            IPlayerRepository playerRepo = new EFPlayerRepository();

            // Bosses
            var hostiles = playerRepo.Players.Where(p => p.Mobility == PvPStatics.MobilityFull && (
                                                        p.BotId == AIStatics.BimboBossBotId ||
                                                        p.BotId == AIStatics.DonnaBotId ||
                                                        p.BotId == AIStatics.FaebossBotId ||
                                                        p.BotId == AIStatics.MotorcycleGangLeaderBotId ||
                                                        p.BotId == AIStatics.MouseBimboBotId ||
                                                        p.BotId == AIStatics.MouseNerdBotId ||
                                                        p.BotId == AIStatics.FemaleRatBotId ||
                                                        p.BotId == AIStatics.MaleRatBotId ||
                                                        p.BotId == AIStatics.ValentineBotId)).ToList();

            // Minibosses
            if (hostiles == null || hostiles.IsEmpty())
            {
                hostiles = playerRepo.Players.Where(p => p.Mobility == PvPStatics.MobilityFull && (
                                                        p.BotId == AIStatics.MinibossPlushAngelId ||
                                                        p.BotId == AIStatics.MinibossArchangelId ||
                                                        p.BotId == AIStatics.MinibossArchdemonId ||
                                                        p.BotId == AIStatics.MinibossExchangeProfessorId ||
                                                        p.BotId == AIStatics.MinibossFiendishFarmhandId ||
                                                        p.BotId == AIStatics.MinibossGroundskeeperId ||
                                                        p.BotId == AIStatics.MinibossLazyLifeguardId ||
                                                        p.BotId == AIStatics.MinibossPopGoddessId ||
                                                        p.BotId == AIStatics.MinibossPossessedMaidId ||
                                                        p.BotId == AIStatics.MinibossSeamstressId ||
                                                        p.BotId == AIStatics.MinibossSororityMotherId)).ToList();
            }

            rand = rand ?? new Random();
            Player npcPlayer = null;

            if (hostiles != null && hostiles.Any())
            {
                npcPlayer = hostiles[rand.Next(hostiles.Count())];
            }

            // Psychopaths
            if (npcPlayer == null)
            {
                npcPlayer = playerRepo.Players.Where(p => p.Mobility == PvPStatics.MobilityFull &&
                                                     p.BotId == AIStatics.PsychopathBotId &&
                                                     p.Level <= player.Level)
                            .OrderByDescending(p => p.Level).FirstOrDefault();
                minLevel = 1;
            }

            if (npcPlayer == null)
            {
                return(null);
            }

            // Turn into form needed to attack
            if (npcPlayer.BotId == AIStatics.MouseBimboBotId)
            {
                targetFormSourceId = BossProcedures_Sisters.NerdSpellFormSourceId;
            }
            else if (npcPlayer.BotId == AIStatics.MouseNerdBotId)
            {
                targetFormSourceId = BossProcedures_Sisters.BimboSpellFormSourceId;
            }

            if (targetFormSourceId != -1)
            {
                CharacterPrankProcedures.TryAnimateTransform(player, targetFormSourceId);
            }

            // Move to same tile as NPC
            if (!Teleport(player, npcPlayer.dbLocationName, rand.Next(2) == 0))
            {
                return(null);
            }

            var message = "The shop suddenly seems to connect with some evil force.  A vortex opens and you are pulled in towards the source of the magic!";

            if (attack && player.Level >= minLevel)
            {
                var spells = SkillProcedures.AvailableSkills(player, npcPlayer, true);
                if (spells != null && spells.Any())
                {
                    var spellList = spells.ToArray();
                    var spell     = spellList[rand.Next(spellList.Count())];

                    // Note we do not apply the full gamut of preconditions of a manual attack present in the controller
                    var attackMessage = AttackProcedures.AttackSequence(player, npcPlayer, spell);
                    message = $"{message}<br />{attackMessage}";
                }
            }

            return(message);
        }
コード例 #8
0
        public virtual ActionResult SelfCastSend(int itemId, int skillSourceId)
        {
            var myMembershipId = User.Identity.GetUserId();
            var me             = PlayerProcedures.GetPlayerFromMembership(myMembershipId);

            // assert player is animate
            if (me.Mobility != PvPStatics.MobilityFull)
            {
                TempData["Error"] = "You must be animate in order to use this.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert that this player is not in a duel
            if (me.InDuel > 0)
            {
                TempData["Error"] = "You must finish your duel before you use this item.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert that this player is not in a quest
            if (me.InQuest > 0)
            {
                TempData["Error"] = "You must finish your quest before you use this item.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert player has not already used an item this turn
            if (me.ItemsUsedThisTurn >= PvPStatics.MaxItemUsesPerUpdate)
            {
                TempData["Error"]    = "You've already used an item this turn.";
                TempData["SubError"] = "You will be able to use another consumable type item next turn.";
                return(RedirectToAction(MVC.Item.MyInventory()));
            }

            var item = ItemProcedures.GetItemViewModel(itemId);

            // assert player does own this
            if (item.dbItem.OwnerId != me.Id)
            {
                TempData["Error"] = "You don't own that item.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert that it is equipped
            if (!item.dbItem.IsEquipped)
            {
                TempData["Error"] = "You cannot use an item you do not have equipped.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert this item is a transmog
            if (item.dbItem.ItemSourceId != ItemStatics.AutoTransmogItemSourceId)
            {
                TempData["Error"] = "You cannot change form with that item.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert player does own this skill
            var skill = SkillProcedures.GetSkillViewModel(skillSourceId, me.Id);

            if (skill == null)
            {
                TempData["Error"] = "You do not own this spell.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert desired form is animate
            if (skill.MobilityType != PvPStatics.MobilityFull)
            {
                TempData["Error"] = "The target form must be an animate form.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            // assert player is not already in the form of the spell
            if (me.FormSourceId == skill.StaticSkill.FormSourceId)
            {
                TempData["Error"] = "You are already in the target form of that spell, so doing this would do you no good.";
                return(RedirectToAction(MVC.PvP.Play()));
            }

            PlayerProcedures.InstantChangeToForm(me, skill.StaticSkill.FormSourceId.Value);
            ItemProcedures.DeleteItem(itemId);

            PlayerProcedures.SetTimestampToNow(me);
            PlayerProcedures.AddItemUses(me.Id, 1);

            var form = FormStatics.GetForm(skill.StaticSkill.FormSourceId.Value);

            TempData["Result"] = "You use a " + item.Item.FriendlyName + ", your spell bouncing through the device for a second before getting flung back at you and hitting you square in the chest, instantly transforming you into a " + form.FriendlyName + "!";

            StatsProcedures.AddStat(me.MembershipId, StatsProcedures.Stat__TransmogsUsed, 1);

            return(RedirectToAction(MVC.PvP.Play()));
        }
コード例 #9
0
        public static string SummonDoppelganger(Player player, Random rand = null, bool?aggro = null)
        {
            rand = rand ?? new Random();

            IPlayerRepository playerRepo = new EFPlayerRepository();
            var cmd = new CreatePlayer
            {
                FirstName          = $"Evil {player.FirstName}",
                LastName           = player.LastName,
                Location           = player.dbLocationName,
                FormSourceId       = player.FormSourceId,
                Level              = Math.Min(9, player.Level),
                Health             = player.Health,
                MaxHealth          = player.MaxHealth,
                Mana               = player.Mana,
                MaxMana            = player.MaxMana,
                BotId              = AIStatics.PsychopathBotId,
                UnusedLevelUpPerks = 0,
                XP     = 0,
                Money  = 100 + player.Money / 10,
                Gender = player.Gender,
            };

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

            // Give spells
            var eligibleSkills = SkillStatics.GetLearnablePsychopathSkills().ToList();

            SkillProcedures.GiveSkillToPlayer(botId, eligibleSkills[rand.Next(eligibleSkills.Count())].Id);
            SkillProcedures.GiveSkillToPlayer(botId, PvPStatics.Spell_WeakenId);

            // Give bonuses - we exclude some with no stats, with side effects, or that serve no purpose on psychos
            var sourcePerks = EffectProcedures.GetPlayerEffects2(player.Id);

            int[] effectsToExclude = { JokeShopProcedures.FIRST_WARNING_EFFECT,
                                       JokeShopProcedures.SECOND_WARNING_EFFECT,
                                       JokeShopProcedures.BANNED_FROM_JOKE_SHOP_EFFECT,
                                       JokeShopProcedures.INVISIBILITY_EFFECT,  // Ensure twin is visible, even if player can't yet attack
                                       JokeShopProcedures.PSYCHOTIC_EFFECT,     // Prevent psycho twin leaving rehab  (Sorry, Pinocchio)
                                       JokeShopProcedures.INSTINCT_EFFECT,      // Should be safe, but just to be on the safe side
                                       JokeShopProcedures.AUTO_RESTORE_EFFECT,  // No free second chances for twins, bad ends are forever
            };

            foreach (var sourcePerk in sourcePerks)
            {
                var effect = sourcePerk.dbEffect;
                if (!effectsToExclude.Contains(effect.EffectSourceId) && effect.Duration > 0)
                {
                    EffectProcedures.GivePerkToPlayer(effect.EffectSourceId, botId, effect.Duration, effect.Cooldown);
                }
            }

            // Approximately mirror the buffs the player gets from their items.
            // (Actually equipping equivalent items and runes could easily be abused so use perks)
            var itemBuffs = ItemProcedures.GetPlayerBuffs(player).ItemBuffs();

            itemBuffs += 30;  // level 1 psycho effect gives -30 stats
            if (itemBuffs >= 315)
            {
                itemBuffs -= 315;
                EffectProcedures.GivePerkToPlayer(AIProcedures.PsychopathicForLevelNineEffectSourceId, botId);
            }
            if (itemBuffs >= 225)
            {
                itemBuffs -= 225;
                EffectProcedures.GivePerkToPlayer(AIProcedures.PsychopathicForLevelSevenEffectSourceId, botId);
            }
            if (itemBuffs >= 135)
            {
                itemBuffs -= 135;
                EffectProcedures.GivePerkToPlayer(AIProcedures.PsychopathicForLevelFiveEffectSourceId, botId);
            }
            if (itemBuffs >= 70)
            {
                itemBuffs -= 70;
                EffectProcedures.GivePerkToPlayer(AIProcedures.PsychopathicForLevelThreeEffectSourceId, botId);
            }
            if (itemBuffs < 30)
            {
                itemBuffs += 30;
                EffectProcedures.GivePerkToPlayer(AIProcedures.PsychopathicForLevelOneEffectSourceId, botId);
            }

            // Give runes (round level down to odd)
            var runeLevel = cmd.Level - 1;

            runeLevel = runeLevel - (runeLevel % 2) + 1;
            var quantity = rand.Next(1, 3);

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

            // Balance stats
            var psychoEF = playerRepo.Players.FirstOrDefault(p => p.Id == botId);

            psychoEF.ReadjustMaxes(ItemProcedures.GetPlayerBuffs(psychoEF));
            playerRepo.SavePlayer(psychoEF);

            // Tell the bot to attack the player
            if (!aggro.HasValue || aggro.Value)
            {
                AIDirectiveProcedures.SetAIDirective_Attack(botId, player.Id);
            }

            PlayerLogProcedures.AddPlayerLog(player.Id, $"<b>You have summoned your evil twin!</b>  Beware!  They are not friendly!", true);
            LocationLogProcedures.AddLocationLog(player.dbLocationName, $"{player.GetFullName()} has summoned their evil twin!");

            return("In the corner of the room is a freestanding mirror with a silver gilt frame.  You smear some of the dust off the glass to see your reflection staring back at you through the clearing in the misty haze.  As you look into it you catch sight of yourself twitching slightly, but you don't actually feel anything.  Then your reflection narrows their gaze into a scowl and steps through the rippling glazed portal, bringing you face-to-face with your mirror self!  You should be careful.  Meeting your doppelganger never ends well..");
        }
コード例 #10
0
        public static string SummonPsychopath(Player player, Random rand = null, int?strengthOverride = null, bool?aggro = null)
        {
            rand = rand ?? new Random();

            var baseStrength = Math.Min(Math.Max(0, (player.Level - 1) / 3), 3);
            var strength     = strengthOverride ?? (baseStrength + Math.Max(0, rand.Next(6) - 1));

            var prefix = "";
            int level;
            int perk;
            int?extraPerk = null;
            var gender    = rand.Next(2);
            int form;

            var turnNumber = PvPWorldStatProcedures.GetWorldTurnNumber();

            if (strength <= 0 || (turnNumber < 300 && !strengthOverride.HasValue))
            {
                strength = 0;
                level    = 1;
                perk     = AIProcedures.PsychopathicForLevelOneEffectSourceId;
                form     = gender == 0 ? AIProcedures.Psycho1MId : AIProcedures.Psycho1FId;
            }
            else if (strength == 1 || (turnNumber < 600 && !strengthOverride.HasValue))
            {
                strength = 1;
                level    = 3;
                prefix   = "Fierce";
                perk     = AIProcedures.PsychopathicForLevelThreeEffectSourceId;
                form     = gender == 0 ? AIProcedures.Psycho3MId : AIProcedures.Psycho3FId;
            }
            else if (strength == 2 || (turnNumber < 900 && !strengthOverride.HasValue))
            {
                strength = 2;
                level    = 5;
                prefix   = "Wrathful";
                perk     = AIProcedures.PsychopathicForLevelFiveEffectSourceId;
                form     = gender == 0 ? AIProcedures.Psycho5MId : AIProcedures.Psycho5FId;
            }
            else if (strength == 3 || (turnNumber < 1500 && !strengthOverride.HasValue))
            {
                strength = 3;
                level    = 7;
                prefix   = "Loathful";
                perk     = AIProcedures.PsychopathicForLevelSevenEffectSourceId;
                form     = gender == 0 ? AIProcedures.Psycho7MId : AIProcedures.Psycho7FId;
            }
            else if (strength == 4 || (turnNumber < 2400 && !strengthOverride.HasValue))
            {
                strength = 4;
                level    = 9;
                prefix   = "Soulless";
                perk     = AIProcedures.PsychopathicForLevelNineEffectSourceId;
                form     = gender == 0 ? AIProcedures.Psycho9MId : AIProcedures.Psycho9FId;
            }
            else if (strength == 5 || (turnNumber < 3600 && !strengthOverride.HasValue))
            {
                strength  = 5;
                level     = 11;
                prefix    = "Ruthless";
                perk      = AIProcedures.PsychopathicForLevelNineEffectSourceId;
                extraPerk = AIProcedures.PsychopathicForLevelThreeEffectSourceId;
                form      = gender == 0 ? AIProcedures.Psycho9MId : AIProcedures.Psycho9FId;
            }
            else
            {
                strength  = 6;
                level     = 13;
                prefix    = "Eternal";
                perk      = AIProcedures.PsychopathicForLevelNineEffectSourceId;
                extraPerk = AIProcedures.PsychopathicForLevelFiveEffectSourceId;
                form      = gender == 0 ? AIProcedures.Psycho9MId : AIProcedures.Psycho9FId;
            }

            var firstName = "Psychopath";
            var lastName  = NameService.GetRandomLastName();

            if (!prefix.IsEmpty())
            {
                firstName = $"{prefix} {firstName}";
            }

            IPlayerRepository playerRepo = new EFPlayerRepository();
            var cmd = new CreatePlayer
            {
                FirstName          = firstName,
                LastName           = lastName,
                Location           = player.dbLocationName,
                FormSourceId       = form,
                Level              = level,
                Health             = 100000,
                MaxHealth          = 100000,
                Mana               = 100000,
                MaxMana            = 100000,
                BotId              = AIStatics.PsychopathBotId,
                UnusedLevelUpPerks = 0,
                XP     = 0,
                Money  = (strength + 1) * 50,
                Gender = gender == 0 ? PvPStatics.GenderMale : PvPStatics.GenderFemale,
            };

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

            // Give spells
            var eligibleSkills = SkillStatics.GetLearnablePsychopathSkills().ToList();

            SkillProcedures.GiveSkillToPlayer(botId, eligibleSkills[rand.Next(eligibleSkills.Count())].Id);

            if (strength >= 5)
            {
                SkillProcedures.GiveSkillToPlayer(botId, PvPStatics.Spell_WeakenId);
            }

            if (strength >= 6)
            {
                var limitedMobilityForms = JokeShopProcedures.AnimateForms().Where(f => f.Category == JokeShopProcedures.LIMITED_MOBILITY).ToArray();

                if (limitedMobilityForms.Any())
                {
                    IDbStaticSkillRepository skillsRepo = new EFDbStaticSkillRepository();

                    var formId        = limitedMobilityForms[rand.Next(limitedMobilityForms.Count())].FormSourceId;
                    var immobileSkill = skillsRepo.DbStaticSkills.FirstOrDefault(spell => spell.FormSourceId == formId);

                    if (immobileSkill != null)
                    {
                        SkillProcedures.GiveSkillToPlayer(botId, immobileSkill.Id);
                    }
                }
            }

            // Give bonuses
            EffectProcedures.GivePerkToPlayer(perk, botId);

            if (extraPerk.HasValue)
            {
                EffectProcedures.GivePerkToPlayer(extraPerk.Value, botId);
            }

            // Give runes
            var quantity = rand.Next(1, 3);

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

            // Balance stats
            var psychoEF = playerRepo.Players.FirstOrDefault(p => p.Id == botId);

            psychoEF.ReadjustMaxes(ItemProcedures.GetPlayerBuffs(psychoEF));
            playerRepo.SavePlayer(psychoEF);

            // Tell the bot to attack the player
            if (!aggro.HasValue || aggro.Value)
            {
                AIDirectiveProcedures.SetAIDirective_Attack(botId, player.Id);
            }

            PlayerLogProcedures.AddPlayerLog(player.Id, $"<b>You have summoned {firstName} {lastName}!</b>  Beware!  They are not friendly!!", true);
            LocationLogProcedures.AddLocationLog(player.dbLocationName, $"{player.GetFullName()} has summoned <b>{firstName} {lastName}</b>!");

            return("Near the counter is an altar with a leather-bound book resting open upon it.  You take a look and try to read one of the jokes aloud.  It seems to be some consonant-heavy tongue twister that soon leaves you faltering.  You're not quite sure what the set up means, but hope the punchline will be worth it.  As you spurt out the last syllable a puff of red smoke explodes out from the book with an audible bang.  You're not laughing, and that remains the case when you close the book to see a large pentagram seared into the cover.  As the smoke subsides there seems to be a strange neon flicker to the light and a crackling to the air.  You turn sharply to see the psychopath you just summoned readying their attack against you!");
        }