Files
test/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs
T
2025-11-11 17:12:51 +07:00

620 lines
20 KiB
C#

using BrewMonster;
using BrewMonster.Managers;
using CSNetwork.GPDataType;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using static CECAttacksMan;
public class CECAttacksMan : MonoSingleton<CECAttacksMan>
{
private readonly LinkedList<CECAttackEvent> m_AttackLinkedList = new LinkedList<CECAttackEvent>();
#if UNITY_EDITOR
public List<CECAttackEvent> m_AttackList = new List<CECAttackEvent>();
#endif
private void Update()
{
#if UNITY_EDITOR
m_AttackList = m_AttackLinkedList.ToList();
#endif
var node = m_AttackLinkedList.First;
while (node != null)
{
var next = node.Next;
//BMLogger.LogError("HoangDev: Update CECAttackEvent node.Value.m_bFinished: " + node.Value.m_bFinished);
if (node.Value.m_bFinished)
m_AttackLinkedList.Remove(node);
else node.Value.Tick((uint)(Time.deltaTime * 1000));
node = next;
}
}
public CECAttackerEvents FindAttackByAttacker(int idHost)
{
CECAttackerEvents result = new CECAttackerEvents();
//BMLogger.LogError("HoangDev: FindAttackByAttacker idHost: " + m_AttackLinkedList.Count);
foreach (var attack in m_AttackLinkedList)
{
if (attack.m_idHost == idHost)
{
result.Add(attack);
}
}
return result;
}
public CECAttackEvent AddMeleeAttack(int idHost, int idTarget, int idWeapon, uint dwModifier, int nDamage, int nTimeFly = 10)
{
var newEvent = new CECAttackEvent(
this,
idHost,
0, // idCastTarget
idTarget,
idWeapon,
0, // idSkill
0, // nSkillLevel
dwModifier,
nDamage,
200, // timeToBeFired
nTimeFly // timeToDoDamage
);
m_AttackLinkedList.AddLast(newEvent);
newEvent.UpdateTargetFlag();
return m_AttackLinkedList.Last.Value;
}
public CECAttackEvent AddSkillAttack(int idHost, int idCastTarget, int idTarget, int idWeapon, int idSkill, int nSkillLevel, uint dwModifier, int nDamage)
{
var newEvent = new CECAttackEvent(
this,
idHost,
idCastTarget,
idTarget,
idWeapon,
idSkill,
nSkillLevel,
dwModifier,
nDamage,
200, // timeToBeFired
1000 // timeToDoDamage
);
m_AttackLinkedList.AddLast(newEvent);
newEvent.UpdateTargetFlag();
return m_AttackLinkedList.Last.Value;
}
// === thêm tạm để code có thể compile ===
public void AddAttack(CECAttackEvent evt)
{
m_AttackLinkedList.AddLast(evt);
}
public class TARGET_DATA
{
public int idTarget;
public uint dwModifier;
public int nDamage;
}
}
[Serializable]
public class CECAttackEvent
{
public CECAttacksMan? m_pManager;
public bool m_bSignaled;
public bool m_bDoFired;
public bool m_bDoDamaged;
public bool m_bFinished;
public uint m_timeLived;
public uint m_timeToBeFired;
public uint m_timeToDoDamage;
public int m_idHost;
public int m_idCastTarget;
public List<TARGET_DATA> m_targets = new List<TARGET_DATA>();
public int m_idWeapon;
public int m_idSkill;
public int m_nSkillLevel;
public int m_nSkillSection;
public CECAttackEvent() { }
public CECAttackEvent(CECAttacksMan? pManager, int idHost, int idCastTarget, int idTarget,
int idWeapon, int idSkill, int nSkillLevel, uint dwModifier,
int nDamage, int nTimeToBeFired, int nTimeToDoDamage)
{
m_pManager = pManager;
m_idHost = idHost;
m_idCastTarget = idCastTarget;
m_idWeapon = idWeapon;
m_idSkill = idSkill;
m_nSkillLevel = nSkillLevel;
m_timeToBeFired = (uint)nTimeToBeFired;
m_timeToDoDamage = (uint)nTimeToDoDamage;
m_bFinished = false;
AddTarget(idTarget, dwModifier, nDamage);
}
public bool Tick(uint dwDeltaTime)
{
m_timeLived += dwDeltaTime;
if (!m_bSignaled)
{
if (m_timeLived > 3500)
{
// too long time, this event will be deleted now
//BMLogger.LogError("HoangDev: m_bSignaled: " + m_bSignaled);
m_bFinished = true;
//DoFire();
DoDamage();
}
return true;
}
else
{
if (m_timeToBeFired != 0)
{
if (m_timeToBeFired <= dwDeltaTime)
{
m_timeToBeFired = 0;
// Fire here
DoFire();
}
else
m_timeToBeFired -= dwDeltaTime;
}
else if (m_timeToDoDamage != 0)
{
//BMLogger.LogError($"HoangDev: m_timeToDoDamage:{m_timeToDoDamage} , dwDeltaTime: {dwDeltaTime}");
if (m_timeToDoDamage <= dwDeltaTime)
{
m_timeToDoDamage = 0;
// Do damage here
DoDamage();
}
else
m_timeToDoDamage -= dwDeltaTime;
}
}
return true;
}
bool DoFire()
{
float vFlyScale = 1.0f;
float vHitScale = 1.0f;
m_bDoFired = true;
if( GPDataTypeHelper.ISPLAYERID(m_idHost) )
{
if( m_idSkill != 0 )
{
// const A3DSkillGfxComposer* pComposer = NULL;
//
// // we use skill composed gfx to present the skill effect
// if (m_nSkillSection>0) // ¶à¶Î¼¼ÄÜ
// {
// CECMultiSectionSkillMan pMan = m_pManager.GetMultiSkillGfxComposerMan();
// if(pMan)
// {
// pMan->Play(m_idSkill, m_nSkillSection,m_idHost, m_idCastTarget, m_targets,GNET::ElementSkill::IsGoblinSkill(m_idSkill));
// pComposer = pMan->GetSkillGfxComposer(m_idSkill, m_nSkillSection);
// }
// }
// else
// {
// if(GNET::ElementSkill::IsGoblinSkill(m_idSkill))
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets, true);
// else
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager->GetSkillGfxComposerMan()->GetSkillGfxComposer(m_idSkill);
// }
//
// if (pComposer && pComposer->m_dwFlyTime == 0) // ¼¼ÄÜgfxûÓзÉÐÐʵ¼Ê£¬ÔòÂíÉÏÍ·¶¥Ã°×Ö
// {
// m_timeToDoDamage = 1;
// }
// else
// {
// A3DVECTOR3 vecHost, vecTarget;
// // now we estimated a time to do damage
// if( m_targets.size() && _get_pos_by_id(m_idHost, vecHost) && _get_pos_by_id(m_targets[0].idTarget, vecTarget) )
// {
// m_timeToDoDamage = int(Magnitude(vecHost - vecTarget) / 20.0f * 1000.0f);
// a_ClampFloor(m_timeToDoDamage, 10ul);
// }
// }
}
else if( m_idWeapon != 0 )
{
// first determine gfx used
// const char * szFlyGFX = NULL;
// const char * szHitGFX = NULL;
//
// // using weapon gfx
// DATA_TYPE dt;
// const void * pData = g_pGame->GetElementDataMan()->get_data_ptr(
// m_idWeapon, ID_SPACE_ESSENCE, dt);
// ASSERT(dt == DT_WEAPON_ESSENCE || dt == DT_PROJECTILE_ESSENCE);
//
// if( dt == DT_PROJECTILE_ESSENCE )
// {
// // Ô¶³ÌÎäÆ÷£¬Ê¹Óõ¯Ò©µÄЧ¹û
// PROJECTILE_ESSENCE * pProjectile = (PROJECTILE_ESSENCE *) pData;
//
// szFlyGFX = pProjectile->file_firegfx + 4; // skip gfx/
// szHitGFX = pProjectile->file_hitgfx + 4; // skip gfx/
// }
// else if (dt == DT_WEAPON_ESSENCE)
// {
// // ½ü³ÌÎïÀí¹¥»÷£¬Ê¹ÓÃÎäÆ÷µÄЧ¹û
// WEAPON_ESSENCE * pWeapon = (WEAPON_ESSENCE *) pData;
// WEAPON_SUB_TYPE * pWeaponType = (WEAPON_SUB_TYPE*) g_pGame->GetElementDataMan()->get_data_ptr(pWeapon->id_sub_type, ID_SPACE_ESSENCE, dt);
// ASSERT(dt == DT_WEAPON_SUB_TYPE);
// szFlyGFX = NULL;
// szHitGFX = pWeaponType->file_hitgfx + 4; // skip gfx/
// }
//
// bool bHideFlyGfx = !CECOptimize::Instance().GetGFX().CanShowFly(m_idHost);
// bool bHideHitGfx = !CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
// int nNumTargets = m_targets.size();
// for(int i=0; i<nNumTargets; i++)
// {
// const TARGET_DATA& data = m_targets[i];
//
// const char * pszFlyGFX = szFlyGFX;
// const char * pszHitGFX = szHitGFX;
//
// if( data.dwModifier & MOD_NULLITY )
// pszHitGFX = "³ÌÐòÁªÈë\\»÷ÖÐ\\ÎÞЧ¹¥»÷»÷ÖÐ.gfx";
//
// if (bHideFlyGfx) pszFlyGFX = NULL;
// if (bHideHitGfx) pszHitGFX = NULL;
//
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget,
// pszFlyGFX, pszHitGFX, m_timeToDoDamage, false, enumLinearMove, 1, 0, NULL, vFlyScale, vHitScale, data.dwModifier);
// }
}
else
{
// without weapon
// ʹÓÃÈ­Ì×ÀàµÄ»÷ÖÐЧ¹û
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
var pData = ElementDataManProvider.GetElementDataMan().get_data_ptr(183, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
WEAPON_SUB_TYPE pWeaponType = (WEAPON_SUB_TYPE) pData;
bool bHideHitGfx = false;//!CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
string szGFX= null;
int nNumTargets = m_targets.Count();
for(int i=0; i<nNumTargets; i++)
{
TARGET_DATA data = m_targets[i];
// szGFX = pWeaponType->file_hitgfx + 4; // skip gfx/
string fullGfx = pWeaponType.GetFileHitGfx();
szGFX = fullGfx.Length > 4 ? fullGfx.Substring(4) : string.Empty;
if ((data.dwModifier & (int)MOD.MOD_NULLITY) != 0)
szGFX = "程序联入\\击中\\无效攻击击中.gfx";//Program link\Hit\InvalidAttackHit.gfx
if (bHideHitGfx) szGFX = null;
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget, NULL,
// szGFX, m_timeToDoDamage, false, GfxMoveMode.enumLinearMove, 1, 0, NULL, vFlyScale, vHitScale, data.dwModifier);
var target = EC_ManMessageMono.Instance?.GetObject(data.idTarget, 0)?.gameObject.transform;
if (target == null)
{
BMLogger.LogError("Target is null!");
return false;
}
var vfx = CECGameRun.Instance.GetTestVfx();
vfx.transform.position = target.position;
CECGameRun.Instance.DestroyTestVfx(vfx, 1f);
}
}
}
else if( GPDataTypeHelper.ISNPCID(m_idHost) )
{
// if( m_idSkill != 0 )
// {
// const A3DSkillGfxComposer* pComposer = NULL;
// // we use skill composed gfx to present the skill effect
// if (m_nSkillSection>0) // ¶à¶Î¼¼ÄÜ
// {
// CECMultiSectionSkillMan* pMan = m_pManager->GetMultiSkillGfxComposerMan();
// if(pMan)
// {
// pMan->Play(m_idSkill, m_nSkillSection,m_idHost, m_idCastTarget, m_targets);
// pComposer = pMan->GetSkillGfxComposer(m_idSkill, m_nSkillSection);
// }
// }
// else
// {
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager->GetSkillGfxComposerMan()->GetSkillGfxComposer(m_idSkill);
// }
//
// if (pComposer && pComposer->m_dwFlyTime == 0) // ¼¼ÄÜûÓзÉÐÐʱ¼ä£¬ÔòÖ±½ÓÍ·¶¥Ã°×Ö
// {
// m_timeToDoDamage = 1;
// }
// else
// {
// A3DVECTOR3 vecHost, vecTarget;
// // now we estimated a time to do damage
// if( m_targets.size() && _get_pos_by_id(m_idHost, vecHost) && _get_pos_by_id(m_targets[0].idTarget, vecTarget) )
// {
// m_timeToDoDamage = int(Magnitude(vecHost - vecTarget) / 20.0f * 1000.0f);
// a_ClampFloor(m_timeToDoDamage, 10ul);
// }
// }
// }
// else
// {
// CECNPC * pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(m_idHost);
// if (!pNPC)
// return true;
//
// const char * szFlyGFX = NULL;
// const char * szHitGFX = NULL;
//
// if (pNPC->IsMonsterNPC())
// {
// const MONSTER_ESSENCE * pEssence = ((CECMonster *)pNPC)->GetDBEssence();
//
// szFlyGFX = pEssence->file_gfx_short + 4; // skip gfx/
// szHitGFX = pEssence->file_gfx_short_hit + 4; // skip gfx/
// }
// else if (pNPC->IsPetNPC())
// {
// //szFlyGFX = "";
// const PET_ESSENCE* pEssence = ((CECPet*)pNPC)->GetDBEssence();
//
// szFlyGFX = pEssence->file_gfx_short + 4; //"²ß»®ÁªÈë\\ͨÓ÷ÉÐÐ\\¹­¼ý·ÉÐÐ.gfx";
//
// szHitGFX = "²ß»®ÁªÈë\\¹ÖÎï»÷ÖÐ\\¹ÖÎïÈⲫ»÷ÖÐ.gfx";
// }
// else
// return false;
//
// if( !szFlyGFX[0] )
// szFlyGFX = NULL;
//
// if( !szHitGFX[0] )
// szHitGFX = NULL;
//
// bool bHideFlyGfx = !CECOptimize::Instance().GetGFX().CanShowFly(m_idHost);
// bool bHideHitGfx = !CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
// int nNumTargets = m_targets.size();
// for(int i=0; i<nNumTargets; i++)
// {
// const TARGET_DATA& data = m_targets[i];
//
// const char * pszFlyGFX = szFlyGFX;
// const char * pszHitGFX = szHitGFX;
// if( data.nDamage <= 0 )
// {
// pszHitGFX = NULL;
// }
// else if( data.dwModifier & MOD_NULLITY )
// {
// pszHitGFX = "³ÌÐòÁªÈë\\»÷ÖÐ\\ÎÞЧ¹¥»÷»÷ÖÐ.gfx";
// }
//
// if (bHideFlyGfx) pszFlyGFX = NULL;
// if (bHideHitGfx) pszHitGFX = NULL;
//
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget,
// pszFlyGFX, pszHitGFX, m_timeToDoDamage, false, enumLinearMove, 1,
// 0, NULL, vFlyScale, vHitScale, data.dwModifier);
// }
// }
}
else
return true;
return true;
}
private bool DoDamage()
{
m_bDoDamaged = true;
m_bFinished = true;
/* CECGameRun pGameRun = g_pGame-GetGameRun();
int idHostPlayer = pGameRun->GetHostPlayer()->GetCharacterID();*/
// Get host name
/* ACString strHostName;
CECObject* pHostObject = pGameRun->GetWorld()->GetObject(m_idHost, 0);
if (pHostObject)
{
if (ISNPCID(m_idHost))
strHostName = ((CECNPC*)pHostObject)->GetName();
else if (ISPLAYERID(m_idHost))
strHostName = GetPlayerName((CECPlayer*)pHostObject);
}*/
int nNumTargets = m_targets.Count;
for (int i = 0; i < nNumTargets; i++)
{
TARGET_DATA data = m_targets[i];
int idTarget = data.idTarget;
string strName;
if (GPDataTypeHelper.ISNPCID(idTarget))
{
CECNPC pNPC = null;
if ((data.dwModifier & (uint)MOD.MOD_SUCCESS) != 0)
pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPCFromAll(idTarget);
else
{
pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPCFromAll(idTarget);
if (!pNPC)
return true;
//strName = pNPC->GetNameToShow();
}
if (!pNPC)
return true;
pNPC.Damaged(data.nDamage, data.dwModifier);
}
else if (GPDataTypeHelper.ISPLAYERID(idTarget))
{
CECPlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idTarget);
//BMLogger.LogError("HoangDev: CECPlayer pPlayer = " + pPlayer );
if (!pPlayer)
return true;
//strName = GetPlayerName(pPlayer);
pPlayer.Damaged(data.nDamage, data.dwModifier, m_idSkill);
}
/* if (data.nDamage > 0)
{
if (m_idHost == idHostPlayer)
{
if (!strName.IsEmpty())
pGameRun->AddFixedChannelMsg(FIXMSG_DODAMAGE, GP_CHAT_DAMAGE, strName, data.nDamage);
}
else if (data.idTarget == idHostPlayer)
{
if (!strHostName.IsEmpty())
pGameRun->AddFixedChannelMsg(FIXMSG_BEDAMAGED, GP_CHAT_DAMAGE, strHostName, data.nDamage);
}
}*/
}
return true;
}
public bool AddTarget(int idTarget, uint dwModifier, int nDamage)
{
m_targets.Add(new TARGET_DATA
{
idTarget = idTarget,
dwModifier = dwModifier,
nDamage = nDamage
});
return true;
}
public bool UpdateTargetFlag()
{
// update all targets' bAboutToDie flag
int nNumTargets = m_targets.Count;
for (int i = 0; i < nNumTargets; i++)
{
TARGET_DATA data = m_targets[i];
/*
if( data.dwModifier & MOD_DEADLYSTRIKE )
{
int idTarget = data.idTarget;
if (ISNPCID(idTarget))
{
CECNPC* pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(idTarget);
if (!pNPC)
return true;
pNPC->SetAboutToDie(true);
}
else if (ISPLAYERID(idTarget))
{
CECPlayer* pPlayer = g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idTarget);
if (!pPlayer)
return true;
pPlayer->SetAboutToDie(true);
}
}*/
}
return true;
}
}
public class CECAttackerEvents
{
private readonly List<CECAttackEvent> m_list = new List<CECAttackEvent>();
public void Add(CECAttackEvent? evt)
{
if (evt != null)
m_list.Add(evt);
}
public bool IsEmpty() => m_list.Count == 0;
public int Count() => m_list.Count;
public CECAttackEvent? Find(int idSkill = 0, int nSkillSection = 0)
{
foreach (var evt in m_list)
{
if (evt.m_idSkill == idSkill && evt.m_nSkillSection == nSkillSection)
return evt;
}
return null;
}
public void Signal()
{
foreach (var evt in m_list)
evt.m_bSignaled = true;
m_list.Clear();
}
public static implicit operator bool(CECAttackerEvents events)
{
return !events.IsEmpty();
}
}
enum MOD
{
MOD_PHYSIC_ATTACK_RUNE = 0x0001, // ÎïÀí¹¥»÷ÓÅ»¯·ûÉúЧ
MOD_MAGIC_ATTACK_RUNE = 0x0002, // ·¨Êõ¹¥»÷ÓÅ»¯·ûÉúЧ
MOD_PHYSIC_DEFENCE_RUNE = 0x0004, // ÎïÀí·ÀÓùÓÅ»¯·ûÉúЧ
MOD_MAGIC_DEFENCE_RUNE = 0x0008, // ·¨Êõ·ÀÓùÓÅ»¯·ûÉúЧ
MOD_CRITICAL_STRIKE = 0x0010, // ±¬»÷
MOD_RETORT = 0x0020, // ·´Õð
MOD_NULLITY = 0x0040, // ÎÞЧ¹¥»÷
MOD_IMMUNE = 0x0080, // ÃâÒßÁ˴˴ι¥»÷£¬ÓÅÏȼ¶¸ßÓÚÎÞЧ
MOD_ENCHANT_FAILED = 0x0100, // enchant ʧ°Ü
MOD_SUCCESS = 0x0200, // ³É¹¦
MOD_DODGE_DAMAGE = 0x0400, // É˺¦¶ãÉÁ
MOD_DODGE_DEBUFF = 0x0800, // ״̬¶ãÉÁ
MOD_ATTACK_AURA = 0x1000, // ¹â»·¹¥»÷
MOD_REBOUND = 0x2000, // ·´µ¯
MOD_BEAT_BACK = 0x4000, // ·´»÷
};
enum GfxMoveMode
{
enumLinearMove = 0, // Linear
enumParabolicMove, // Parabolic
enumMissileMove, // Missile
enumMeteoricMove, // Meteoric (shooting star)
enumHelixMove, // Helix (spiral)
enumCurvedMove, // Curved
enumAccMove, // Accelerated
enumOnTarget, // Targeted
enumLink, // Linked
enumRandMove, // Random movement
enumMoveModeNum
};