using System; using System.Threading; using System.Threading.Tasks; using PhoenixLib.DAL.Redis.Locks; using PhoenixLib.Events; using WingsEmu.DTOs.Maps; using WingsEmu.Game._i18n; using WingsEmu.Game.Act4.Configuration; using WingsEmu.Game.Act4.Event; using WingsEmu.Game.Battle; using WingsEmu.Game.Buffs; using WingsEmu.Game.Characters; using WingsEmu.Game.Characters.Events; using WingsEmu.Game.Configurations; using WingsEmu.Game.Entities; using WingsEmu.Game.Entities.Extensions; using WingsEmu.Game.Extensions; using WingsEmu.Game.Managers; using WingsEmu.Game.Maps; using WingsEmu.Game.Mates; using WingsEmu.Game.Networking; using WingsEmu.Game.Networking.Broadcasting; using WingsEmu.Game.Revival; using WingsEmu.Packets.Enums; using WingsEmu.Packets.Enums.Chat; namespace Plugin.Act4.Event; public class RevivalStartProcedureEventAct4Handler : IAsyncEventProcessor { private readonly Act4Configuration _act4Configuration; private readonly IAsyncEventPipeline _asyncEventPipeline; private readonly IGameLanguageService _languageService; private readonly IExpirableLockService _lockService; private readonly GameMinMaxConfiguration _minMaxConfiguration; private readonly IRankingManager _rankingManager; private readonly IReputationConfiguration _reputationConfiguration; private readonly PlayerRevivalConfiguration _revivalConfiguration; private readonly ISessionManager _sessionManager; public RevivalStartProcedureEventAct4Handler(GameRevivalConfiguration gameRevivalConfiguration, Act4Configuration act4Configuration, IAsyncEventPipeline asyncEventPipeline, GameMinMaxConfiguration minMaxConfiguration, IGameLanguageService languageService, ISessionManager sessionManager, IReputationConfiguration reputationConfiguration, IRankingManager rankingManager, IExpirableLockService lockService) { _act4Configuration = act4Configuration; _asyncEventPipeline = asyncEventPipeline; _minMaxConfiguration = minMaxConfiguration; _languageService = languageService; _sessionManager = sessionManager; _reputationConfiguration = reputationConfiguration; _rankingManager = rankingManager; _lockService = lockService; _revivalConfiguration = gameRevivalConfiguration.PlayerRevivalConfiguration; } public async Task HandleAsync(RevivalStartProcedureEvent e, CancellationToken cancellation) { IClientSession session = e.Sender; IBattleEntity killer = e.Killer; if (session.PlayerEntity.IsAlive()) { return; } if (!session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4)) { return; } if (session.CurrentMapInstance.MapInstanceType == MapInstanceType.Act4Dungeon) { return; } if (session.PlayerEntity.IsOnVehicle) { await session.EmitEventAsync(new RemoveVehicleEvent()); } await session.PlayerEntity.RemoveBuffsOnDeathAsync(); session.RefreshStat(); if (killer?.Faction != session.PlayerEntity.Faction) { IPlayerEntity playerEntity = killer switch { IPlayerEntity player => player, IMateEntity mateEntity => mateEntity.Owner, IMonsterEntity monsterEntity => monsterEntity.SummonerType is VisualType.Player && monsterEntity.SummonerId.HasValue ? monsterEntity.MapInstance.GetCharacterById(monsterEntity.SummonerId.Value) : null, _ => null }; if (playerEntity != null) { if (!session.PlayerEntity.IsGettingLosingReputation) { if (session.PlayerEntity.DeathsOnAct4 < 10) { session.PlayerEntity.DeathsOnAct4++; } else { session.PlayerEntity.IsGettingLosingReputation = true; await _lockService.TryAddTemporaryLockAsync($"game:locks:character:{session.PlayerEntity.Id}:act-4-less-rep", DateTime.UtcNow.Date.AddDays(1)); session.SendChatMessage(session.GetLanguage(GameDialogKey.ACT4_CHATMESSAGE_LESS_REPUTATION), ChatMessageColorType.Red); } } else { session.SendChatMessage(session.GetLanguage(GameDialogKey.ACT4_CHATMESSAGE_LESS_REPUTATION), ChatMessageColorType.Red); } await HandleReputation(session, playerEntity); await playerEntity.Session.EmitEventAsync(new Act4KillEvent { TargetId = session.PlayerEntity.Id }); playerEntity.Act4Kill++; session.PlayerEntity.Act4Dead++; playerEntity.Session.SendChatMessage(playerEntity.Session.GetLanguageFormat(GameDialogKey.ACT4_CHATMESSAGE_KILL_INFO, playerEntity.Act4Kill, playerEntity.Act4Dead), ChatMessageColorType.Yellow); session.SendChatMessage(session.GetLanguageFormat(GameDialogKey.ACT4_CHATMESSAGE_KILL_INFO, session.PlayerEntity.Act4Kill, session.PlayerEntity.Act4Dead), ChatMessageColorType.Yellow); switch (session.PlayerEntity.Faction) { case FactionType.Angel: // For every demon, send "killer killed an angel" _sessionManager.Broadcast(x => { string factionKey = _languageService.GetLanguage(GameDialogKey.ACT4_CHATMESSAGE_PVP_ANGELS, x.UserLanguage); return session.PlayerEntity.GenerateSayPacket(_languageService.GetLanguageFormat(GameDialogKey.ACT4_CHATMESSAGE_PVP_KILL, x.UserLanguage, factionKey, playerEntity.Name), ChatMessageColorType.Green); }, new FactionBroadcast(FactionType.Demon)); // For every angel, send "nick died from a demon" _sessionManager.Broadcast(x => { string factionKey = _languageService.GetLanguage(GameDialogKey.ACT4_CHATMESSAGE_PVP_DEMONS, x.UserLanguage); return session.PlayerEntity.GenerateSayPacket(_languageService.GetLanguageFormat(GameDialogKey.ACT4_CHATMESSAGE_PVP_DEATH, x.UserLanguage, factionKey, session.PlayerEntity.Name), ChatMessageColorType.Red); }, new FactionBroadcast(FactionType.Angel)); break; case FactionType.Demon: _sessionManager.Broadcast(x => { string factionKey = _languageService.GetLanguage(GameDialogKey.ACT4_CHATMESSAGE_PVP_ANGELS, x.UserLanguage); return session.PlayerEntity.GenerateSayPacket(_languageService.GetLanguageFormat(GameDialogKey.ACT4_CHATMESSAGE_PVP_DEATH, x.UserLanguage, factionKey, session.PlayerEntity.Name), ChatMessageColorType.Red); }, new FactionBroadcast(FactionType.Demon)); _sessionManager.Broadcast(x => { string factionKey = _languageService.GetLanguage(GameDialogKey.ACT4_CHATMESSAGE_PVP_DEMONS, x.UserLanguage); return session.PlayerEntity.GenerateSayPacket(_languageService.GetLanguageFormat(GameDialogKey.ACT4_CHATMESSAGE_PVP_KILL, x.UserLanguage, factionKey, playerEntity.Name), ChatMessageColorType.Green); }, new FactionBroadcast(FactionType.Angel)); break; } } } DateTime actualTime = DateTime.UtcNow; if (killer is null or IMonsterEntity { SummonerType: not VisualType.Player }) { await Penalty(e); session.PlayerEntity.UpdateRevival(actualTime + _revivalConfiguration.ForcedRevivalDelay, RevivalType.DontPayRevival, ForcedType.Forced); session.PlayerEntity.UpdateAskRevival(actualTime + _revivalConfiguration.RevivalDialogDelay, AskRevivalType.BasicRevival); return; } session.PlayerEntity.UpdateRevival(actualTime + _revivalConfiguration.Act4SealRevivalDelay, RevivalType.DontPayRevival, ForcedType.Act4SealRevival); } private async Task HandleReputation(IClientSession session, IPlayerEntity killer) { if (_act4Configuration.PvpFactionPoints) { await _asyncEventPipeline.ProcessEventAsync(new Act4FactionPointsIncreaseEvent(killer.Faction, _act4Configuration.FactionPointsPerPvpKill)); } int killerReputDegree = (int)killer.GetReputationIcon(_reputationConfiguration, _rankingManager.TopReputation); int victimReputDegree = (int)session.PlayerEntity.GetReputationIcon(_reputationConfiguration, _rankingManager.TopReputation); int formulaResult = victimReputDegree * session.PlayerEntity.Level * 10 / killerReputDegree + killerReputDegree * 50 / 3; int finalReputation = 9 < killerReputDegree - victimReputDegree ? Convert.ToInt32(formulaResult * 0.1) : formulaResult; if (session.PlayerEntity.IsGettingLosingReputation || killer.IsGettingLosingReputation) { finalReputation = (int)(finalReputation * 0.05); } finalReputation = (int)(finalReputation * (1 + killer.BCardComponent.GetAllBCardsInformation(BCardType.ReputHeroLevel, (byte)AdditionalTypes.ReputHeroLevel.ReputIncreased, killer.Level).firstData * 0.01)); if (killer.IsInGroup()) { foreach (IPlayerEntity member in killer.GetGroup().Members) { if (member == null) { continue; } if (killer.MapInstance.Id != member.MapInstance?.Id) { continue; } if (member.Id != killer.Id) { int reputationForMember = (int)(finalReputation * 0.1); if (finalReputation <= 0) { continue; } await member.Session.EmitEventAsync(new GenerateReputationEvent { Amount = reputationForMember, SendMessage = true }); continue; } if (finalReputation <= 0) { continue; } await member.Session.EmitEventAsync(new GenerateReputationEvent { Amount = finalReputation, SendMessage = true }); } } else { await killer.Session.EmitEventAsync(new GenerateReputationEvent { Amount = finalReputation, SendMessage = true }); } int toRemove = killerReputDegree * killer.Level * 10 / victimReputDegree + victimReputDegree * 50 / 35; if (session.PlayerEntity.IsGettingLosingReputation || killer.IsGettingLosingReputation) { toRemove = (int)(toRemove * 0.05); } int decrease = session.PlayerEntity.BCardComponent .GetAllBCardsInformation(BCardType.ChangingPlace, (byte)AdditionalTypes.ChangingPlace.DecreaseReputationLostAfterDeath, session.PlayerEntity.Level).firstData; toRemove = (int)(toRemove * (1 - decrease * 0.01)); if (toRemove <= 0) { return; } await session.EmitEventAsync(new GenerateReputationEvent { Amount = -toRemove, SendMessage = true }); } private async Task Penalty(RevivalStartProcedureEvent e) { PlayerRevivalPenalization playerRevivalPenalization = _revivalConfiguration.PlayerRevivalPenalization; if (e.Sender.PlayerEntity.Level <= playerRevivalPenalization.MaxLevelWithoutRevivalPenalization) { return; } int amount = e.Sender.PlayerEntity.Level < playerRevivalPenalization.MaxLevelWithDignityPenalizationIncrement ? e.Sender.PlayerEntity.Level * playerRevivalPenalization.DignityPenalizationIncrementMultiplier : playerRevivalPenalization.MaxLevelWithDignityPenalizationIncrement * playerRevivalPenalization.DignityPenalizationIncrementMultiplier; await e.Sender.PlayerEntity.RemoveDignity(amount, _minMaxConfiguration, _languageService, _reputationConfiguration, _rankingManager.TopReputation); } }