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 { private readonly LinkedList m_AttackLinkedList = new LinkedList(); #if UNITY_EDITOR public List m_AttackList = new List(); #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 m_targets = new List(); 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; iGetGameRun()->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; ifile_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; iGetGameRun()->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 m_list = new List(); 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 };