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

233 lines
No EOL
8.8 KiB
C#

using System;
using System.Linq;
using System.Threading.Tasks;
using PhoenixLib.MultiLanguage;
using WingsEmu.Game._enum;
using WingsEmu.Game._i18n;
using WingsEmu.Game.Battle;
using WingsEmu.Game.Characters;
using WingsEmu.Game.Entities;
using WingsEmu.Game.Entities.Event;
using WingsEmu.Game.Items;
using WingsEmu.Game.Mates;
using WingsEmu.Game.Monster;
using WingsEmu.Game.Networking;
using WingsEmu.Game.Npcs;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Battle;
namespace WingsEmu.Game.Extensions;
public static class NpcMonsterExtension
{
public static string GenerateEInfo(this IMonsterData npcMonster, IGameLanguageService gameLanguage, RegionLanguageType languageType)
{
string name = gameLanguage.GetLanguage(GameDataType.NpcMonster, npcMonster.Name, languageType);
return "e_info 10 " +
$"{npcMonster.MonsterVNum} " +
$"{npcMonster.BaseLevel} " +
$"{npcMonster.BaseElement} " +
$"{(byte)npcMonster.AttackType} " +
$"{npcMonster.BaseElementRate} " +
$"{npcMonster.AttackUpgrade} " +
$"{npcMonster.BaseDamageMinimum} " +
$"{npcMonster.BaseDamageMaximum} " +
$"{npcMonster.BaseConcentrate} " +
$"{npcMonster.BaseCriticalChance} " +
$"{npcMonster.BaseCriticalRate} " +
$"{npcMonster.DefenceUpgrade} " +
$"{npcMonster.BaseCloseDefence} " +
$"{npcMonster.DefenceDodge} " +
$"{npcMonster.DistanceDefence} " +
$"{npcMonster.DistanceDefenceDodge} " +
$"{npcMonster.MagicDefence} " +
$"{npcMonster.BaseFireResistance} " +
$"{npcMonster.BaseWaterResistance} " +
$"{npcMonster.BaseLightResistance} " +
$"{npcMonster.BaseDarkResistance} " +
$"{npcMonster.BaseMaxHp} " +
$"{npcMonster.BaseMaxMp} " +
"-1 " +
$"{name.Replace(' ', '^')}";
}
public static void SendNpcInfo(this IClientSession session, IMonsterData npcMonster, IGameLanguageService gameLanguage) =>
session.SendPacket(npcMonster.GenerateEInfo(gameLanguage, session.UserLanguage));
public static int GetModifier(this MonsterData monster)
{
return monster.AttackType switch
{
AttackType.Melee => monster.MeleeHpFactor,
AttackType.Ranged => monster.RangeDodgeFactor,
AttackType.Magical => monster.MagicMpFactor
};
}
public static bool CanHit(this IMonsterData npcMonster, IBattleEntity entity)
{
switch (entity)
{
case IPlayerEntity player when player.CheatComponent.IsInvisible:
return false;
case IMateEntity mateEntity:
if (mateEntity.Owner == null)
{
break;
}
if (mateEntity.Owner.IsInvisible())
{
return false;
}
if (mateEntity.Owner.Invisible)
{
return false;
}
if (mateEntity.Owner.CheatComponent.IsInvisible)
{
return false;
}
if (mateEntity.Owner.IsOnVehicle)
{
return false;
}
break;
}
return !(npcMonster.MonsterRaceType == MonsterRaceType.People && npcMonster.MonsterRaceSubType == 3 && entity.Faction == FactionType.Angel
| npcMonster.MonsterRaceType == MonsterRaceType.Angel && entity.Faction == FactionType.Demon);
}
public static bool FindPhantomAmulet(this IMonsterData npcMonster, IBattleEntity entity)
{
if (npcMonster.RawHostility != (int)HostilityType.ATTACK_NOT_WEARING_PHANTOM_AMULET)
{
return false;
}
switch (entity)
{
case IPlayerEntity character:
GameItemInstance amulet = character.Amulet;
if (amulet == null)
{
return false;
}
return amulet.GameItem.Id == (short)ItemVnums.PHANTOM_AMULET;
case IMateEntity mateEntity:
IPlayerEntity owner = mateEntity.Owner;
GameItemInstance ownerAmulet = owner.Amulet;
if (ownerAmulet == null)
{
return false;
}
return ownerAmulet.GameItem.Id == (short)ItemVnums.PHANTOM_AMULET;
}
return true;
}
public static MonsterRaceType GetMonsterRaceType(this IBattleEntity entity)
{
return entity switch
{
IPlayerEntity => MonsterRaceType.People,
IMateEntity mateEntity => mateEntity.MonsterRaceType,
INpcEntity mapNpc => mapNpc.MonsterRaceType,
IMonsterEntity monster => monster.MonsterRaceType,
_ => MonsterRaceType.People
};
}
public static Enum GetMonsterRaceSubType(this IMonsterData monster)
{
MonsterRaceType monsterRaceType = monster.MonsterRaceType;
byte subType = monster.MonsterRaceSubType;
Enum raceSubType;
switch (monsterRaceType)
{
case MonsterRaceType.LowLevel:
raceSubType = (MonsterSubRace.LowLevel)subType;
break;
case MonsterRaceType.HighLevel:
raceSubType = (MonsterSubRace.HighLevel)subType;
break;
case MonsterRaceType.Furry:
raceSubType = (MonsterSubRace.Furry)subType;
break;
case MonsterRaceType.People:
raceSubType = (MonsterSubRace.People)subType;
break;
case MonsterRaceType.Angel:
raceSubType = (MonsterSubRace.Angels)subType;
break;
case MonsterRaceType.Undead:
raceSubType = (MonsterSubRace.Undead)subType;
break;
case MonsterRaceType.Spirit:
raceSubType = (MonsterSubRace.Spirits)subType;
break;
case MonsterRaceType.Other:
raceSubType = (MonsterSubRace.Other)subType;
break;
case MonsterRaceType.Fixed:
raceSubType = (MonsterSubRace.Fixed)subType;
break;
default:
return null;
}
return raceSubType;
}
public static string GenerateCMode(this IMonsterEntity monsterEntity, short? value = null) => $"c_mode 3 {monsterEntity.Id} {value ?? monsterEntity.Morph} 0 0";
public static void BroadcastMonsterMorph(this IMonsterEntity monsterEntity, short? value = null) => monsterEntity.MapInstance.Broadcast(monsterEntity.GenerateCMode(value));
public static bool IsMonsterSpawningMonstersForQuest(this IMonsterEntity monsterEntity) => monsterEntity.RawHostility > 20000;
public static string GenerateEnhancedGuri(this IMonsterEntity monsterEntity) => $"guri 21 3 {monsterEntity.Id}";
public static void BroadcastEnhancedGuri(this IMonsterEntity monsterEntity) => monsterEntity.MapInstance.Broadcast(monsterEntity.GenerateEnhancedGuri());
public static bool IsMandra(this IBattleEntity battleEntity)
{
if (battleEntity is not IMonsterEntity monsterEntity)
{
return false;
}
return monsterEntity.MonsterVNum is >= (short)MonsterVnum.HAPPY_MANDRA and <= (short)MonsterVnum.STRONG_GRASSMANDRA
or (short)MonsterVnum.GIANT_MANDRA or (short)MonsterVnum.DASHING_MANDRA;
}
public static bool IsPhantom(this IMonsterEntity monsterEntity) =>
(MonsterVnum)monsterEntity.MonsterVNum is MonsterVnum.RUBY_PHANTOM or MonsterVnum.EMERALD_PHANTOM or MonsterVnum.SAPPHIRE_PHANTOM;
public static bool IsPhantom(this INpcEntity npcEntity) =>
(MonsterVnum)npcEntity.MonsterVNum is MonsterVnum.RUBY_SHADOW_PHANTOM or MonsterVnum.EMERALD_SHADOW_PHANTOM or MonsterVnum.SAPPHIRE_SHADOW_PHANTOM;
public static async Task TryDespawnTimeSpacePortal(this IClientSession session)
{
INpcEntity timeSpacePortal = session.CurrentMapInstance.GetPassiveNpcs().FirstOrDefault(x => x.TimeSpaceOwnerId.HasValue && x.TimeSpaceOwnerId.Value == session.PlayerEntity.Id);
if (timeSpacePortal == null)
{
return;
}
string firstEffectPacket = timeSpacePortal.GenerateEffectGround(EffectType.BlueTimeSpace, timeSpacePortal.PositionX, timeSpacePortal.PositionY, true);
string secondEffectPacket = timeSpacePortal.GenerateEffectGround(EffectType.BlueRemoveTimeSpace, timeSpacePortal.PositionX, timeSpacePortal.PositionY, false);
timeSpacePortal.MapInstance.Broadcast(_ => firstEffectPacket);
timeSpacePortal.MapInstance.Broadcast(_ => secondEffectPacket);
await timeSpacePortal.EmitEventAsync(new MapLeaveNpcEntityEvent(timeSpacePortal));
}
}