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

209 lines
No EOL
7.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using PhoenixLib.Events;
using WingsEmu.Core.Extensions;
using WingsEmu.Game;
using WingsEmu.Game._enum;
using WingsEmu.Game.Battle.Managers;
using WingsEmu.Game.Characters;
using WingsEmu.Game.Entities;
using WingsEmu.Game.Entities.Event;
using WingsEmu.Game.Helpers.Damages;
using WingsEmu.Game.Managers.StaticData;
using WingsEmu.Game.Maps;
using WingsEmu.Game.Monster.Event;
using WingsEmu.Game.Npcs.Event;
using WingsEmu.Game.Triggers;
namespace WingsEmu.Plugins.BasicImplementations.Event.Monster;
public class MonsterSummonEventHandler : IAsyncEventProcessor<MonsterSummonEvent>
{
private readonly IMonsterEntityFactory _monsterEntityFactory;
private readonly INpcMonsterManager _npcMonsterManager;
private readonly IPhantomPositionManager _phantomPositionManager;
private readonly IRandomGenerator _randomGenerator;
public MonsterSummonEventHandler(IRandomGenerator randomGenerator, INpcMonsterManager npcMonsterManager, IMonsterEntityFactory monsterEntityFactory, IPhantomPositionManager phantomPositionManager)
{
_randomGenerator = randomGenerator;
_npcMonsterManager = npcMonsterManager;
_monsterEntityFactory = monsterEntityFactory;
_phantomPositionManager = phantomPositionManager;
}
public async Task HandleAsync(MonsterSummonEvent e, CancellationToken cancellation)
{
List<ToSummon> toSummon = new();
short? scaledAmount = e.ScaledWithPlayerAmount;
if (scaledAmount.HasValue)
{
for (int i = 0; i < scaledAmount.Value; i++)
{
toSummon.AddRange(e.Monsters);
}
}
else
{
toSummon = e.Monsters.ToList();
}
foreach (ToSummon summon in toSummon)
{
IMonsterData npcMonster = _npcMonsterManager.GetNpc(summon.VNum);
if (npcMonster == null || _randomGenerator.RandomNumber() > summon.SummonChance)
{
continue;
}
if (e.Map.IsSummonLimitReached(e.Summoner?.Id, summon.SummonType))
{
continue;
}
IMonsterEntity mapMonster = summon.MonsterEntity ?? _monsterEntityFactory.CreateMonster(npcMonster, e.Map, new MonsterEntityBuilder
{
IsMateTrainer = summon.IsMateTrainer,
IsBonus = summon.IsBonusOrProtected,
IsBoss = summon.IsBossOrMate,
IsTarget = summon.IsTarget,
IsHostile = summon.IsHostile,
IsWalkingAround = summon.IsMoving,
IsVesselMonster = summon.IsVesselMonster,
SummonType = summon.SummonType,
SummonerId = e.Summoner?.Id,
SummonerType = e.Summoner?.Type,
FactionType = summon.FactionType ?? e.Summoner?.Faction,
HpMultiplier = summon.HpMultiplier,
MpMultiplier = summon.MpMultiplier,
SetHitChance = summon.SetHitChance != 0 && !summon.IsBossOrMate ? summon.SetHitChance : npcMonster.BasicHitChance,
Direction = summon.Direction,
GoToBossPosition = summon.GoToBossPosition,
IsInstantBattle = summon.IsInstantBattle,
Level = summon.Level
});
mapMonster.Target = summon.Target;
mapMonster.Waypoints = summon.Waypoints;
if (summon.TriggerEvents != null)
{
foreach ((string key, IAsyncEvent asyncEvent, bool removeOnUse) in summon.TriggerEvents)
{
mapMonster.AddEvent(key, asyncEvent, removeOnUse);
}
}
if (e.Summoner != null)
{
if (e.GetSummonerLevel)
{
mapMonster.Level = e.Summoner.Level;
}
if (e.Summoner is IPlayerEntity player && summon.VNum == (short)MonsterVnum.BOMB)
{
player.SkillComponent.BombEntityId = mapMonster.Id;
}
}
Position? phantomPosition = e.NpcId.HasValue ? _phantomPositionManager.GetPosition(e.NpcId.Value) : null;
Position spawnCell = phantomPosition ?? summon.SpawnCell ?? e.Map.GetRandomPosition();
if (summon.AtAroundMobId.HasValue && summon.AtAroundMobRange.HasValue)
{
IMonsterEntity originalEntity = e.Map.GetMonsterByUniqueId(summon.AtAroundMobId.Value);
byte range = summon.AtAroundMobRange.Value;
if (originalEntity is not null)
{
spawnCell = new Position((short)(originalEntity.PositionX + _randomGenerator.RandomNumber(-range, range)),
(short)(originalEntity.PositionY + _randomGenerator.RandomNumber(-range, range)));
if (originalEntity.MapInstance.IsBlockedZone(spawnCell.X, spawnCell.Y))
{
spawnCell = originalEntity.Position;
}
}
}
await mapMonster.EmitEventAsync(new MapJoinMonsterEntityEvent(mapMonster, spawnCell.X, spawnCell.Y, e.ShowEffect));
CheckBeriosPhantom(mapMonster);
DateTime now = DateTime.UtcNow;
mapMonster.AttentionTime = now + TimeSpan.FromSeconds(10);
if (!summon.RemoveTick)
{
continue;
}
mapMonster.NextTick = DateTime.UtcNow.AddSeconds(-1000);
mapMonster.NextAttackReady = DateTime.UtcNow.AddSeconds(-1000);
}
}
private void CheckBeriosPhantom(IMonsterEntity mapMonster)
{
switch ((MonsterVnum)mapMonster.MonsterVNum)
{
case MonsterVnum.EMERALD_PHANTOM:
mapMonster.AddEvent(BattleTriggers.OnDeath, new NpcSummonEvent
{
Map = mapMonster.MapInstance,
MonsterId = mapMonster.UniqueId,
Npcs = Lists.Create(new ToSummon
{
VNum = (short)MonsterVnum.EMERALD_SHADOW_PHANTOM,
SpawnCell = mapMonster.Position,
IsMoving = true,
IsHostile = true
})
}, true);
break;
case MonsterVnum.SAPPHIRE_PHANTOM:
mapMonster.AddEvent(BattleTriggers.OnDeath, new NpcSummonEvent
{
Map = mapMonster.MapInstance,
MonsterId = mapMonster.UniqueId,
Npcs = Lists.Create(new ToSummon
{
VNum = (short)MonsterVnum.SAPPHIRE_SHADOW_PHANTOM,
SpawnCell = mapMonster.Position,
IsMoving = true,
IsHostile = true
})
}, true);
break;
case MonsterVnum.RUBY_PHANTOM:
mapMonster.AddEvent(BattleTriggers.OnDeath, new NpcSummonEvent
{
Map = mapMonster.MapInstance,
MonsterId = mapMonster.UniqueId,
Npcs = Lists.Create(new ToSummon
{
VNum = (short)MonsterVnum.RUBY_SHADOW_PHANTOM,
SpawnCell = mapMonster.Position,
IsMoving = true,
IsHostile = true
})
}, true);
break;
default:
return;
}
}
}