server-master/srcs/_plugins/WingsEmu.Plugins.BasicImplementation/Event/Characters/KillBonusEventHandler.cs
2026-02-10 18:21:30 +01:00

805 lines
No EOL
31 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using PhoenixLib.Events;
using WingsAPI.Data.Drops;
using WingsAPI.Game.Extensions.ItemExtension.Inventory;
using WingsEmu.DTOs.Maps;
using WingsEmu.DTOs.Quests;
using WingsEmu.Game;
using WingsEmu.Game._enum;
using WingsEmu.Game._i18n;
using WingsEmu.Game.Algorithm.Events;
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.Extensions;
using WingsEmu.Game.Groups;
using WingsEmu.Game.Helpers.Damages;
using WingsEmu.Game.Inventory.Event;
using WingsEmu.Game.Items;
using WingsEmu.Game.Managers;
using WingsEmu.Game.Managers.ServerData;
using WingsEmu.Game.Managers.StaticData;
using WingsEmu.Game.Maps;
using WingsEmu.Game.Mates;
using WingsEmu.Game.Networking;
using WingsEmu.Game.Quests;
using WingsEmu.Game.Quests.Event;
using WingsEmu.Game.Raids;
using WingsEmu.Game.TimeSpaces;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Chat;
namespace WingsEmu.Plugins.BasicImplementations.Event.Characters;
public sealed class KillBonusEventHandler : IAsyncEventProcessor<KillBonusEvent>
{
private readonly IDropManager _dropManager;
private readonly IDropRarityConfigurationProvider _dropRarityConfigurationProvider;
private readonly IAsyncEventPipeline _eventPipeline;
private readonly IGameItemInstanceFactory _gameItemInstance;
private readonly IGameLanguageService _gameLanguage;
private readonly IItemsManager _itemsManager;
private readonly IRandomGenerator _randomGenerator;
private readonly IRankingManager _rankingManager;
private readonly IReputationConfiguration _reputationConfiguration;
private readonly IServerManager _serverManager;
private readonly ISessionManager _sessionManager;
private readonly HashSet<QuestType> NormalDropQuestTypes = new() { QuestType.DROP_CHANCE, QuestType.DROP_CHANCE_2, QuestType.DROP_IN_TIMESPACE };
public KillBonusEventHandler(IRandomGenerator randomGenerator,
IDropManager dropManager, IServerManager serverManager, IGameLanguageService gameLanguage, ISessionManager sessionManager,
IItemsManager itemsManager, IAsyncEventPipeline eventPipeline, IGameItemInstanceFactory gameItemInstance,
IDropRarityConfigurationProvider dropRarityConfigurationProvider, IReputationConfiguration reputationConfiguration, IRankingManager rankingManager)
{
_randomGenerator = randomGenerator;
_dropManager = dropManager;
_serverManager = serverManager;
_gameLanguage = gameLanguage;
_sessionManager = sessionManager;
_itemsManager = itemsManager;
_eventPipeline = eventPipeline;
_gameItemInstance = gameItemInstance;
_dropRarityConfigurationProvider = dropRarityConfigurationProvider;
_reputationConfiguration = reputationConfiguration;
_rankingManager = rankingManager;
}
public async Task HandleAsync(KillBonusEvent e, CancellationToken cancellation)
{
IMonsterEntity monsterEntityToAttack = e.MonsterEntity;
IPlayerEntity character = e.Sender.PlayerEntity;
IClientSession session = e.Sender;
if (monsterEntityToAttack == null || monsterEntityToAttack.IsStillAlive || monsterEntityToAttack.SummonerType is VisualType.Player)
{
return;
}
if (!ShouldMonsterDrop(monsterEntityToAttack))
{
return;
}
// owner set
IPlayerEntity dropOwner = null;
if (monsterEntityToAttack.Damagers.Count > 0)
{
IBattleEntity entityDropOwner = monsterEntityToAttack.Damagers.FirstOrDefault();
if (entityDropOwner != null)
{
dropOwner = entityDropOwner switch
{
IMonsterEntity monsterEntity
=> monsterEntity.SummonerType != null && monsterEntity.SummonerId != null && monsterEntity.SummonerType == VisualType.Player
? monsterEntity.MapInstance.GetCharacterById(monsterEntity.SummonerId.Value)
: null,
IPlayerEntity playerEntity => playerEntity,
IMateEntity mateEntity => mateEntity.Owner,
_ => null
};
}
}
// Check if owner is online and it's at the same map
IClientSession firstAttacker = dropOwner != null ? _sessionManager.GetSessionByCharacterId(dropOwner.Id) : null;
if (firstAttacker == null)
{
dropOwner = character;
}
else
{
dropOwner = firstAttacker.CurrentMapInstance?.Id == character.MapInstance.Id ? firstAttacker.PlayerEntity : character;
}
PlayerGroup playerGroup = null;
if (dropOwner != null)
{
playerGroup = dropOwner.GetGroup();
}
// end owner set
if (!session.HasCurrentMapInstance)
{
return;
}
await HandleExp(session, character, monsterEntityToAttack, dropOwner?.Id);
await HandleGoldDrops(monsterEntityToAttack, playerGroup, dropOwner);
await HandleDrops(monsterEntityToAttack, session.PlayerEntity, playerGroup, dropOwner);
}
private bool ShouldMonsterDrop(IMonsterEntity monsterEntityToAttack)
{
switch ((MonsterVnum)monsterEntityToAttack.MonsterVNum)
{
case MonsterVnum.TRAINING_STAKE:
case MonsterVnum.DEMON_CAMP:
case MonsterVnum.ANGEL_CAMP:
return false;
}
return true;
}
private async Task HandleExp(IClientSession session, IPlayerEntity character, IMonsterEntity monsterEntityToAttack, long? dropOwner)
{
if (!character.IsAlive())
{
return;
}
await _eventPipeline.ProcessEventAsync(new GenerateExperienceEvent(character, monsterEntityToAttack, dropOwner));
if (character.Level >= monsterEntityToAttack.Level || character.Dignity >= 100)
{
return;
}
character.Dignity += 1;
session.RefreshReputation(_reputationConfiguration, _rankingManager.TopReputation);
session.SendSuccessChatMessage(_gameLanguage.GetLanguageFormat(GameDialogKey.DIGNITY_CHATMESSAGE_RESTORE, session.UserLanguage, 1));
}
private async Task HandleDrops(IMonsterEntity monsterEntityToAttack, IPlayerEntity mainKiller, PlayerGroup playerGroup, IPlayerEntity firstAttacker)
{
IClientSession session = firstAttacker.Session;
IReadOnlyList<DropDTO> monsterDrops = monsterEntityToAttack.Drops;
var additionalDrop = new List<DropDTO>();
IReadOnlyList<DropDTO> mapDrop = _dropManager.GetDropsByMapId(monsterEntityToAttack.MapInstance.MapId);
IEnumerable<DropDTO> generalDrop = _dropManager.GetGeneralDrops();
additionalDrop.AddRange(mapDrop);
additionalDrop.AddRange(generalDrop);
int secondChanceDropBCard = session.PlayerEntity.BCardComponent
.GetAllBCardsInformation(BCardType.DropItemTwice, (byte)AdditionalTypes.DropItemTwice.DoubleDropChance, session.PlayerEntity.Level).firstData;
bool secondChanceDrop = secondChanceDropBCard != 0 && _randomGenerator.RandomNumber() <= secondChanceDropBCard;
#region Quests
// Normal quest drops
IEnumerable<CharacterQuest> characterQuests = session.PlayerEntity.GetCurrentQuestsByTypes(NormalDropQuestTypes);
foreach (CharacterQuest characterQuest in characterQuests)
{
foreach (QuestObjectiveDto objective in characterQuest.Quest.Objectives)
{
if (monsterEntityToAttack.MonsterVNum != objective.Data0 && characterQuest.Quest.QuestType != QuestType.DROP_IN_TIMESPACE)
{
continue;
}
if (characterQuest.Quest.QuestType == QuestType.DROP_IN_TIMESPACE)
{
TimeSpaceParty timeSpace = session.PlayerEntity.TimeSpaceComponent.TimeSpace;
if (timeSpace == null || timeSpace.TimeSpaceId != objective.Data0)
{
continue;
}
}
float rndChance = _randomGenerator.RandomNumber();
float chance = characterQuest.Quest.QuestType == QuestType.DROP_CHANCE ? objective.Data3 : objective.Data3 * 0.1f;
if (rndChance > chance)
{
continue;
}
await DropQuestItem(session, monsterEntityToAttack, playerGroup, objective.Data1);
if (!secondChanceDrop)
{
continue;
}
await DropQuestItem(session, monsterEntityToAttack, playerGroup, objective.Data1);
}
}
// It has to be hardcoded, sorry T-T
if (session.PlayerEntity.HasQuestWithId((int)QuestsVnums.LILIES_SP2))
{
if (monsterEntityToAttack.Level >= session.PlayerEntity.Level - 15 && monsterEntityToAttack.Level <= session.PlayerEntity.Level + 15 || monsterEntityToAttack.Level > 75)
{
float rndChance = _randomGenerator.RandomNumber();
float chance = 25; // It has to be like this for now
if (rndChance < chance)
{
await DropQuestItem(session, monsterEntityToAttack, playerGroup, (int)ItemVnums.LILY_OF_PURITY);
if (secondChanceDrop)
{
await DropQuestItem(session, monsterEntityToAttack, playerGroup, (int)ItemVnums.LILY_OF_PURITY);
}
}
}
}
#endregion
bool hasPenalty = HasLevelPenalty(mainKiller, monsterEntityToAttack);
int rate = session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4) || session.CurrentMapInstance.HasMapFlag(MapFlags.HAS_DROP_DIRECTLY_IN_INVENTORY_ENABLED) ||
monsterEntityToAttack.DropToInventory
? 1
: _serverManager.MobDropRate;
if (secondChanceDrop)
{
session.PlayerEntity.BroadcastEffectInRange(EffectType.DoubleChanceDrop);
}
for (int i = 0; i < rate; i++)
{
foreach (DropDTO drop in monsterDrops)
{
float rndChance = _randomGenerator.RandomNumber(0, 100000);
float chance = drop.DropChance + drop.DropChance * _serverManager.MobDropChance * (hasPenalty ? 0.1f : 1.0f);
if (rndChance > chance)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVNum, drop.Amount, playerGroup);
if (!secondChanceDrop)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVNum, drop.Amount, playerGroup);
}
}
if (monsterEntityToAttack.RaidDrop != null)
{
foreach (DropChance drop in monsterEntityToAttack.RaidDrop)
{
float rndChance = _randomGenerator.RandomNumber(0, 100000);
float chance = drop.Chance + drop.Chance * _serverManager.MobDropChance;
if (rndChance > chance)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVnum, drop.Amount, playerGroup);
if (!secondChanceDrop)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVnum, drop.Amount, playerGroup);
}
}
if (session.PlayerEntity.TimeSpaceComponent.TimeSpace != null && monsterEntityToAttack.MapInstance.MapInstanceType == MapInstanceType.TimeSpaceInstance)
{
TimeSpaceParty timeSpace = session.PlayerEntity.TimeSpaceComponent.TimeSpace;
float rndChance = _randomGenerator.RandomNumber(0, 100000);
int itemChance = timeSpace.Instance.BonusPointItemDropChance;
float chance = itemChance + itemChance * _serverManager.MobDropChance * (hasPenalty ? 0.1f : 1.0f);
if (rndChance <= chance)
{
await DropItem(session, monsterEntityToAttack, (short)ItemVnums.BONUS_POINTS, 1, playerGroup);
if (secondChanceDrop)
{
await DropItem(session, monsterEntityToAttack, (short)ItemVnums.BONUS_POINTS, 1, playerGroup);
}
}
}
IReadOnlyList<DropDTO> raceDrop = _dropManager.GetDropsByMonsterRace(monsterEntityToAttack.MonsterRaceType, monsterEntityToAttack.MonsterRaceSubType);
for (int i = 0; i < rate; i++)
{
foreach (DropDTO drop in raceDrop)
{
float rndChance = _randomGenerator.RandomNumber(0, 10000);
float chance = drop.DropChance + drop.DropChance * _serverManager.MobDropChance * (hasPenalty ? 0.1f : 1.0f);
if (rndChance > chance)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVNum, drop.Amount, playerGroup);
if (!secondChanceDrop)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVNum, drop.Amount, playerGroup);
}
}
if (monsterEntityToAttack.MonsterRaceType is MonsterRaceType.Fixed or MonsterRaceType.Other)
{
return;
}
int genericRate = session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4) ? 1 : _serverManager.GenericDropRate;
for (int i = 0; i < genericRate; i++)
{
foreach (DropDTO drop in additionalDrop)
{
float rndChance = _randomGenerator.RandomNumber(0, 10000);
float chance = drop.DropChance + drop.DropChance * _serverManager.GenericDropChance * (hasPenalty ? 0.1f : 1.0f);
if (rndChance > chance)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVNum, drop.Amount, playerGroup);
if (!secondChanceDrop)
{
continue;
}
await DropItem(session, monsterEntityToAttack, drop.ItemVNum, drop.Amount, playerGroup);
}
}
}
private async Task DropQuestItem(IClientSession session, IMonsterEntity monsterEntityToAttack, PlayerGroup playerGroup, int itemVnum)
{
if (session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4) || monsterEntityToAttack.DropToInventory
|| session.CurrentMapInstance.HasMapFlag(MapFlags.HAS_DROP_DIRECTLY_IN_INVENTORY_ENABLED))
{
var alreadyGifted = new List<long>();
foreach (IBattleEntity entity in monsterEntityToAttack.Damagers)
{
long charId = entity.Id;
if (alreadyGifted.Contains(charId))
{
continue;
}
IClientSession giftSession = _sessionManager.GetSessionByCharacterId(charId);
if (giftSession == null)
{
continue;
}
if (giftSession.PlayerEntity.MapInstance?.Id != monsterEntityToAttack.MapInstance?.Id)
{
continue;
}
bool shouldReceiveDrop = ShouldReceiveDrop(giftSession, monsterEntityToAttack);
if (!shouldReceiveDrop)
{
continue;
}
if (giftSession.PlayerEntity.IsInGroup())
{
foreach (IPlayerEntity member in giftSession.PlayerEntity.GetGroup().Members)
{
await member.Session.EmitEventAsync(new QuestItemPickUpEvent
{
ItemVnum = itemVnum,
Amount = 1,
SendMessage = true
});
alreadyGifted.Add(member.Id);
}
}
else
{
await giftSession.EmitEventAsync(new QuestItemPickUpEvent
{
ItemVnum = itemVnum,
Amount = 1,
SendMessage = true
});
alreadyGifted.Add(giftSession.PlayerEntity.Id);
}
}
return;
}
short newX = (short)(monsterEntityToAttack.PositionX + _randomGenerator.RandomNumber(-1, 2));
short newY = (short)(monsterEntityToAttack.PositionY + _randomGenerator.RandomNumber(-1, 2));
if (monsterEntityToAttack.MapInstance.IsBlockedZone(newX, newY))
{
newX = monsterEntityToAttack.PositionX;
newY = monsterEntityToAttack.PositionY;
}
var newItemPosition = new Position(newX, newY);
if (playerGroup == null)
{
var dropItem = new DropMapItemEvent(session.PlayerEntity.MapInstance, newItemPosition, (short)itemVnum, 1, ownerId: session.PlayerEntity.Id, isQuest: true);
await _eventPipeline.ProcessEventAsync(dropItem);
return;
}
string itemName;
if (playerGroup.SharingMode == (byte)GroupSharingType.ByOrder)
{
long? dropOwner = playerGroup.GetNextOrderedCharacterId(session.PlayerEntity);
if (!dropOwner.HasValue)
{
return;
}
foreach (IPlayerEntity s in playerGroup.Members)
{
itemName = _gameLanguage.GetItemName(_itemsManager.GetItem(itemVnum), s.Session);
s.Session.SendChatMessage(_gameLanguage.GetLanguageFormat(GameDialogKey.GROUP_CHATMESSAGE_DROP_ORDERED, session.UserLanguage, 1,
itemName, playerGroup.Members.FirstOrDefault(c => c.Id == (long)dropOwner)?.Name), ChatMessageColorType.Yellow);
}
var dropItem = new DropMapItemEvent(session.PlayerEntity.MapInstance, newItemPosition, (short)itemVnum, 1, ownerId: dropOwner.Value, isQuest: true);
await _eventPipeline.ProcessEventAsync(dropItem);
}
else
{
foreach (IPlayerEntity s in playerGroup.Members)
{
itemName = _gameLanguage.GetItemName(_itemsManager.GetItem(itemVnum), s.Session);
s.Session.SendChatMessage(_gameLanguage.GetLanguageFormat(GameDialogKey.GROUP_CHATMESSAGE_DROP_SHARED, session.UserLanguage, 1, itemName), ChatMessageColorType.Yellow);
}
var dropItem = new DropMapItemEvent(session.PlayerEntity.MapInstance, newItemPosition, (short)itemVnum, 1, ownerId: session.PlayerEntity.Id, isQuest: true);
await _eventPipeline.ProcessEventAsync(dropItem);
}
}
private async Task DropItem(IClientSession session, IMonsterEntity monsterEntityToAttack, int itemVnum, int amount, PlayerGroup playerGroup)
{
if (session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4) || session.CurrentMapInstance.HasMapFlag(MapFlags.HAS_DROP_DIRECTLY_IN_INVENTORY_ENABLED)
|| monsterEntityToAttack.DropToInventory)
{
var alreadyGifted = new HashSet<long>();
foreach (IBattleEntity entity in monsterEntityToAttack.Damagers)
{
long charId = entity.Id;
if (alreadyGifted.Contains(charId))
{
continue;
}
IClientSession giftSession = _sessionManager.GetSessionByCharacterId(charId);
if (giftSession == null)
{
continue;
}
if (giftSession.PlayerEntity.MapInstance?.Id != monsterEntityToAttack.MapInstance?.Id)
{
continue;
}
bool shouldReceiveDrop = ShouldReceiveDrop(giftSession, monsterEntityToAttack);
if (!shouldReceiveDrop)
{
continue;
}
IGameItem item = _itemsManager.GetItem(itemVnum);
sbyte randomRarity = _dropRarityConfigurationProvider.GetRandomRarity(item.ItemType);
GameItemInstance itemInstance = _gameItemInstance.CreateItem(itemVnum, amount, 0, randomRarity);
if (item.ItemType == ItemType.Map)
{
continue;
}
await giftSession.AddNewItemToInventory(itemInstance, true, ChatMessageColorType.Yellow, true);
alreadyGifted.Add(charId);
}
return;
}
short newX = (short)(monsterEntityToAttack.PositionX + _randomGenerator.RandomNumber(-1, 2));
short newY = (short)(monsterEntityToAttack.PositionY + _randomGenerator.RandomNumber(-1, 2));
if (monsterEntityToAttack.MapInstance.IsBlockedZone(newX, newY))
{
newX = monsterEntityToAttack.PositionX;
newY = monsterEntityToAttack.PositionY;
}
var newItemPosition = new Position(newX, newY);
if (playerGroup == null)
{
var dropItem = new DropMapItemEvent(session.PlayerEntity.MapInstance, newItemPosition, (short)itemVnum, amount, ownerId: session.PlayerEntity.Id);
await _eventPipeline.ProcessEventAsync(dropItem);
return;
}
if (playerGroup.SharingMode == (byte)GroupSharingType.ByOrder)
{
long? dropOwner = playerGroup.GetNextOrderedCharacterId(session.PlayerEntity);
if (!dropOwner.HasValue)
{
return;
}
foreach (IPlayerEntity s in playerGroup.Members)
{
string itemName = _gameLanguage.GetItemName(_itemsManager.GetItem(itemVnum), s.Session);
s.Session.SendChatMessage(_gameLanguage.GetLanguageFormat(GameDialogKey.GROUP_CHATMESSAGE_DROP_ORDERED, s.Session.UserLanguage, amount,
itemName, playerGroup.Members.FirstOrDefault(c => c.Id == (long)dropOwner)?.Name), ChatMessageColorType.Yellow);
}
var dropItem = new DropMapItemEvent(session.PlayerEntity.MapInstance, newItemPosition, (short)itemVnum, amount, ownerId: dropOwner.Value);
await _eventPipeline.ProcessEventAsync(dropItem);
}
else
{
foreach (IPlayerEntity s in playerGroup.Members)
{
string itemName = _gameLanguage.GetItemName(_itemsManager.GetItem(itemVnum), s.Session);
s.Session.SendChatMessage(_gameLanguage.GetLanguageFormat(GameDialogKey.GROUP_CHATMESSAGE_DROP_SHARED, s.Session.UserLanguage, amount, itemName), ChatMessageColorType.Yellow);
}
var dropItem = new DropMapItemEvent(session.PlayerEntity.MapInstance, newItemPosition, (short)itemVnum, amount, ownerId: session.PlayerEntity.Id);
await _eventPipeline.ProcessEventAsync(dropItem);
}
}
private bool ShouldReceiveDrop(IClientSession giftSession, IMonsterEntity monsterEntityToAttack)
{
long? tankPlayer = null;
int highestHits = 0;
foreach (IBattleEntity damager in monsterEntityToAttack.Damagers)
{
if (damager is not IPlayerEntity playerEntity)
{
continue;
}
if (!playerEntity.HitsByMonsters.TryGetValue(monsterEntityToAttack.Id, out int hits))
{
continue;
}
if (highestHits > hits)
{
continue;
}
tankPlayer = playerEntity.Id;
highestHits = hits;
}
if (tankPlayer != null && giftSession.PlayerEntity.Id == tankPlayer.Value)
{
return true;
}
IPlayerEntity player = giftSession.PlayerEntity;
if (!monsterEntityToAttack.PlayersDamage.TryGetValue(player.Id, out int damage))
{
return false;
}
int damageToDealt = (int)(monsterEntityToAttack.MaxHp * 0.05);
return damageToDealt <= damage;
}
private async Task HandleGoldDrops(IMonsterEntity monsterEntityToAttack, PlayerGroup playerGroup, IPlayerEntity firstAttacker)
{
if (monsterEntityToAttack.MonsterRaceType is MonsterRaceType.Fixed or MonsterRaceType.Other)
{
return;
}
if (monsterEntityToAttack.MapInstance.MapInstanceType == MapInstanceType.TimeSpaceInstance)
{
return;
}
if (HasLevelPenalty(firstAttacker, monsterEntityToAttack))
{
return;
}
int gold = GetGold(firstAttacker, monsterEntityToAttack);
long maxGold = _serverManager.MaxGold;
gold = gold > maxGold ? (int)maxGold : gold;
int randomNumber = 0;
int rate = _serverManager.GoldDropRate;
for (int i = 0; i < rate; i++)
{
randomNumber += _randomGenerator.RandomNumber();
}
if (randomNumber >= 50 * _serverManager.GoldDropChance)
{
return;
}
if (gold <= 0)
{
return;
}
IClientSession session = firstAttacker.Session;
if (session.CurrentMapInstance == null)
{
return;
}
int secondChanceDropBCard = session.PlayerEntity.BCardComponent
.GetAllBCardsInformation(BCardType.DropItemTwice, (byte)AdditionalTypes.DropItemTwice.DoubleDropChance, session.PlayerEntity.Level).firstData;
bool secondChanceDrop = secondChanceDropBCard != 0 && _randomGenerator.RandomNumber() <= secondChanceDropBCard;
if (secondChanceDrop)
{
session.BroadcastEffectInRange(EffectType.DoubleChanceDrop);
}
if (session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4) || session.CurrentMapInstance.HasMapFlag(MapFlags.HAS_DROP_DIRECTLY_IN_INVENTORY_ENABLED)
|| monsterEntityToAttack.DropToInventory)
{
var alreadyGifted = new HashSet<long>();
foreach (IBattleEntity entity in monsterEntityToAttack.Damagers)
{
long charId = entity.Id;
if (alreadyGifted.Contains(charId))
{
continue;
}
IClientSession giftSession = _sessionManager.GetSessionByCharacterId(charId);
if (giftSession == null)
{
continue;
}
if (giftSession.PlayerEntity.MapInstance?.Id != monsterEntityToAttack.MapInstance?.Id)
{
continue;
}
bool shouldReceiveDrop = ShouldReceiveDrop(giftSession, monsterEntityToAttack);
if (!shouldReceiveDrop)
{
continue;
}
await giftSession.EmitEventAsync(new GenerateGoldEvent
(
(long)(gold * (1 + giftSession.PlayerEntity.BCardComponent.GetAllBCardsInformation(BCardType.Item,
(byte)AdditionalTypes.Item.IncreaseEarnedGold, giftSession.PlayerEntity.Level).firstData * 0.01))
));
if (secondChanceDrop)
{
await giftSession.EmitEventAsync(new GenerateGoldEvent
(
(long)(gold * (1 + giftSession.PlayerEntity.BCardComponent.GetAllBCardsInformation(BCardType.Item,
(byte)AdditionalTypes.Item.IncreaseEarnedGold, giftSession.PlayerEntity.Level).firstData * 0.01))
));
}
alreadyGifted.Add(charId);
}
return;
}
string itemName = _itemsManager.GetItem((short)ItemVnums.GOLD).Name;
if (playerGroup == null)
{
var dropGold = new DropMapItemEvent(session.PlayerEntity.MapInstance, monsterEntityToAttack.Position, (short)ItemVnums.GOLD, gold, ownerId: firstAttacker.Id);
await _eventPipeline.ProcessEventAsync(dropGold);
if (secondChanceDrop)
{
await _eventPipeline.ProcessEventAsync(dropGold);
}
return;
}
if (playerGroup.SharingMode == (byte)GroupSharingType.ByOrder)
{
long? dropOwner = playerGroup.GetNextOrderedCharacterId(firstAttacker);
if (!dropOwner.HasValue)
{
return;
}
foreach (IPlayerEntity s in playerGroup.Members)
{
string itemNameTranslated = _gameLanguage.GetLanguage(GameDataType.Item, itemName, s.Session.UserLanguage);
s.Session.SendChatMessage(
s.Session.GetLanguageFormat(GameDialogKey.GROUP_CHATMESSAGE_DROP_ORDERED, gold, itemNameTranslated, playerGroup.Members.FirstOrDefault(c => c.Id == (long)dropOwner)?.Name),
ChatMessageColorType.Yellow);
}
var dropGold = new DropMapItemEvent(session.PlayerEntity.MapInstance, monsterEntityToAttack.Position, (short)ItemVnums.GOLD, gold, ownerId: dropOwner.Value);
await _eventPipeline.ProcessEventAsync(dropGold);
if (secondChanceDrop)
{
await _eventPipeline.ProcessEventAsync(dropGold);
}
}
else
{
foreach (IPlayerEntity s in playerGroup.Members)
{
string itemNameTranslated = _gameLanguage.GetLanguage(GameDataType.Item, itemName, s.Session.UserLanguage);
s.Session.SendChatMessage(s.Session.GetLanguageFormat(GameDialogKey.GROUP_CHATMESSAGE_DROP_SHARED, gold, itemNameTranslated), ChatMessageColorType.Yellow);
}
var dropGold = new DropMapItemEvent(session.PlayerEntity.MapInstance, monsterEntityToAttack.Position, (short)ItemVnums.GOLD, gold, ownerId: session.PlayerEntity.Id);
await _eventPipeline.ProcessEventAsync(dropGold);
if (secondChanceDrop)
{
await _eventPipeline.ProcessEventAsync(dropGold);
}
}
}
private int GetGold(IPlayerEntity playerEntity, IMonsterEntity monsterEntity)
{
if (!playerEntity.MapInstance.HasMapFlag(MapFlags.IS_BASE_MAP) && playerEntity.MapInstance.MapInstanceType != MapInstanceType.TimeSpaceInstance)
{
return 0;
}
int lowBaseGold = _randomGenerator.RandomNumber(6 * monsterEntity.Level, 12 * monsterEntity.Level);
return lowBaseGold * _serverManager.GoldRate;
}
private bool HasLevelPenalty(IPlayerEntity playerEntity, IMonsterEntity monsterEntity)
{
if (monsterEntity.Level >= 70)
{
return false;
}
return playerEntity.Level - monsterEntity.Level > 10;
}
}