652 lines
No EOL
25 KiB
C#
652 lines
No EOL
25 KiB
C#
// WingsEmu
|
|
// WingsEmu
|
|
//
|
|
// Developed by NosWings Team
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using PhoenixLib.Events;
|
|
using WingsAPI.Data.Drops;
|
|
using WingsEmu.Core.Generics;
|
|
using WingsEmu.DTOs.BCards;
|
|
using WingsEmu.DTOs.Skills;
|
|
using WingsEmu.Game;
|
|
using WingsEmu.Game._enum;
|
|
using WingsEmu.Game.Algorithm;
|
|
using WingsEmu.Game.Battle;
|
|
using WingsEmu.Game.Battle.Managers;
|
|
using WingsEmu.Game.Buffs;
|
|
using WingsEmu.Game.Entities;
|
|
using WingsEmu.Game.Extensions;
|
|
using WingsEmu.Game.Helpers.Damages;
|
|
using WingsEmu.Game.Maps;
|
|
using WingsEmu.Game.Monster;
|
|
using WingsEmu.Game.Raids;
|
|
using WingsEmu.Game.Skills;
|
|
using WingsEmu.Packets.Enums;
|
|
using WingsEmu.Packets.Enums.Battle;
|
|
|
|
namespace Plugin.CoreImpl.Entities
|
|
{
|
|
public class MonsterEntity : IMonsterEntity
|
|
{
|
|
private readonly IAsyncEventPipeline _asyncEventPipeline;
|
|
private readonly IBattleEntityAlgorithmService _battleEntityAlgorithmService;
|
|
private readonly ICastingComponent _castingComponent;
|
|
private readonly IEndBuffDamageComponent _endBuffDamageComponent;
|
|
private readonly IEventTriggerContainer _eventContainer;
|
|
|
|
private double _enhancedHp = 1;
|
|
|
|
public MonsterEntity(int id, IEventTriggerContainer eventContainer, IBCardComponent bCardComponent, IAsyncEventPipeline asyncEventPipeline, IMonsterData monsterData, IMapInstance mapInstance,
|
|
MonsterEntityBuilder builder, IReadOnlyList<INpcMonsterSkill> npcMonsterSkills, IBattleEntityAlgorithmService battleEntityAlgorithmService)
|
|
{
|
|
UniqueId = builder?.GeneratedGuid ?? Guid.NewGuid();
|
|
BCardComponent = bCardComponent;
|
|
_castingComponent = new CastingComponent();
|
|
Damagers = new ThreadSafeHashSet<IBattleEntity>();
|
|
_endBuffDamageComponent = new EndBuffDamageComponent();
|
|
ChargeComponent = new ChargeComponent();
|
|
_eventContainer = eventContainer;
|
|
BuffComponent = new BuffComponent();
|
|
_asyncEventPipeline = asyncEventPipeline;
|
|
_battleEntityAlgorithmService = battleEntityAlgorithmService;
|
|
|
|
Id = id;
|
|
AmountRequired = monsterData.AmountRequired;
|
|
ArmorLevel = monsterData.ArmorLevel;
|
|
AttackType = monsterData.AttackType;
|
|
AttackUpgrade = monsterData.AttackUpgrade;
|
|
BasicCastTime = monsterData.BasicCastTime;
|
|
BasicCooldown = monsterData.BasicCooldown;
|
|
BasicRange = monsterData.BasicRange;
|
|
BCards = monsterData.BCards;
|
|
AttackEffect = monsterData.AttackEffect;
|
|
BasicHitChance = monsterData.BasicHitChance;
|
|
CanBeCollected = monsterData.CanBeCollected;
|
|
CanBeDebuffed = monsterData.CanBeDebuffed;
|
|
CanBeCaught = monsterData.CanBeCaught;
|
|
CanBePushed = monsterData.CanBePushed;
|
|
CanRegenMp = monsterData.CanRegenMp;
|
|
CellSize = monsterData.CellSize;
|
|
CleanDamageMin = monsterData.CleanDamageMin;
|
|
CleanDamageMax = monsterData.CleanDamageMax;
|
|
CleanHitRate = monsterData.CleanHitRate;
|
|
CleanMeleeDefence = monsterData.CleanMeleeDefence;
|
|
CleanRangeDefence = monsterData.CleanRangeDefence;
|
|
CleanMagicDefence = monsterData.CleanMagicDefence;
|
|
CleanDodge = monsterData.CleanDodge;
|
|
CleanHp = monsterData.CleanHp;
|
|
CleanMp = monsterData.CleanMp;
|
|
BaseCloseDefence = monsterData.BaseCloseDefence;
|
|
BaseConcentrate = monsterData.BaseConcentrate;
|
|
BaseCriticalChance = monsterData.BaseCriticalChance;
|
|
BaseCriticalRate = monsterData.BaseCriticalRate;
|
|
DamagedOnlyLastJajamaruSkill = monsterData.DamagedOnlyLastJajamaruSkill;
|
|
BaseDamageMinimum = monsterData.BaseDamageMaximum;
|
|
BaseDamageMaximum = monsterData.BaseDamageMinimum;
|
|
BaseDarkResistance = monsterData.BaseDarkResistance;
|
|
DeathEffect = monsterData.DeathEffect;
|
|
BaseMaxHp = monsterData.BaseMaxHp;
|
|
BaseMaxMp = monsterData.BaseMaxMp;
|
|
DefenceDodge = monsterData.DefenceDodge;
|
|
DefenceUpgrade = monsterData.DefenceUpgrade;
|
|
Drops = monsterData.Drops;
|
|
DisappearAfterHitting = monsterData.DisappearAfterHitting;
|
|
DisappearAfterSeconds = monsterData.DisappearAfterSeconds;
|
|
DisappearAfterSecondsMana = monsterData.DisappearAfterSecondsMana;
|
|
DistanceDefence = monsterData.DistanceDefence;
|
|
DistanceDefenceDodge = monsterData.DistanceDefenceDodge;
|
|
BaseElement = monsterData.BaseElement;
|
|
BaseElementRate = monsterData.BaseElementRate;
|
|
BaseFireResistance = monsterData.BaseFireResistance;
|
|
GiveDamagePercentage = monsterData.GiveDamagePercentage;
|
|
GroupAttack = monsterData.GroupAttack;
|
|
HasMode = monsterData.HasMode;
|
|
RawHostility = monsterData.RawHostility;
|
|
IconId = monsterData.IconId;
|
|
IsPercent = monsterData.IsPercent;
|
|
JobXp = monsterData.JobXp;
|
|
BaseLevel = monsterData.BaseLevel;
|
|
BaseLightResistance = monsterData.BaseLightResistance;
|
|
MagicDefence = monsterData.MagicDefence;
|
|
MagicMpFactor = monsterData.MagicMpFactor;
|
|
MeleeHpFactor = monsterData.MeleeHpFactor;
|
|
MinimumAttackRange = monsterData.MinimumAttackRange;
|
|
MonsterVNum = monsterData.MonsterVNum;
|
|
Name = monsterData.Name;
|
|
NoticeRange = monsterData.NoticeRange;
|
|
OnDefenseOnlyOnce = monsterData.OnDefenseOnlyOnce;
|
|
PermanentEffect = monsterData.PermanentEffect;
|
|
MonsterRaceType = monsterData.MonsterRaceType;
|
|
MonsterRaceSubType = monsterData.MonsterRaceSubType;
|
|
RangeDodgeFactor = monsterData.RangeDodgeFactor;
|
|
BaseRespawnTime = monsterData.BaseRespawnTime;
|
|
SpawnMobOrColor = monsterData.SpawnMobOrColor;
|
|
BaseSpeed = monsterData.BaseSpeed;
|
|
SpriteSize = monsterData.SpriteSize;
|
|
TakeDamages = monsterData.TakeDamages;
|
|
VNumRequired = monsterData.VNumRequired;
|
|
BaseWaterResistance = monsterData.BaseWaterResistance;
|
|
WeaponLevel = monsterData.WeaponLevel;
|
|
WinfoValue = monsterData.WinfoValue;
|
|
Xp = monsterData.Xp;
|
|
MaxTries = monsterData.MaxTries;
|
|
CollectionCooldown = monsterData.CollectionCooldown;
|
|
CollectionDanceTime = monsterData.CollectionDanceTime;
|
|
TeleportRemoveFromInventory = monsterData.TeleportRemoveFromInventory;
|
|
BasicDashSpeed = monsterData.BasicDashSpeed;
|
|
ModeIsHpTriggered = monsterData.ModeIsHpTriggered;
|
|
ModeLimiterType = monsterData.ModeLimiterType;
|
|
ModeRangeTreshold = monsterData.ModeRangeTreshold;
|
|
ModeCModeVnum = monsterData.ModeCModeVnum;
|
|
ModeHpTresholdOrItemVnum = monsterData.ModeHpTresholdOrItemVnum;
|
|
MidgardDamage = monsterData.MidgardDamage;
|
|
HasDash = monsterData.HasDash;
|
|
DropToInventory = monsterData.DropToInventory;
|
|
ModeBCards = monsterData.ModeBCards;
|
|
BaseXp = monsterData.BaseXp;
|
|
BaseJobXp = monsterData.BaseJobXp;
|
|
|
|
LastEffect = Death = SpawnDate = DateTime.UtcNow;
|
|
LastSkill = DateTime.MinValue;
|
|
IsHostile = RawHostility != (int)HostilityType.NOT_HOSTILE;
|
|
|
|
IsStillAlive = true;
|
|
Speed = this.GetSpeed(BaseSpeed);
|
|
Hp = BaseMaxHp;
|
|
Mp = BaseMaxMp;
|
|
Level = BaseLevel;
|
|
CanSeeInvisible = monsterData.CanSeeInvisible;
|
|
Faction = RawHostility switch
|
|
{
|
|
(int)HostilityType.ATTACK_ANGELS_ONLY => FactionType.Demon,
|
|
(int)HostilityType.ATTACK_DEVILS_ONLY => FactionType.Angel,
|
|
_ => monsterData.SuggestedFaction ?? FactionType.Neutral
|
|
};
|
|
|
|
if (builder != null)
|
|
{
|
|
PositionX = FirstX = builder.PositionX;
|
|
PositionY = FirstY = builder.PositionY;
|
|
Direction = builder.Direction;
|
|
CanWalk = builder.IsWalkingAround & monsterData.CanWalk;
|
|
BaseShouldRespawn = builder.IsRespawningOnDeath;
|
|
IsMateTrainer = builder.IsMateTrainer;
|
|
IsBonus = builder.IsBonus;
|
|
IsBoss = builder.IsBoss;
|
|
IsTarget = builder.IsTarget;
|
|
VesselMonster = builder.IsVesselMonster;
|
|
SummonerId = builder.SummonerId;
|
|
SummonerType = builder.SummonerType;
|
|
IsHostile = builder.IsHostile;
|
|
SummonType = builder.SummonType;
|
|
GoToBossPosition = builder.GoToBossPosition;
|
|
IsInstantBattle = builder.IsInstantBattle;
|
|
RaidDrop = builder.RaidDrop;
|
|
|
|
if (builder.Level.HasValue)
|
|
{
|
|
Level = builder.Level.Value;
|
|
UpdateMonstersBaseStatistics();
|
|
Hp = MaxHp;
|
|
Mp = MaxMp;
|
|
}
|
|
|
|
if (builder.HpMultiplier.HasValue)
|
|
{
|
|
BaseMaxHp = (int)(BaseMaxHp * builder.HpMultiplier.Value);
|
|
Hp = BaseMaxHp;
|
|
}
|
|
|
|
if (builder.MpMultiplier.HasValue)
|
|
{
|
|
BaseMaxMp = (int)(BaseMaxMp * builder.MpMultiplier.Value);
|
|
Mp = BaseMaxMp;
|
|
}
|
|
|
|
Faction = builder.FactionType ?? (SuggestedFaction ?? FactionType.Neutral);
|
|
}
|
|
|
|
Drops = monsterData.Drops;
|
|
MonsterSkills = npcMonsterSkills;
|
|
|
|
NotBasicSkills = MonsterSkills.Where(x => !x.IsBasicAttack).ToArray();
|
|
if (HasDash)
|
|
{
|
|
DashSkill = MonsterSkills.Count != 0 ? MonsterSkills[0] : null;
|
|
}
|
|
|
|
SkillsWithoutDashSkill = MonsterSkills.Where(x => DashSkill != null && DashSkill.Skill.Id != x.Skill.Id).ToArray();
|
|
|
|
foreach (INpcMonsterSkill skill in MonsterSkills)
|
|
{
|
|
Skills.Add(skill);
|
|
|
|
if (skill.IsBasicAttack)
|
|
{
|
|
ReplacedBasicSkill = skill;
|
|
}
|
|
}
|
|
|
|
this.InitializeBCards();
|
|
|
|
BasicSkill = new SkillInfo
|
|
{
|
|
Vnum = default,
|
|
AttackType = AttackType,
|
|
Range = BasicRange,
|
|
CastTime = BasicCastTime,
|
|
Cooldown = BasicCooldown,
|
|
HitEffect = AttackEffect,
|
|
Element = BaseElement,
|
|
HitChance = builder?.SetHitChance ?? BasicHitChance,
|
|
HitAnimation = 11,
|
|
TargetType = TargetType.Target,
|
|
TargetAffectedEntities = TargetAffectedEntities.Enemies,
|
|
SkillType = SkillType.MonsterSkill
|
|
};
|
|
|
|
MapInstance = mapInstance;
|
|
}
|
|
|
|
public bool IsEnhanced { get; set; }
|
|
|
|
public DateTime LastEnhancedEffect { get; set; }
|
|
|
|
public bool BaseShouldRespawn { get; }
|
|
public bool TeleportBackOnNoticeRangeExceed { get; }
|
|
|
|
public void RefreshStats()
|
|
{
|
|
Speed = this.GetSpeed(BaseSpeed);
|
|
}
|
|
|
|
public ConcurrentDictionary<long, int> PlayersDamage { get; } = new();
|
|
|
|
public DateTime LastMpRegen { get; set; }
|
|
|
|
public Position? GoToBossPosition { get; set; }
|
|
public bool IsInstantBattle { get; set; }
|
|
|
|
public IEnumerable<DropChance> RaidDrop { get; }
|
|
public DateTime LastBonusEffectTime { get; set; }
|
|
public DateTime AttentionTime { get; set; }
|
|
public ConcurrentDictionary<byte, Waypoint> Waypoints { get; set; }
|
|
public DateTime LastWayPoint { get; set; }
|
|
public byte CurrentWayPoint { get; set; }
|
|
public byte ReturnTimeOut { get; set; }
|
|
public (VisualType, long) LastAttackedEntity { get; set; }
|
|
public bool IsRunningAway { get; set; }
|
|
public IReadOnlyList<INpcMonsterSkill> NotBasicSkills { get; }
|
|
public IReadOnlyList<INpcMonsterSkill> SkillsWithoutDashSkill { get; }
|
|
public INpcMonsterSkill ReplacedBasicSkill { get; }
|
|
public INpcMonsterSkill DashSkill { get; }
|
|
|
|
public IBCardComponent BCardComponent { get; }
|
|
public IChargeComponent ChargeComponent { get; }
|
|
public ThreadSafeHashSet<Guid> AggroedEntities { get; } = new();
|
|
public IBuffComponent BuffComponent { get; }
|
|
public bool IsMateTrainer { get; }
|
|
|
|
public int MaxHp
|
|
{
|
|
get => this.GetMaxHp((int)(BaseMaxHp * _enhancedHp));
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int MaxMp
|
|
{
|
|
get => this.GetMaxMp(BaseMaxMp);
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int Hp { get; set; }
|
|
public int Mp { get; set; }
|
|
|
|
public ThreadSafeHashSet<IBattleEntity> Damagers { get; }
|
|
public ThreadSafeHashSet<IBattleEntity> Targets { get; } = new();
|
|
public ThreadSafeHashSet<(VisualType, long)> TargetsByVisualTypeAndId { get; } = new();
|
|
public DateTime LastTargetsRefresh { get; set; }
|
|
|
|
public DateTime Death { get; set; }
|
|
|
|
public bool IsStillAlive { get; set; }
|
|
|
|
public byte Level { get; set; }
|
|
|
|
public byte Element
|
|
{
|
|
get => BaseElement;
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int ElementRate
|
|
{
|
|
get => BaseElementRate;
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int FireResistance
|
|
{
|
|
get => BaseFireResistance;
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int WaterResistance
|
|
{
|
|
get => BaseWaterResistance;
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int LightResistance
|
|
{
|
|
get => BaseLightResistance;
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int DarkResistance
|
|
{
|
|
get => BaseDarkResistance;
|
|
set => throw new NotImplementedException();
|
|
}
|
|
|
|
public int DamagesMinimum { get; set; }
|
|
public int DamagesMaximum { get; set; }
|
|
|
|
public Position Position
|
|
{
|
|
get => new(PositionX, PositionY);
|
|
set
|
|
{
|
|
PositionX = value.X;
|
|
PositionY = value.Y;
|
|
}
|
|
}
|
|
|
|
public short PositionX { get; private set; }
|
|
|
|
public short PositionY { get; private set; }
|
|
|
|
public FactionType Faction { get; }
|
|
|
|
public byte Speed { get; set; }
|
|
|
|
public byte Size { get; set; } = 10;
|
|
|
|
public bool IsBonus { get; set; }
|
|
|
|
public bool IsBoss { get; }
|
|
|
|
public string Name { get; }
|
|
public byte NoticeRange { get; }
|
|
public bool OnDefenseOnlyOnce { get; }
|
|
public short PermanentEffect { get; }
|
|
|
|
public SummonType? SummonType { get; }
|
|
public bool IsHostile { get; set; }
|
|
|
|
public bool IsTarget { get; set; }
|
|
|
|
public DateTime LastEffect { get; set; }
|
|
|
|
public DateTime LastSkill { get; set; }
|
|
|
|
public IMapInstance MapInstance { get; set; }
|
|
|
|
public List<IBattleEntitySkill> Skills { get; set; } = new();
|
|
|
|
public IBattleEntity Target { get; set; }
|
|
public DateTime NextTick { get; set; }
|
|
public DateTime NextAttackReady { get; set; }
|
|
public bool ModeIsActive { get; set; }
|
|
public short Morph { get; set; }
|
|
public long ModeDeathsSinceRespawn { get; set; }
|
|
|
|
public short FirstX { get; set; }
|
|
|
|
public short FirstY { get; set; }
|
|
|
|
public bool VesselMonster { get; set; }
|
|
|
|
public short AmountRequired { get; }
|
|
public byte ArmorLevel { get; }
|
|
public AttackType AttackType { get; }
|
|
public byte AttackUpgrade { get; }
|
|
public byte BasicCastTime { get; }
|
|
public short BasicCooldown { get; }
|
|
public byte BasicRange { get; }
|
|
public short AttackEffect { get; }
|
|
public short BasicHitChance { get; }
|
|
public bool CanBeCollected { get; }
|
|
public bool CanBeDebuffed { get; }
|
|
public bool CanBeCaught { get; }
|
|
public bool CanBePushed { get; }
|
|
public bool CanRegenMp { get; }
|
|
public bool CanWalk { get; set; }
|
|
public int CellSize { get; }
|
|
public int CleanDamageMin { get; }
|
|
public int CleanDamageMax { get; }
|
|
public int CleanHitRate { get; }
|
|
public int CleanMeleeDefence { get; }
|
|
public int CleanRangeDefence { get; }
|
|
public int CleanMagicDefence { get; }
|
|
public int CleanDodge { get; }
|
|
public int CleanHp { get; }
|
|
public int CleanMp { get; }
|
|
public short BaseCloseDefence { get; private set; }
|
|
|
|
public short BaseConcentrate { get; private set; }
|
|
|
|
public short BaseCriticalChance { get; }
|
|
public short BaseCriticalRate { get; }
|
|
public bool DamagedOnlyLastJajamaruSkill { get; }
|
|
public int BaseDamageMaximum { get; private set; }
|
|
|
|
public int BaseDamageMinimum { get; private set; }
|
|
|
|
public short BaseDarkResistance { get; }
|
|
public short DeathEffect { get; }
|
|
public int BaseMaxHp { get; private set; }
|
|
|
|
public int BaseMaxMp { get; private set; }
|
|
|
|
public short DefenceDodge { get; private set; }
|
|
|
|
public byte DefenceUpgrade { get; }
|
|
public bool DisappearAfterHitting { get; }
|
|
public bool DisappearAfterSeconds { get; }
|
|
public bool DisappearAfterSecondsMana { get; }
|
|
public short DistanceDefence { get; private set; }
|
|
|
|
public short DistanceDefenceDodge { get; private set; }
|
|
|
|
public byte BaseElement { get; }
|
|
public short BaseElementRate { get; }
|
|
public short BaseFireResistance { get; }
|
|
public FactionType? SuggestedFaction => Faction;
|
|
public int GiveDamagePercentage { get; }
|
|
public int GroupAttack { get; }
|
|
public bool HasMode { get; }
|
|
public int RawHostility { get; }
|
|
public int IconId { get; }
|
|
public bool IsPercent { get; }
|
|
public int JobXp { get; private set; }
|
|
|
|
public byte BaseLevel { get; }
|
|
public short BaseLightResistance { get; }
|
|
public short MagicDefence { get; private set; }
|
|
|
|
public short MagicMpFactor { get; }
|
|
public short MeleeHpFactor { get; }
|
|
public sbyte MinimumAttackRange { get; }
|
|
|
|
public long? SummonerId { get; set; }
|
|
public VisualType? SummonerType { get; set; }
|
|
|
|
public IBattleEntity Killer { get; set; }
|
|
|
|
public Guid UniqueId { get; }
|
|
|
|
public void GenerateDeath(IBattleEntity killer = null)
|
|
{
|
|
IsStillAlive = false;
|
|
Hp = 0;
|
|
Mp = 0;
|
|
Death = DateTime.UtcNow;
|
|
this.RemoveAllBuffsAsync(true);
|
|
Target = null;
|
|
}
|
|
|
|
public VisualType Type => VisualType.Monster;
|
|
public int Id { get; set; }
|
|
public byte Direction { get; set; } = 2;
|
|
|
|
|
|
bool INpcMonsterEntity.ShouldRespawn => BaseShouldRespawn;
|
|
public bool ReturningToFirstPosition { get; set; }
|
|
public bool ShouldFindNewTarget { get; set; }
|
|
public bool FindNewPositionAroundTarget { get; set; }
|
|
public bool IsApproachingTarget { get; set; }
|
|
public bool OnFirstDamageReceive { get; set; }
|
|
|
|
public DateTime SpawnDate { get; set; }
|
|
public DateTime LastSpecialHpDecrease { get; set; }
|
|
|
|
public bool IsMoving => CanWalk;
|
|
|
|
public int MonsterVNum { get; }
|
|
|
|
public void AddEvent(string key, IAsyncEvent notification, bool removedOnTrigger = false) => _eventContainer.AddEvent(key, notification, removedOnTrigger);
|
|
|
|
public async Task TriggerEvents(string key) => await _eventContainer.TriggerEvents(key);
|
|
|
|
public async Task EmitEventAsync<T>(T eventArgs) where T : IBattleEntityEvent
|
|
{
|
|
if (eventArgs.Entity != this)
|
|
{
|
|
throw new ArgumentException("An event should be emitted only from the event sender");
|
|
}
|
|
|
|
await _asyncEventPipeline.ProcessEventAsync(eventArgs);
|
|
}
|
|
|
|
public void EmitEvent<T>(T eventArgs) where T : IBattleEntityEvent
|
|
{
|
|
EmitEventAsync(eventArgs).ConfigureAwait(false).GetAwaiter().GetResult();
|
|
}
|
|
|
|
public MonsterRaceType MonsterRaceType { get; set; }
|
|
public byte MonsterRaceSubType { get; }
|
|
public short RangeDodgeFactor { get; }
|
|
public TimeSpan BaseRespawnTime { get; }
|
|
public int SpawnMobOrColor { get; }
|
|
public byte BaseSpeed { get; }
|
|
public int SpriteSize { get; }
|
|
public int TakeDamages { get; }
|
|
public short VNumRequired { get; }
|
|
public short BaseWaterResistance { get; }
|
|
public byte WeaponLevel { get; }
|
|
public byte WinfoValue { get; }
|
|
public int Xp { get; private set; }
|
|
|
|
public byte MaxTries { get; }
|
|
public short CollectionCooldown { get; }
|
|
public byte CollectionDanceTime { get; }
|
|
public bool TeleportRemoveFromInventory { get; }
|
|
public short BasicDashSpeed { get; }
|
|
public bool ModeIsHpTriggered { get; }
|
|
public byte ModeLimiterType { get; }
|
|
public short ModeRangeTreshold { get; }
|
|
public short ModeCModeVnum { get; }
|
|
public short ModeHpTresholdOrItemVnum { get; }
|
|
public short MidgardDamage { get; }
|
|
public bool HasDash { get; }
|
|
public bool DropToInventory { get; }
|
|
public int BaseXp { get; }
|
|
public int BaseJobXp { get; }
|
|
public IReadOnlyList<DropDTO> Drops { get; }
|
|
public bool CanSeeInvisible { get; }
|
|
public IReadOnlyList<BCardDTO> BCards { get; }
|
|
public IReadOnlyList<BCardDTO> ModeBCards { get; }
|
|
|
|
public IReadOnlyList<INpcMonsterSkill> MonsterSkills { get; }
|
|
|
|
public SkillInfo BasicSkill { get; }
|
|
|
|
public SkillCast SkillCast => _castingComponent.SkillCast;
|
|
|
|
public bool IsCastingSkill => _castingComponent.IsCastingSkill;
|
|
|
|
public void SetCastingSkill(SkillInfo skill, DateTime time)
|
|
{
|
|
_castingComponent.SetCastingSkill(skill, time);
|
|
}
|
|
|
|
public void RemoveCastingSkill()
|
|
{
|
|
_castingComponent.RemoveCastingSkill();
|
|
}
|
|
|
|
public IReadOnlyDictionary<short, int> EndBuffDamages => _endBuffDamageComponent.EndBuffDamages;
|
|
|
|
public void AddEndBuff(short buffVnum, int damage)
|
|
{
|
|
_endBuffDamageComponent.AddEndBuff(buffVnum, damage);
|
|
}
|
|
|
|
public int DecreaseDamageEndBuff(short buffVnum, int damage) => _endBuffDamageComponent.DecreaseDamageEndBuff(buffVnum, damage);
|
|
|
|
public void RemoveEndBuffDamage(short buffVnum)
|
|
{
|
|
_endBuffDamageComponent.RemoveEndBuffDamage(buffVnum);
|
|
}
|
|
|
|
public void ChangeHpMultiplier(double hp = 1)
|
|
{
|
|
_enhancedHp = hp;
|
|
}
|
|
|
|
private void UpdateMonstersBaseStatistics()
|
|
{
|
|
BaseMaxHp = _battleEntityAlgorithmService.GetBasicHp((short)MonsterRaceType, Level, MeleeHpFactor, CleanHp);
|
|
BaseMaxMp = _battleEntityAlgorithmService.GetBasicMp((short)MonsterRaceType, Level, MagicMpFactor, CleanMp);
|
|
|
|
BaseDamageMinimum = _battleEntityAlgorithmService.GetAttack(true, (short)MonsterRaceType, AttackType, WeaponLevel, WinfoValue, Level, GetModifier(), CleanDamageMin);
|
|
BaseDamageMaximum = _battleEntityAlgorithmService.GetAttack(false, (short)MonsterRaceType, AttackType, WeaponLevel, WinfoValue, Level, GetModifier(), CleanDamageMax);
|
|
BaseConcentrate = (short)_battleEntityAlgorithmService.GetHitrate((short)MonsterRaceType, AttackType, WeaponLevel, Level, GetModifier(), CleanHitRate);
|
|
BaseCloseDefence = (short)_battleEntityAlgorithmService.GetDefense((short)MonsterRaceType, AttackType.Melee, ArmorLevel, Level, GetModifier(), CleanMeleeDefence);
|
|
DistanceDefence = (short)_battleEntityAlgorithmService.GetDefense((short)MonsterRaceType, AttackType.Ranged, ArmorLevel, Level, GetModifier(), CleanRangeDefence);
|
|
MagicDefence = (short)_battleEntityAlgorithmService.GetDefense((short)MonsterRaceType, AttackType.Magical, ArmorLevel, Level, GetModifier(), CleanMagicDefence);
|
|
DefenceDodge = (short)_battleEntityAlgorithmService.GetDodge((short)MonsterRaceType, ArmorLevel, Level, GetModifier(), CleanDodge);
|
|
DistanceDefenceDodge = (short)_battleEntityAlgorithmService.GetDodge((short)MonsterRaceType, ArmorLevel, Level, GetModifier(), CleanDodge);
|
|
|
|
Xp = Level < 20 ? 60 * Level + BaseXp : 70 * Level + BaseXp;
|
|
JobXp = Level > 60 ? 105 + BaseJobXp : 120 + BaseJobXp;
|
|
|
|
if (Xp < 0)
|
|
{
|
|
Xp = 0;
|
|
}
|
|
|
|
if (JobXp < 0)
|
|
{
|
|
JobXp = 0;
|
|
}
|
|
}
|
|
|
|
private int GetModifier()
|
|
{
|
|
return AttackType switch
|
|
{
|
|
AttackType.Melee => MeleeHpFactor,
|
|
AttackType.Ranged => RangeDodgeFactor,
|
|
AttackType.Magical => MagicMpFactor,
|
|
_ => 0
|
|
};
|
|
}
|
|
}
|
|
} |