server-master/srcs/WingsAPI.Game/Extensions/BuffExtension.cs
2026-02-10 18:21:30 +01:00

267 lines
No EOL
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WingsAPI.Packets.Enums.Shells;
using WingsEmu.DTOs.BCards;
using WingsEmu.Game._enum;
using WingsEmu.Game.Buffs;
using WingsEmu.Game.Buffs.Events;
using WingsEmu.Game.Characters;
using WingsEmu.Game.Entities;
using WingsEmu.Game.Managers.StaticData;
using WingsEmu.Game.Networking;
using WingsEmu.Packets.Enums;
namespace WingsEmu.Game.Extensions;
public static class BuffExtension
{
private static readonly HashSet<short> _buffResistance = new()
{
(short)BCardType.DebuffResistance,
(short)BCardType.AngerSkill,
(short)BCardType.SpecialisationBuffResistance,
(short)BCardType.DragonSkills,
(short)BCardType.Buff
};
public static bool IsNormal(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.NORMAL);
public static bool IsNotRemovedOnDeath(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.NOT_REMOVED_ON_DEATH);
public static bool IsNotDisappearOnSpChange(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.NOT_REMOVED_ON_SP_CHANGE);
public static bool IsRefreshAtExpiration(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.REFRESH_AT_EXPIRATION);
public static bool IsDisappearOnPvp(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.DISAPPEAR_ON_PVP);
public static bool IsBigBuff(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.BIG);
public static bool IsNoDuration(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.NO_DURATION);
public static bool IsSavingOnDisconnect(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.SAVING_ON_DISCONNECT);
public static bool IsPartnerBuff(this Buff buff) => buff != null && buff.BuffFlags.HasFlag(BuffFlag.PARTNER);
public static bool IsPartnerRankBuff(this int buffVnum) => buffVnum >= 2000;
public static int RemainingTimeInMilliseconds(this Buff buff) => (int)(buff.Start - DateTime.UtcNow + buff.Duration).TotalMilliseconds;
public static async Task CheckPartnerBuff(this IClientSession session) => await session.EmitEventAsync(new BuffPartnerCheckEvent());
public static double CheckForResistance(this IBattleEntity target, Buff b, ICardsManager cardsManager, out double buffCounter, out double specializedResistance)
{
var bCards = new List<(int casterLevel, BCardDTO bCard)>();
IReadOnlyList<BCardDTO> buffDebuffResistance = target.BCardComponent.GetAllBCards();
IReadOnlyList<(int casterLevel, BCardDTO bCard)> buffsBCards = target.BCardComponent.GetBuffBCards();
foreach (BCardDTO bCard in buffDebuffResistance)
{
bCards.Add((target.Level, bCard));
}
bCards.AddRange(buffsBCards);
double debuffCounter = 1;
buffCounter = 1;
specializedResistance = 1;
int secondDataSum = 0;
foreach ((int casterLevel, BCardDTO resistanceBCard) in bCards)
{
if (!_buffResistance.Contains(resistanceBCard.Type))
{
continue;
}
int firstDataValue = resistanceBCard.FirstDataValue(casterLevel);
int secondDataValue = resistanceBCard.SecondDataValue(casterLevel);
switch (resistanceBCard.Type)
{
case (short)BCardType.SpecialisationBuffResistance when resistanceBCard.SubType == (byte)AdditionalTypes.SpecialisationBuffResistance.ResistanceToEffect ||
resistanceBCard.SubType == (byte)AdditionalTypes.SpecialisationBuffResistance.ResistanceToEffectNegated:
{
if (secondDataValue == 0)
{
continue;
}
Card anotherBuff = cardsManager.GetCardByCardId(secondDataValue);
if (anotherBuff == null)
{
continue;
}
if (b.GroupId == anotherBuff.GroupId && b.Level <= anotherBuff.Level)
{
specializedResistance *= 1.0 - firstDataValue / 100.0;
}
break;
}
case (short)BCardType.DragonSkills when resistanceBCard.SubType == (byte)AdditionalTypes.DragonSkills.CannotUseBuffChance:
{
if (b.Level <= resistanceBCard.SecondData)
{
buffCounter *= 1.0 - firstDataValue / 100.0;
}
break;
}
case (short)BCardType.DebuffResistance when b.BuffGroup == BuffGroup.Bad:
{
switch (resistanceBCard.SubType)
{
case (byte)AdditionalTypes.DebuffResistance.NeverBadDiseaseEffectChance when b.BuffCategory == BuffCategory.DiseaseSeries && b.Level <= firstDataValue:
secondDataSum -= secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.NeverBadGeneralEffectChance when b.BuffCategory == BuffCategory.GeneralEffect && b.Level <= firstDataValue:
secondDataSum -= secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.NeverBadMagicEffectChance when b.BuffCategory == BuffCategory.MagicEffect && b.Level <= firstDataValue:
secondDataSum -= secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.NeverBadToxicEffectChance when b.BuffCategory == BuffCategory.PoisonType && b.Level <= firstDataValue:
secondDataSum -= secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.IncreaseBadDiseaseEffectChance when b.BuffCategory == BuffCategory.DiseaseSeries && b.Level <= firstDataValue:
secondDataSum += secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.IncreaseBadGeneralEffectChance when b.BuffCategory == BuffCategory.GeneralEffect && b.Level <= firstDataValue:
secondDataSum += secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.IncreaseBadMagicEffectChance when b.BuffCategory == BuffCategory.MagicEffect && b.Level <= firstDataValue:
secondDataSum += secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.IncreaseBadToxicEffectChance when b.BuffCategory == BuffCategory.PoisonType && b.Level <= firstDataValue:
secondDataSum += secondDataValue;
break;
}
switch (resistanceBCard.SubType)
{
case (byte)AdditionalTypes.DebuffResistance.NeverBadEffectChance when b.Level <= firstDataValue:
secondDataSum -= secondDataValue;
break;
case (byte)AdditionalTypes.DebuffResistance.IncreaseBadEffectChance when b.Level <= firstDataValue:
secondDataSum += secondDataValue;
break;
}
break;
}
case (short)BCardType.AngerSkill when b.BuffGroup == BuffGroup.Good:
switch (resistanceBCard.SubType)
{
case (byte)AdditionalTypes.AngerSkill.BlockGoodEffectNegated when b.Level <= secondDataValue:
case (byte)AdditionalTypes.AngerSkill.BlockGoodEffect when b.Level <= secondDataValue:
buffCounter *= 1.0 - firstDataValue / 100.0;
break;
}
break;
case (short)BCardType.Buff when resistanceBCard.SubType == (byte)AdditionalTypes.Buff.PreventingBadEffect:
if (firstDataValue != b.GroupId)
{
break;
}
if (b.Level > secondDataValue)
{
break;
}
secondDataSum -= 80;
break;
}
}
debuffCounter *= 1.0 + secondDataSum / 100.0;
if (target is not IPlayerEntity playerEntity)
{
return debuffCounter;
}
int shell = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedAllNegativeEffect);
debuffCounter *= 1.0 - shell / 100.0;
int reducedByBuffVnum = 0;
switch ((BuffVnums)b.CardId)
{
case BuffVnums.MINOR_BLEEDING:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedMinorBleeding);
reducedByBuffVnum += playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedBleedingAndMinorBleeding);
break;
case BuffVnums.BLEEDING:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedBleedingAndMinorBleeding);
break;
case BuffVnums.BLACKOUT:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedStun);
break;
case BuffVnums.HAND_OF_DEATH:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedParalysis);
break;
case BuffVnums.FREEZE:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedFreeze);
break;
case BuffVnums.BLIND:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedBlind);
break;
case BuffVnums.BIND:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedSlow);
break;
case BuffVnums.WEAKEN_DEFENCE_POWER:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedArmorDeBuff);
break;
case BuffVnums.SHOCK:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedShock);
break;
case BuffVnums.PARALYSIS:
reducedByBuffVnum = playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedPoisonParalysis);
break;
}
debuffCounter *= 1.0 - reducedByBuffVnum / 100.0;
int reducedByGroupId = (BuffGroupIds)b.GroupId switch
{
BuffGroupIds.STUNS => playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedAllStun),
BuffGroupIds.BLEEDING => playerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedAllBleedingType),
_ => 0
};
debuffCounter *= 1.0 - reducedByGroupId / 100.0;
return debuffCounter;
}
public static void SendBuffsPacket(this IClientSession session)
{
if (!session.PlayerEntity.BuffComponent.HasAnyBuff())
{
return;
}
IReadOnlyList<Buff> buffs = session.PlayerEntity.BuffComponent.GetAllBuffs();
foreach (Buff buff in buffs)
{
if (!buff.IsBigBuff())
{
switch (buff.CardId)
{
case (short)BuffVnums.CHARGE when session.PlayerEntity.BCardComponent.GetChargeBCards().Any():
int sum = session.PlayerEntity.BCardComponent.GetChargeBCards().Sum(x => x.FirstDataValue(session.PlayerEntity.Level));
session.SendBfPacket(buff, sum, sum);
break;
case (short)BuffVnums.CHARGE:
session.SendBfPacket(buff, session.PlayerEntity.ChargeComponent.GetCharge(), session.PlayerEntity.ChargeComponent.GetCharge());
break;
default:
session.SendBfLeftPacket(buff);
break;
}
}
else
{
session.SendStaticBuffUiPacket(buff, buff.RemainingTimeInMilliseconds());
}
}
}
}