233 lines
No EOL
8.8 KiB
C#
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));
|
|
}
|
|
} |