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 (bool, LogBox) AddTFEnergyToPlayer(Player victim, Player attacker, SkillViewModel skill, decimal modifier, decimal victimHealthBefore) { var output = new LogBox { AttackerLog = " ", VictimLog = " " }; var victimMaxHealth = victim.MaxHealth; // Remember this before any form change can affect it // Move old energy to pool, add pool energy to the current attack (var energyBefore, var energyAfter) = AccumulateTFEnergy(victim, attacker, skill, modifier); var eventualForm = FormStatics.GetForm(skill.StaticSkill.FormSourceId.Value); var energyAmount = $" [{energyAfter:0.00} / {eventualForm.TFEnergyRequired:0.00} TF energy]<br />"; output.AttackerLog += energyAmount; output.VictimLog += energyAmount; // Return early if victim is already in the target form if (victim.FormSourceId == eventualForm.Id && victim.Mobility == eventualForm.MobilityType) { var noTransformMessage = $"Since {victim.GetFullName()} is already in this form, the spell has no transforming effect."; output.AttackerLog += noTransformMessage; output.VictimLog += noTransformMessage; return(false, output); } // Perform any form change logic (inc extra health damage) var formChangeLog = new LogBox(); var(complete, victimHealthAfter) = TFEnergyProcedures.RunFormChangeLogic(victim, attacker.Id, skill, energyAfter, formChangeLog); // Add the spell text to the player logs (now that we know the full damage of this hit) var percentTransformedBefore = CalculateTransformationProgress(victimHealthBefore, victimMaxHealth, energyBefore, eventualForm); var percentTransformedAfter = CalculateTransformationProgress(victimHealthAfter, victimMaxHealth, energyAfter, eventualForm); LogTransformationMessages(victim, attacker, eventualForm, percentTransformedBefore, percentTransformedAfter, output); // Append energy overflow damage and form change output from earlier output.Add(formChangeLog); // Only give XP if attacker and victim are not part of the same covenant if (attacker.Covenant == null || attacker.Covenant != victim.Covenant) { AwardXP(victim, attacker, eventualForm.MobilityType, output); } return(complete, output); }
private static void PerformAnimateTransformation(Player victim, Player attacker, DbStaticForm targetForm, LogBox output) { var playerRepo = new EFPlayerRepository(); var dbVictim = playerRepo.Players.FirstOrDefault(p => p.Id == victim.Id); SkillProcedures.UpdateFormSpecificSkillsToPlayer(dbVictim, targetForm.Id); DomainRegistry.Repository.Execute(new ChangeForm { PlayerId = dbVictim.Id, FormSourceId = targetForm.Id }); // wipe out half of the target's mana dbVictim.Mana -= dbVictim.MaxMana / 2; if (dbVictim.Mana < 0) { dbVictim.Mana = 0; } // Remove any Self Restore entires. RemoveSelfRestore(dbVictim); var targetbuffs = ItemProcedures.GetPlayerBuffs(dbVictim); dbVictim = PlayerProcedures.ReadjustMaxes(dbVictim, targetbuffs); // take away some of the victim's XP based on the their level // target.XP += -2.5M * target.Level; playerRepo.SavePlayer(dbVictim); output.LocationLog += $"<br><b>{dbVictim.GetFullName()} was completely transformed into a {targetForm.FriendlyName} here.</b>"; output.AttackerLog += $"<br><b>You fully transformed {dbVictim.GetFullName()} into a {targetForm.FriendlyName}</b>!"; output.VictimLog += $"<br><b>You have been fully transformed into a {targetForm.FriendlyName}!</b>"; // Let the target know they are best friends with the angel plush. if (attacker.BotId == AIStatics.MinibossPlushAngelId) { output.VictimLog += $"<br><br><b>{attacker.GetFullName()}</b> was happy to make you into a new friend!<br>"; } TFEnergyProcedures.DeleteAllPlayerTFEnergiesOfFormSourceId(dbVictim.Id, targetForm.Id); StatsProcedures.AddStat(dbVictim.MembershipId, StatsProcedures.Stat__TimesAnimateTFed, 1); StatsProcedures.AddStat(attacker.MembershipId, StatsProcedures.Stat__TimesAnimateTFing, 1); }
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); }
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); } } } }