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); } }
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); } }
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"); }
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); } } }
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); }
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 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); }
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)}%]"); } }
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); } } } }