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); } }
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!"); }
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.."); }
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); } } } }