Merge remote-tracking branch 'origin/develop' into feature/chat
This commit is contained in:
@@ -50,7 +50,7 @@ ParticleSystem:
|
||||
ringBufferMode: 0
|
||||
ringBufferLoopRange: {x: 0, y: 1}
|
||||
emitterVelocityMode: 1
|
||||
looping: 1
|
||||
looping: 0
|
||||
prewarm: 0
|
||||
playOnAwake: 1
|
||||
useUnscaledTime: 0
|
||||
@@ -4883,7 +4883,7 @@ ParticleSystem:
|
||||
ringBufferMode: 0
|
||||
ringBufferLoopRange: {x: 0, y: 1}
|
||||
emitterVelocityMode: 1
|
||||
looping: 1
|
||||
looping: 0
|
||||
prewarm: 0
|
||||
playOnAwake: 1
|
||||
useUnscaledTime: 0
|
||||
@@ -9774,7 +9774,7 @@ ParticleSystem:
|
||||
ringBufferMode: 0
|
||||
ringBufferLoopRange: {x: 0, y: 1}
|
||||
emitterVelocityMode: 1
|
||||
looping: 1
|
||||
looping: 0
|
||||
prewarm: 0
|
||||
playOnAwake: 1
|
||||
useUnscaledTime: 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,11 @@ using UnityEngine;
|
||||
public static class GameConstants
|
||||
{
|
||||
public static int NUM_MAGICCLASS = 5;
|
||||
public static int ARMOR_RUIN_SPEED = -25;
|
||||
public static int WEAPON_RUIN_SPEED = -2;
|
||||
public static float PLAYER_PRICE_SCALE = 1.0f;
|
||||
public static int ENDURANCE_SCALE = 100;
|
||||
|
||||
}
|
||||
|
||||
public struct ROLEBASICPROP
|
||||
|
||||
@@ -2,10 +2,6 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
public class InventoryConst
|
||||
{
|
||||
// Equipment endurance scale
|
||||
public const int ENDURANCE_SCALE = 100;
|
||||
// NUM_MAGICCLASS
|
||||
public const int NUM_MAGICCLASS = 5;
|
||||
// Index of item in equipment inventory
|
||||
public const int EQUIPIVTR_WEAPON = 0;
|
||||
public const int EQUIPIVTR_HEAD = 1;
|
||||
|
||||
@@ -316,8 +316,8 @@ namespace BrewMonster.Network
|
||||
}
|
||||
public static void update_require_data(ref prerequisition require)
|
||||
{
|
||||
require.durability *= BrewMonster.Scripts.InventoryConst.ENDURANCE_SCALE;
|
||||
require.max_durability *= BrewMonster.Scripts.InventoryConst.ENDURANCE_SCALE;
|
||||
require.durability *= GameConstants.ENDURANCE_SCALE;
|
||||
require.max_durability *= GameConstants.ENDURANCE_SCALE;
|
||||
}
|
||||
public static void set_to_classid(DATA_TYPE type, byte[] data, int major_type)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -146,6 +146,7 @@ namespace BrewMonster
|
||||
pEvent.SetDelay(dwDelayTime);
|
||||
pEvent.SetReverse(bReverse);
|
||||
pEvent.SetParam(param);
|
||||
BMLogger.LogError("[HoangDev] bTraceTarget=" + bTraceTarget);
|
||||
pEvent.SetTraceTarget(bTraceTarget);
|
||||
pEvent.SetModifier(dwModifier);
|
||||
pEvent.SetIsCluster(bCluster);
|
||||
@@ -503,4 +504,4 @@ namespace BrewMonster
|
||||
public bool bGfxDisableCamShake;
|
||||
public bool bHostECMCreatedByGfx;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,6 @@ namespace BrewMonster
|
||||
if (m_enumState == GfxSkillEventState.enumHit && m_bTraceTarget)
|
||||
{
|
||||
UpdateHitGfxTransform();
|
||||
|
||||
// Check if hit GFX has been destroyed (3 second lifetime) or target is destroyed
|
||||
// 检查命中特效是否已被销毁(3秒生命周期)或目标是否已销毁
|
||||
if (m_hitGfxInstance == null || (!m_bTargetExist && m_nTargetID != 0))
|
||||
@@ -296,7 +295,26 @@ namespace BrewMonster
|
||||
protected override void HitTarget(Vector3 vTarget)
|
||||
{
|
||||
base.HitTarget(vTarget);
|
||||
DestroyFlyGfx();
|
||||
|
||||
// Only destroy fly GFX if NOT tracing target
|
||||
// If tracing target, fly GFX will be cleaned up when buff expires
|
||||
// 只有在不跟踪目标时才销毁飞行特效
|
||||
// 如果跟踪目标,飞行特效将在buff过期时清理
|
||||
if (!m_bTraceTarget)
|
||||
{
|
||||
DestroyFlyGfx();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If fly GFX exists and m_bTraceTarget is true, add to tracking list
|
||||
// 如果飞行特效存在且m_bTraceTarget为true,添加到跟踪列表
|
||||
if (m_flyGfxInstance != null)
|
||||
{
|
||||
SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_flyGfxInstance, 0); // Skill ID not available, use 0
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] HitTarget: Added fly GFX to trace target list (m_bTraceTarget=true)");
|
||||
}
|
||||
}
|
||||
|
||||
SpawnHitGfx(vTarget);
|
||||
|
||||
// TODO Phase 2: Special hit effects (rune, critical, nullity)
|
||||
@@ -333,6 +351,13 @@ namespace BrewMonster
|
||||
|
||||
m_flyGfxInstance = GameObject.Instantiate(prefab, pos, prefab.transform.rotation);
|
||||
|
||||
// If m_bTraceTarget is true, add to tracking list when spawned
|
||||
// 如果m_bTraceTarget为true,在生成时添加到跟踪列表
|
||||
if (m_bTraceTarget)
|
||||
{
|
||||
SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_flyGfxInstance, 0); // Skill ID not available, use 0
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] SpawnFlyGfx: Added fly GFX to trace target list (m_bTraceTarget=true)");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -401,6 +426,7 @@ namespace BrewMonster
|
||||
// 这与C++逻辑匹配:当投射物击中地面(无目标)时使用m_szHitGrndGfx
|
||||
bool bTargetExists = m_bTargetExist && m_nTargetID != 0;
|
||||
GameObject prefab = bTargetExists ? m_pComposer.GetHitGFX() : m_pComposer.GetHitGrdGFX();
|
||||
BMLogger.LogError("bTargetExists : " + bTargetExists);
|
||||
BMLogger.LogError("HitGfx : " + m_pComposer.hitGfxName);
|
||||
|
||||
if (prefab == null)
|
||||
@@ -429,9 +455,21 @@ namespace BrewMonster
|
||||
|
||||
m_hitGfxInstance = GameObject.Instantiate(prefab, vTarget, prefab.transform.rotation);
|
||||
|
||||
// Destroy hit GFX after 3 seconds (unless m_bTraceTarget is true, then it follows target until destroyed)
|
||||
// 3秒后销毁命中特效(除非m_bTraceTarget为true,否则它会跟随目标直到被销毁)
|
||||
//GameObject.Destroy(m_hitGfxInstance, 3.0f);
|
||||
// If m_bTraceTarget is true, add to tracking list (don't auto-destroy)
|
||||
// 如果m_bTraceTarget为true,添加到跟踪列表(不自动销毁)
|
||||
if (m_bTraceTarget)
|
||||
{
|
||||
SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_hitGfxInstance, 0); // Skill ID not available, use 0
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] SpawnHitGfx: Added hit GFX to trace target list (m_bTraceTarget=true)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Destroy hit GFX after 5 seconds (unless m_bTraceTarget is true, then it follows target until destroyed)
|
||||
// 5秒后销毁命中特效(除非m_bTraceTarget为true,否则它会跟随目标直到被销毁)
|
||||
//HIT_GFX_MAX_TIMESPAN 5000
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] SpawnHitGfx: GameObject.Destroy(m_hitGfxInstance, 5.0f);");
|
||||
GameObject.Destroy(m_hitGfxInstance, 5.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -440,10 +478,28 @@ namespace BrewMonster
|
||||
/// </summary>
|
||||
public new void Resume()
|
||||
{
|
||||
DestroyFlyGfx();
|
||||
// Hit GFX is auto-destroyed by Unity's Destroy timer, don't null it here
|
||||
// 命中特效由Unity的Destroy计时器自动销毁,不在此处置null
|
||||
m_hitGfxInstance = null;
|
||||
// Don't destroy GFX if it's in trace target list
|
||||
// It will be cleaned up when buff expires
|
||||
// 如果GFX在跟踪目标列表中,不要销毁它
|
||||
// 它将在buff过期时清理
|
||||
if (m_flyGfxInstance != null)
|
||||
{
|
||||
if (SkillGfxMan.InstanceSub != null && !SkillGfxMan.InstanceSub.IsTraceTargetGfx(m_flyGfxInstance))
|
||||
{
|
||||
DestroyFlyGfx();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_hitGfxInstance != null)
|
||||
{
|
||||
if (SkillGfxMan.InstanceSub != null && !SkillGfxMan.InstanceSub.IsTraceTargetGfx(m_hitGfxInstance))
|
||||
{
|
||||
// Hit GFX is auto-destroyed by Unity's Destroy timer, don't null it here
|
||||
// 命中特效由Unity的Destroy计时器自动销毁,不在此处置null
|
||||
m_hitGfxInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
base.Resume();
|
||||
}
|
||||
|
||||
@@ -878,6 +934,13 @@ namespace BrewMonster
|
||||
protected EC_ManPlayer m_pPlayerMan;
|
||||
protected CECNPCMan m_pNPCMan;
|
||||
|
||||
// Track GFX instances that have m_bTraceTarget = true
|
||||
// These are typically buff-related trail effects that persist until buff expires
|
||||
// 跟踪具有m_bTraceTarget = true的GFX实例
|
||||
// 这些通常是持续到buff结束的buff相关轨迹效果
|
||||
private List<GameObject> m_TraceTargetGfxList = new List<GameObject>();
|
||||
private Dictionary<GameObject, int> m_TraceTargetGfxSkillMap = new Dictionary<GameObject, int>();
|
||||
|
||||
public SkillGfxMan(CECGameRun pGameRun)
|
||||
{
|
||||
m_EventLst = new LinkedList<CECSkillGfxEvent>();
|
||||
@@ -971,6 +1034,110 @@ namespace BrewMonster
|
||||
{
|
||||
m_FreeLst[i].Clear();
|
||||
}
|
||||
|
||||
// Clean up trace target GFX
|
||||
// 清理跟踪目标GFX
|
||||
RemoveAllTraceTargetGfx();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a GFX instance to trace target tracking list
|
||||
/// 将GFX实例添加到跟踪目标跟踪列表
|
||||
/// </summary>
|
||||
public void AddTraceTargetGfx(GameObject gfxInstance, int skillId)
|
||||
{
|
||||
if (gfxInstance == null) return;
|
||||
|
||||
if (!m_TraceTargetGfxList.Contains(gfxInstance))
|
||||
{
|
||||
m_TraceTargetGfxList.Add(gfxInstance);
|
||||
m_TraceTargetGfxSkillMap[gfxInstance] = skillId;
|
||||
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] Added GFX for skill {skillId}, total tracked: {m_TraceTargetGfxList.Count}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all trace target GFX (called when buff states update)
|
||||
/// 移除所有跟踪目标GFX(在buff状态更新时调用)
|
||||
/// </summary>
|
||||
public void RemoveAllTraceTargetGfx()
|
||||
{
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] Removing {m_TraceTargetGfxList.Count} trace target GFX");
|
||||
|
||||
foreach (GameObject gfx in m_TraceTargetGfxList)
|
||||
{
|
||||
if (gfx != null)
|
||||
{
|
||||
GameObject.Destroy(gfx);
|
||||
}
|
||||
}
|
||||
|
||||
m_TraceTargetGfxList.Clear();
|
||||
m_TraceTargetGfxSkillMap.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove trace target GFX for specific skill
|
||||
/// 移除特定技能的跟踪目标GFX
|
||||
/// </summary>
|
||||
public void RemoveTraceTargetGfxForSkill(int skillId)
|
||||
{
|
||||
List<GameObject> toRemove = new List<GameObject>();
|
||||
|
||||
foreach (var kvp in m_TraceTargetGfxSkillMap)
|
||||
{
|
||||
if (kvp.Value == skillId)
|
||||
{
|
||||
toRemove.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GameObject gfx in toRemove)
|
||||
{
|
||||
if (gfx != null)
|
||||
{
|
||||
GameObject.Destroy(gfx);
|
||||
}
|
||||
m_TraceTargetGfxList.Remove(gfx);
|
||||
m_TraceTargetGfxSkillMap.Remove(gfx);
|
||||
}
|
||||
|
||||
if (toRemove.Count > 0)
|
||||
{
|
||||
BMLogger.Log($"[TRACE_TARGET_GFX] Removed {toRemove.Count} GFX for skill {skillId}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a GFX instance is tracked as trace target GFX
|
||||
/// 检查GFX实例是否被跟踪为跟踪目标GFX
|
||||
/// </summary>
|
||||
public bool IsTraceTargetGfx(GameObject gfx)
|
||||
{
|
||||
return m_TraceTargetGfxList.Contains(gfx);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up null references (GFX destroyed elsewhere)
|
||||
/// 清理空引用(在其他地方销毁的GFX)
|
||||
/// </summary>
|
||||
public void CleanupTraceTargetGfx()
|
||||
{
|
||||
m_TraceTargetGfxList.RemoveAll(gfx => gfx == null);
|
||||
|
||||
List<GameObject> nullKeys = new List<GameObject>();
|
||||
foreach (var kvp in m_TraceTargetGfxSkillMap)
|
||||
{
|
||||
if (kvp.Key == null)
|
||||
{
|
||||
nullKeys.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
foreach (var key in nullKeys)
|
||||
{
|
||||
m_TraceTargetGfxSkillMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -201,8 +201,8 @@ namespace PerfectWorld.Scripts.Managers
|
||||
StrengthReq = m_pDBEssence.require_strength;
|
||||
AgilityReq = m_pDBEssence.require_agility;
|
||||
ReputationReq = m_pDBEssence.require_reputation;
|
||||
CurEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE;
|
||||
MaxEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE;
|
||||
CurEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE;
|
||||
MaxEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE;
|
||||
}
|
||||
// Get item icon file name
|
||||
public override string GetIconFile()
|
||||
|
||||
@@ -207,8 +207,8 @@ namespace PerfectWorld.Scripts.Managers
|
||||
StrengthReq = m_pDBEssence.require_strength;
|
||||
AgilityReq = m_pDBEssence.require_agility;
|
||||
ReputationReq = m_pDBEssence.require_reputation;
|
||||
CurEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE;
|
||||
MaxEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE;
|
||||
CurEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE;
|
||||
MaxEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE;
|
||||
}
|
||||
// Get item icon file name
|
||||
public override string GetIconFile()
|
||||
|
||||
@@ -174,8 +174,8 @@ namespace PerfectWorld.Scripts.Managers
|
||||
StrengthReq = 0;
|
||||
AgilityReq = 0;
|
||||
ReputationReq = m_pDBEssence.require_reputation;
|
||||
CurEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE;
|
||||
MaxEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE;
|
||||
CurEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE;
|
||||
MaxEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE;
|
||||
}
|
||||
public override string GetIconFile()
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@ using System.Text.RegularExpressions;
|
||||
using System.Reflection;
|
||||
using BrewMonster.Scripts.Managers;
|
||||
using BrewMonster.Scripts;
|
||||
|
||||
namespace PerfectWorld.Scripts.Managers
|
||||
{
|
||||
/// <summary>
|
||||
@@ -161,9 +160,6 @@ namespace PerfectWorld.Scripts.Managers
|
||||
// Scale Types
|
||||
public const int SCALE_SELL = 1;
|
||||
|
||||
// Endurance Scale
|
||||
public const int ENDURANCE_SCALE = 100;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Fields
|
||||
@@ -925,7 +921,7 @@ namespace PerfectWorld.Scripts.Managers
|
||||
/// </summary>
|
||||
public static int VisualizeEndurance(int v)
|
||||
{
|
||||
return (v + ENDURANCE_SCALE - 1) / ENDURANCE_SCALE;
|
||||
return (v + GameConstants.ENDURANCE_SCALE - 1) / GameConstants.ENDURANCE_SCALE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -115,8 +115,8 @@ namespace BrewMonster.Scripts.Managers
|
||||
magic_damage = dr.ReadInt();
|
||||
defense = dr.ReadInt();
|
||||
armor = dr.ReadInt();
|
||||
resistance = new int[InventoryConst.NUM_MAGICCLASS];
|
||||
for (int i = 0; i < InventoryConst.NUM_MAGICCLASS; i++)
|
||||
resistance = new int[GameConstants.NUM_MAGICCLASS];
|
||||
for (int i = 0; i < GameConstants.NUM_MAGICCLASS; i++)
|
||||
{
|
||||
resistance[i] = dr.ReadInt();
|
||||
}
|
||||
@@ -132,13 +132,13 @@ namespace BrewMonster.Scripts.Managers
|
||||
public int[] resistance;
|
||||
public IVTR_ESSENCE_ARMOR(byte[] data)
|
||||
{
|
||||
resistance = new int[InventoryConst.NUM_MAGICCLASS];
|
||||
resistance = new int[GameConstants.NUM_MAGICCLASS];
|
||||
CECDataReader dr = new(data, data.Length);
|
||||
defense = dr.ReadInt();
|
||||
armor = dr.ReadInt();
|
||||
mp_enhance = dr.ReadInt();
|
||||
hp_enhance = dr.ReadInt();
|
||||
for (int i = 0; i < InventoryConst.NUM_MAGICCLASS; i++)
|
||||
for (int i = 0; i < GameConstants.NUM_MAGICCLASS; i++)
|
||||
{
|
||||
resistance[i] = dr.ReadInt();
|
||||
}
|
||||
|
||||
@@ -142,14 +142,22 @@ namespace PerfectWorld.Scripts.Managers
|
||||
|
||||
if (host != null && cid == host.GetCharacterID())
|
||||
{
|
||||
host.ProcessMessage(Msg);
|
||||
// Call OnMsgPlayerExtState directly instead of ProcessMessage
|
||||
// ProcessMessage doesn't handle MSG_PM_PLAYEREXTSTATE
|
||||
// 直接调用OnMsgPlayerExtState而不是ProcessMessage
|
||||
// ProcessMessage不处理MSG_PM_PLAYEREXTSTATE
|
||||
host.OnMsgPlayerExtState(Msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
EC_ElsePlayer elsePlayer = SeekOutElsePlayer(cid);
|
||||
if (elsePlayer != null)
|
||||
{
|
||||
elsePlayer.ProcessMessage(Msg);
|
||||
// Call OnMsgPlayerExtState directly instead of ProcessMessage
|
||||
// ProcessMessage doesn't handle MSG_PM_PLAYEREXTSTATE
|
||||
// 直接调用OnMsgPlayerExtState而不是ProcessMessage
|
||||
// ProcessMessage不处理MSG_PM_PLAYEREXTSTATE
|
||||
elsePlayer.OnMsgPlayerExtState(Msg);
|
||||
}
|
||||
|
||||
if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY && host != null && host.GetTeam() != null)
|
||||
|
||||
@@ -231,8 +231,7 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
// Constants
|
||||
public const int EC_MAXNOPKLEVEL = 0; // The maximum no PK level
|
||||
public const float EC_TABSEL_DIST = 60.0f; // Distance of TAB selection
|
||||
public const int NUM_MAGICCLASS = 5;
|
||||
public const float EC_TABSEL_DIST = 60.0f;
|
||||
public const int NUM_ESBYTE = (int)(ExtendState.NUM_EXTSTATE + 31) >> 5;
|
||||
|
||||
// Helper methods for bit manipulation (equivalent to the C++ inline functions)
|
||||
|
||||
@@ -741,6 +741,15 @@ namespace BrewMonster
|
||||
public virtual void SetNewExtendStates(int unknown, uint[] states, int count)
|
||||
{
|
||||
// TODO: Implement appearance or physics change
|
||||
|
||||
// Remove all trace target GFX when buff states change
|
||||
// This ensures buff-related trail effects are cleaned up when buffs expire
|
||||
// 当buff状态改变时移除所有跟踪目标GFX
|
||||
// 这确保buff相关的轨迹效果在buff过期时被清理
|
||||
if (SkillGfxMan.InstanceSub != null)
|
||||
{
|
||||
SkillGfxMan.InstanceSub.RemoveAllTraceTargetGfx();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetUpPlayer()
|
||||
@@ -2202,7 +2211,45 @@ namespace BrewMonster
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void OnMsgEnchantResult(ECMSG msg)
|
||||
{
|
||||
// 从消息中获取cmd_enchant_result结构 // Get cmd_enchant_result structure from message
|
||||
cmd_enchant_result pCmd = GPDataTypeHelper.FromBytes<cmd_enchant_result>((byte[])msg.dwParam1);
|
||||
|
||||
// 初始化掩码为全1 // Initialize mask to all 1s
|
||||
uint mask = 0xFFFFFFFF;
|
||||
|
||||
// 如果目标不是主机玩家且当前不是主机玩家,则过滤会引起气泡文本的修饰符
|
||||
// We should filter out these things that will cause bubble texts
|
||||
CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer();
|
||||
if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer())
|
||||
{
|
||||
mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE |
|
||||
MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED);
|
||||
}
|
||||
|
||||
// 获取修饰符 // Get modifier
|
||||
uint dwModifier = (uint)pCmd.attack_flag;
|
||||
|
||||
// 获取技能类型 // Get skill type
|
||||
int nDamage = -2; // 默认为-2,不会引起受伤动作 // Default to -2, will not cause wounded action
|
||||
|
||||
if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK)
|
||||
{
|
||||
// 只有攻击技能会引起受伤动作,伤害值为-1 // Only attack skill will cause wounded action, when damage is -1
|
||||
nDamage = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他技能不会引起受伤动作,伤害值设为-2 // Other skills will not cause wounded action, so we set damage to -2
|
||||
nDamage = -2;
|
||||
}
|
||||
|
||||
// 播放攻击效果 // Play attack effect
|
||||
int attackTime = 0;
|
||||
PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage,
|
||||
dwModifier & mask, 0, ref attackTime, pCmd.section);
|
||||
}
|
||||
// 判断是否在飞行 / Check if flying
|
||||
public bool IsFlying()
|
||||
{
|
||||
|
||||
@@ -470,7 +470,7 @@ public class CECNPC : CECObject
|
||||
{
|
||||
return m_pNPCModelPolicy.PlayAttackAction(nAttackSpeed, attackevent);
|
||||
}
|
||||
void NPCTurnFaceTo(int idTarget, float dwTime = 0.3f)
|
||||
public void NPCTurnFaceTo(int idTarget, float dwTime = 0.3f)
|
||||
{
|
||||
if (IsDirFixed())
|
||||
{
|
||||
|
||||
@@ -1539,6 +1539,18 @@ namespace CSNetwork.GPDataType
|
||||
public byte section;
|
||||
};
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_host_skill_attacked
|
||||
{
|
||||
public int idAttacker;
|
||||
public int idSkill;
|
||||
public int iDamage;
|
||||
public byte cEquipment; // The equipment which is mangled, ��λ������ι����Dz���Ӧ�ñ��ɫ
|
||||
|
||||
public int attack_flag; //��Ǹù����Ƿ��й����Ż����ͷ����Ż������ػ�����
|
||||
public byte speed; //�����ٶ� speed * 50 ms
|
||||
public byte section; // skill section
|
||||
};
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_matter_info_list
|
||||
{
|
||||
public ushort count;
|
||||
@@ -2929,5 +2941,6 @@ namespace CSNetwork.GPDataType
|
||||
{
|
||||
public int id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1123,6 +1123,9 @@ namespace CSNetwork
|
||||
case CommandID.HOST_SKILL_ATTACK_RESULT:
|
||||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SKILLRESULT, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
|
||||
break;
|
||||
case CommandID.HOST_SKILL_ATTACKED:
|
||||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SKILLATTACKED, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
|
||||
break;
|
||||
case CommandID.CHANGE_FACE_START:
|
||||
case CommandID.CHANGE_FACE_END:
|
||||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CHANGEFACE, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, dwDataSize);
|
||||
|
||||
@@ -447,36 +447,6 @@ namespace BrewMonster
|
||||
|
||||
public bool ProcessMessage(ECMSG Msg)
|
||||
{
|
||||
// Log ALL messages for this player to debug missing attack results
|
||||
// Filter out common noise messages but log important ones
|
||||
int msgType = (int)Msg.dwMsg;
|
||||
int param2 = Convert.ToInt32(Msg.dwParam2);
|
||||
|
||||
// Log skill-related messages
|
||||
if (msgType == EC_MsgDef.MSG_PM_CASTSKILL || msgType == EC_MsgDef.MSG_PM_PLAYERATKRESULT)
|
||||
{
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] ProcessMessage: Received message, playerID={m_PlayerInfo.cid}, " +
|
||||
$"msgType={msgType}, subID={Msg.iSubID}, param2={param2}, " +
|
||||
$"m_pCurSkill={(m_pCurSkill != null ? m_pCurSkill.GetSkillID().ToString() : "null")}");
|
||||
}
|
||||
|
||||
// Log any unknown command IDs in MSG_PM_CASTSKILL to catch OBJECT_SKILL_ATTACK_RESULT
|
||||
if (msgType == EC_MsgDef.MSG_PM_CASTSKILL)
|
||||
{
|
||||
// Check if this might be OBJECT_SKILL_ATTACK_RESULT (unknown command ID)
|
||||
if (param2 != CommandID.OBJECT_CAST_SKILL &&
|
||||
param2 != CommandID.OBJECT_CAST_INSTANT_SKILL &&
|
||||
param2 != CommandID.OBJECT_CAST_POS_SKILL &&
|
||||
param2 != CommandID.SKILL_PERFORM &&
|
||||
param2 != CommandID.SKILL_INTERRUPTED &&
|
||||
param2 != CommandID.PLAYER_CAST_RUNE_SKILL &&
|
||||
param2 != CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL)
|
||||
{
|
||||
BMLogger.LogWarning($"[ELSEPLAYER_SKILL_FLOW] ProcessMessage: Unknown commandID={param2} in MSG_PM_CASTSKILL! " +
|
||||
$"This might be OBJECT_SKILL_ATTACK_RESULT - we need to handle it!");
|
||||
}
|
||||
}
|
||||
|
||||
switch (Msg.dwMsg)
|
||||
{
|
||||
case EC_MsgDef.MSG_PM_PLAYERFLY: OnMsgPlayerFly(Msg); break;
|
||||
@@ -484,6 +454,7 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_PM_PLAYEREQUIPDATA: OnMsgPlayerEquipData(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_PLAYERATKRESULT: OnMsgPlayerAtkResult(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_ENCHANTRESULT: OnMsgEnchantResult(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_PLAYERDOEMOTE: OnMsgPlayerDoEmote(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_PLAYERSKILLRESULT: OnMsgPlayerSkillResult(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_PLAYERGATHER: OnMsgPlayerGather(Msg); break;
|
||||
@@ -510,30 +481,21 @@ namespace BrewMonster
|
||||
{
|
||||
cmd_object_skill_attack_result pCmd = GPDataTypeHelper.FromBytes<cmd_object_skill_attack_result>((byte[])Msg.dwParam1);
|
||||
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerSkillResult: Entry, attackerID={pCmd.attacker_id}, targetID={pCmd.target_id}, " +
|
||||
$"skillID={pCmd.skill_id}, damage={pCmd.damage}, speed={pCmd.speed}, attack_flag={pCmd.attack_flag}, section={pCmd.section}");
|
||||
|
||||
// Face to target
|
||||
TurnFaceTo(pCmd.target_id);
|
||||
|
||||
// Call PlayAttackEffect with skill_id directly from command (like C++ does)
|
||||
// Unlike OnMsgPlayerAtkResult, we get skill_id from the command structure, not from m_pCurSkill
|
||||
int attackTime = int.MinValue;
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerSkillResult: Calling PlayAttackEffect: target={pCmd.target_id}, skillID={pCmd.skill_id}, " +
|
||||
$"skillLevel=0, damage={pCmd.damage}, attack_flag={pCmd.attack_flag}, speed={pCmd.speed * 50}, section={pCmd.section}");
|
||||
PlayAttackEffect(pCmd.target_id, pCmd.skill_id, 0, -1,
|
||||
(uint)pCmd.attack_flag, pCmd.speed * 50, ref attackTime, pCmd.section);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerSkillResult: PlayAttackEffect complete, attackTime={attackTime}");
|
||||
|
||||
// Check skill type and enter fight state if needed (matching C++ logic)
|
||||
byte skillType = ElementSkill.GetType((uint)pCmd.skill_id);
|
||||
if (skillType == (byte)skill_type.TYPE_ATTACK || skillType == (byte)skill_type.TYPE_CURSE)
|
||||
{
|
||||
EnterFightState();
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerSkillResult: Entered fight state (skillType={skillType})");
|
||||
}
|
||||
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerSkillResult: Complete");
|
||||
}
|
||||
|
||||
public void HandleRevive(short sReviveType, A3DVECTOR3 pos)
|
||||
@@ -624,63 +586,21 @@ namespace BrewMonster
|
||||
cmd_object_atk_result pCmd = GPDataTypeHelper.FromBytes<cmd_object_atk_result>((byte[])Msg.dwParam1);
|
||||
//ASSERT(pCmd && pCmd.attacker_id == m_PlayerInfo.cid);
|
||||
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerAtkResult: Entry, attackerID={pCmd.attacker_id}, targetID={pCmd.target_id}, " +
|
||||
$"damage={pCmd.damage}, speed={pCmd.speed}, attack_flag={pCmd.attack_flag}, m_pCurSkill={(m_pCurSkill != null ? m_pCurSkill.GetSkillID().ToString() : "null")}");
|
||||
|
||||
// Face to target
|
||||
TurnFaceTo(pCmd.target_id);
|
||||
|
||||
// Check if this is a skill attack or melee attack
|
||||
// For skill attacks, we need to get the skill ID from the current skill
|
||||
int idSkill = 0;
|
||||
int skillLevel = 0;
|
||||
int nSection = 0;
|
||||
|
||||
// If we have a current skill being cast, use it for the attack effect
|
||||
if (m_pCurSkill != null)
|
||||
{
|
||||
idSkill = m_pCurSkill.GetSkillID();
|
||||
skillLevel = m_pCurSkill.GetSkillLevel();
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerAtkResult: Skill attack detected, skillID={idSkill}, skillLevel={skillLevel}");
|
||||
}
|
||||
else
|
||||
{
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerAtkResult: Melee attack (m_pCurSkill is null)");
|
||||
}
|
||||
|
||||
// TO DO: fix later
|
||||
int attackTime = int.MinValue;
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] Calling PlayAttackEffect: target={pCmd.target_id}, skillID={idSkill}, skillLevel={skillLevel}, " +
|
||||
$"damage={pCmd.damage}, attack_flag={pCmd.attack_flag}, speed={pCmd.speed * 50}");
|
||||
PlayAttackEffect(pCmd.target_id, idSkill, skillLevel, -1, (uint)pCmd.attack_flag, pCmd.speed * 50, ref attackTime);
|
||||
PlayAttackEffect(pCmd.target_id, 0, 0, -1, (uint)pCmd.attack_flag, pCmd.speed * 50, ref attackTime);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] PlayAttackEffect: Complete, attackTime={attackTime}");
|
||||
|
||||
// Only start melee work if this is a melee attack (idSkill == 0)
|
||||
if (idSkill == 0)
|
||||
{
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerAtkResult: Starting melee work for target={pCmd.target_id}");
|
||||
if (!m_pEPWorkMan.FindWork(CECEPWorkMan.Work_type.WT_NORMAL, CECEPWork.EP_work_ID.WORK_HACKOBJECT))
|
||||
if (!m_pEPWorkMan.FindWork(CECEPWorkMan.Work_type.WT_NORMAL, CECEPWork.EP_work_ID.WORK_HACKOBJECT))
|
||||
{
|
||||
m_pEPWorkMan.StartNormalWork(new CECEPWorkMelee(m_pEPWorkMan, pCmd.target_id));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For skill attacks, the attack effect will use m_pCurSkill to get skill info
|
||||
// The GFX system (CECAttacksMan) will handle spawning effects at hook positions
|
||||
// We keep m_pCurSkill until the next cast or interruption to allow
|
||||
// multiple attack results for the same skill cast (multi-hit skills)
|
||||
// The skill will be cleared when:
|
||||
// 1. A new skill is cast (replaced in OnMsgPlayerCastSkill)
|
||||
// 2. Skill is interrupted (SKILL_INTERRUPTED message)
|
||||
// 3. Player stops casting (handled by server messages)
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerAtkResult: Skill attack - GFX should be triggered via CECAttacksMan, " +
|
||||
$"keeping m_pCurSkill={(m_pCurSkill != null ? m_pCurSkill.GetSkillID().ToString() : "null")}");
|
||||
}
|
||||
|
||||
// Enter fight state
|
||||
EnterFightState();
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerAtkResult: Complete");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -699,7 +619,6 @@ namespace BrewMonster
|
||||
private void OnMsgPlayerCastSkill(ECMSG Msg)
|
||||
{
|
||||
int commandID = Convert.ToInt32(Msg.dwParam2);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerCastSkill: Entry, playerID={m_PlayerInfo.cid}, commandID={commandID}");
|
||||
|
||||
switch (commandID)
|
||||
{
|
||||
@@ -712,8 +631,6 @@ namespace BrewMonster
|
||||
// For else players, we mainly need the skill ID for animation purposes
|
||||
int skillID = pCmd.skill;
|
||||
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OBJECT_CAST_SKILL: playerID={m_PlayerInfo.cid}, skillID={skillID}, target={pCmd.target}, time={pCmd.time}");
|
||||
|
||||
// Store current skill target
|
||||
m_idCurSkillTarget = pCmd.target;
|
||||
|
||||
@@ -721,9 +638,7 @@ namespace BrewMonster
|
||||
TurnFaceTo(pCmd.target);
|
||||
|
||||
// Play skill cast animation
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] Calling PlaySkillCastAction: skillID={skillID}");
|
||||
bool castActionResult = PlaySkillCastAction(skillID);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] PlaySkillCastAction result: {castActionResult}");
|
||||
PlaySkillCastAction(skillID);
|
||||
|
||||
// Create a temporary skill object for tracking (if needed)
|
||||
// Note: Else players don't maintain skill lists like host player does
|
||||
@@ -732,17 +647,11 @@ namespace BrewMonster
|
||||
{
|
||||
// Create a temporary skill object with level 1 (we don't know the actual level)
|
||||
m_pCurSkill = new CECSkill(skillID, 1);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] Created new CECSkill: skillID={skillID}, level=1");
|
||||
}
|
||||
else
|
||||
{
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] Reusing existing m_pCurSkill: skillID={m_pCurSkill.GetSkillID()}");
|
||||
}
|
||||
|
||||
// Enter fight state
|
||||
EnterFightState();
|
||||
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OBJECT_CAST_SKILL: Complete, m_pCurSkill={(m_pCurSkill != null ? m_pCurSkill.GetSkillID().ToString() : "null")}, m_idCurSkillTarget={m_idCurSkillTarget}");
|
||||
break;
|
||||
}
|
||||
case CommandID.OBJECT_CAST_INSTANT_SKILL:
|
||||
@@ -751,18 +660,15 @@ namespace BrewMonster
|
||||
GPDataTypeHelper.FromBytes<cmd_object_cast_instant_skill>((byte[])Msg.dwParam1);
|
||||
|
||||
int skillID = pCmd.skill;
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OBJECT_CAST_INSTANT_SKILL: playerID={m_PlayerInfo.cid}, skillID={skillID}, target={pCmd.target}");
|
||||
|
||||
m_idCurSkillTarget = pCmd.target;
|
||||
|
||||
TurnFaceTo(pCmd.target);
|
||||
bool instantResult = PlaySkillCastAction(skillID);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] PlaySkillCastAction (instant) result: {instantResult}");
|
||||
PlaySkillCastAction(skillID);
|
||||
|
||||
if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID)
|
||||
{
|
||||
m_pCurSkill = new CECSkill(skillID, 1);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] Created new CECSkill (instant): skillID={skillID}");
|
||||
}
|
||||
|
||||
EnterFightState();
|
||||
@@ -774,17 +680,14 @@ namespace BrewMonster
|
||||
GPDataTypeHelper.FromBytes<cmd_object_cast_pos_skill>((byte[])Msg.dwParam1);
|
||||
|
||||
int skillID = pCmd.skill;
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] OBJECT_CAST_POS_SKILL: playerID={m_PlayerInfo.cid}, skillID={skillID}, pos=({pCmd.pos.x:F2}, {pCmd.pos.y:F2}, {pCmd.pos.z:F2})");
|
||||
|
||||
// For position-based skills, target is the position, not an object
|
||||
// We still play the cast animation
|
||||
bool posResult = PlaySkillCastAction(skillID);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] PlaySkillCastAction (pos) result: {posResult}");
|
||||
PlaySkillCastAction(skillID);
|
||||
|
||||
if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID)
|
||||
{
|
||||
m_pCurSkill = new CECSkill(skillID, 1);
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] Created new CECSkill (pos): skillID={skillID}");
|
||||
}
|
||||
|
||||
EnterFightState();
|
||||
@@ -796,26 +699,10 @@ namespace BrewMonster
|
||||
// For else players, we keep m_pCurSkill until attack result is received
|
||||
// This allows PlayAttackEffect to use the skill information
|
||||
// Durative skills (channeling) will continue until interrupted
|
||||
int performSkillID = m_pCurSkill != null ? m_pCurSkill.GetSkillID() : 0;
|
||||
bool isDurative = m_pCurSkill != null && m_pCurSkill.IsDurative();
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] SKILL_PERFORM: playerID={m_PlayerInfo.cid}, skillID={performSkillID}, isDurative={isDurative}, " +
|
||||
$"m_idCurSkillTarget={m_idCurSkillTarget}");
|
||||
|
||||
if (m_pCurSkill != null && m_pCurSkill.IsDurative())
|
||||
{
|
||||
// For durative skills, we keep the skill active
|
||||
// It will be cleared when SKILL_INTERRUPTED is received
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] SKILL_PERFORM: Durative skill, keeping m_pCurSkill active");
|
||||
}
|
||||
else if (m_pCurSkill != null && m_idCurSkillTarget != 0)
|
||||
{
|
||||
// For non-durative skills with a target, if server doesn't send attack result,
|
||||
// we might need to trigger GFX directly from SKILL_PERFORM
|
||||
// But normally attack result should come through OnMsgPlayerAtkResult
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] SKILL_PERFORM: Non-durative skill with target - " +
|
||||
$"Waiting for attack result message. If no attack result arrives, GFX will not spawn!");
|
||||
BMLogger.LogWarning($"[ELSEPLAYER_SKILL_FLOW] SKILL_PERFORM: WARNING - If you don't see OnMsgPlayerAtkResult logs after this, " +
|
||||
$"the server is not sending attack results for else players' skills!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -825,29 +712,21 @@ namespace BrewMonster
|
||||
cmd_skill_interrupted pCmd =
|
||||
GPDataTypeHelper.FromBytes<cmd_skill_interrupted>((byte[])Msg.dwParam1);
|
||||
|
||||
int interruptedSkillID = m_pCurSkill != null ? m_pCurSkill.GetSkillID() : 0;
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] SKILL_INTERRUPTED: playerID={m_PlayerInfo.cid}, skillID={interruptedSkillID}, caster={pCmd.caster}");
|
||||
|
||||
if (m_pCurSkill != null)
|
||||
{
|
||||
StopSkillCastAction();
|
||||
m_pCurSkill = null;
|
||||
BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] SKILL_INTERRUPTED: Cleared m_pCurSkill and stopped cast action");
|
||||
}
|
||||
m_idCurSkillTarget = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
BMLogger.LogWarning($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerCastSkill: Unknown commandID={commandID} - " +
|
||||
$"This might be OBJECT_SKILL_ATTACK_RESULT or another skill-related message we need to handle!");
|
||||
BMLogger.LogWarning($"[ELSEPLAYER_SKILL_FLOW] OnMsgPlayerCastSkill: Unknown command - " +
|
||||
$"If this is OBJECT_SKILL_ATTACK_RESULT, we need to add a handler for it to trigger GFX!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async void LoadAppearGfx()
|
||||
{
|
||||
if (!m_pAppearGFX && m_iAppearFlag == (int)PlayerAppearFlag.APPEAR_ENTERWORLD)
|
||||
|
||||
@@ -206,11 +206,11 @@ RectTransform:
|
||||
- {fileID: 6133989890986254344}
|
||||
m_Father: {fileID: 1983722419643715407}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: -545.9587, y: 54.83423}
|
||||
m_SizeDelta: {x: -1091.9175, y: -653.2429}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 500, y: 426.75708}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!222 &6409592904291504631
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -458,11 +458,11 @@ RectTransform:
|
||||
- {fileID: 4454076196230765805}
|
||||
m_Father: {fileID: 6199635200021499044}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -288.98}
|
||||
m_SizeDelta: {x: 508.681, y: 53}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!1 &4190358850504021446
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -497,11 +497,11 @@ RectTransform:
|
||||
- {fileID: 7473152984931807423}
|
||||
m_Father: {fileID: 6199635200021499044}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -783}
|
||||
m_SizeDelta: {x: 508.681, y: 441.022}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!222 &5213722908587404148
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -553,7 +553,6 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
inputField: {fileID: 2725480406471239880}
|
||||
maxChatLength: 256
|
||||
--- !u!1 &4425286880128952433
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1134,11 +1133,11 @@ RectTransform:
|
||||
- {fileID: 7133716985767026273}
|
||||
m_Father: {fileID: 4963429530816417249}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -746.7, y: 304}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 116, y: -0.000026464}
|
||||
m_SizeDelta: {x: 160, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!222 &5054963699385999060
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1427,7 +1426,7 @@ MonoBehaviour:
|
||||
m_Spacing: 0
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 1
|
||||
m_ChildControlWidth: 0
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 0
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
|
||||
@@ -8,7 +8,7 @@ using System;
|
||||
using UnityEngine;
|
||||
using static BrewMonster.Scripts.CECHPWork;
|
||||
using static CECPlayerWrapper;
|
||||
|
||||
using PerfectWorld.Scripts.Managers;
|
||||
namespace BrewMonster
|
||||
{
|
||||
public partial class CECHostPlayer
|
||||
@@ -40,10 +40,10 @@ namespace BrewMonster
|
||||
|
||||
if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f)
|
||||
{
|
||||
/* char cEquip = (char)(pCmd.cEquipment & 0x7f);
|
||||
CECIvtrEquip pEquip = (CECIvtrEquip)m_pEquipPack.GetItem(cEquip);
|
||||
if (pEquip)
|
||||
pEquip.AddCurEndurance(ARMOR_RUIN_SPEED);*/
|
||||
char cEquip = (char)(pCmd.cEquipment & 0x7f);
|
||||
EC_IvtrEquip pEquip = (EC_IvtrEquip)m_pEquipPack.GetItem(cEquip);
|
||||
if (pEquip != null)
|
||||
pEquip.AddCurEndurance(GameConstants.ARMOR_RUIN_SPEED);
|
||||
}
|
||||
|
||||
// The host player is attacked, we should make an effect here
|
||||
@@ -204,6 +204,49 @@ namespace BrewMonster
|
||||
PlayAttackEffect(pCmd.idTarget, pCmd.idSkill, 0, pCmd.iDamage, (uint)pCmd.attack_flag,
|
||||
pCmd.attack_speed * 50, ref refFake, pCmd.section);
|
||||
}
|
||||
void OnMsgHstSkillAttacked(ECMSG Msg)
|
||||
{
|
||||
cmd_host_skill_attacked pCmd = GPDataTypeHelper.FromBytes<cmd_host_skill_attacked>((byte[])Msg.dwParam1);
|
||||
|
||||
if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f)
|
||||
{
|
||||
EC_IvtrEquip pEquip = (EC_IvtrEquip)m_pEquipPack.GetItem(pCmd.cEquipment & 0x7f);
|
||||
if (pEquip != null)
|
||||
pEquip.AddCurEndurance(GameConstants.ARMOR_RUIN_SPEED);
|
||||
}
|
||||
|
||||
// The host player is attacked, we should make an effect here
|
||||
if( GPDataTypeHelper.ISPLAYERID(pCmd.idAttacker) )
|
||||
{
|
||||
EC_ElsePlayer pAttacker = EC_ManMessageMono.Instance.EC_ManPlayer.GetElsePlayer(pCmd.idAttacker);
|
||||
if (pAttacker)
|
||||
{
|
||||
if( !pAttacker.IsDead() )
|
||||
{
|
||||
// Face to target
|
||||
pAttacker.TurnFaceTo(GetPlayerInfo().cid);
|
||||
}
|
||||
int refFake = 0;
|
||||
pAttacker.PlayAttackEffect(GetCharacterID(), pCmd.idSkill, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.speed * 50,ref refFake,pCmd.section);
|
||||
pAttacker.EnterFightState();
|
||||
}
|
||||
}
|
||||
else if( GPDataTypeHelper.ISNPCID(pCmd.idAttacker) )
|
||||
{
|
||||
CECNPC pAttacker = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idAttacker);
|
||||
if (pAttacker)
|
||||
{
|
||||
if( !pAttacker.IsDead())
|
||||
{
|
||||
// Face to target
|
||||
pAttacker.NPCTurnFaceTo(GetPlayerInfo().cid);
|
||||
}
|
||||
pAttacker.PlayAttackEffect(GetCharacterID(), pCmd.idSkill, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.speed,pCmd.section);
|
||||
}
|
||||
}
|
||||
|
||||
CECAutoPolicy.GetInstance().SendEvent_BeHurt(pCmd.idAttacker);
|
||||
}
|
||||
|
||||
private void OnMsgPlayerCastSkill(ECMSG Msg)
|
||||
{
|
||||
|
||||
@@ -763,45 +763,7 @@ namespace BrewMonster
|
||||
UnityGameSession.c2s_CmdGetItemInfo(Inventory_type.IVTRTYPE_PACK, pCmd.equip_idx);
|
||||
}
|
||||
|
||||
private void OnMsgEnchantResult(ECMSG msg)
|
||||
{
|
||||
// 从消息中获取cmd_enchant_result结构 // Get cmd_enchant_result structure from message
|
||||
cmd_enchant_result pCmd = GPDataTypeHelper.FromBytes<cmd_enchant_result>((byte[])msg.dwParam1);
|
||||
|
||||
// 初始化掩码为全1 // Initialize mask to all 1s
|
||||
uint mask = 0xFFFFFFFF;
|
||||
|
||||
// 如果目标不是主机玩家且当前不是主机玩家,则过滤会引起气泡文本的修饰符
|
||||
// We should filter out these things that will cause bubble texts
|
||||
CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer();
|
||||
if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer())
|
||||
{
|
||||
mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE |
|
||||
MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED);
|
||||
}
|
||||
|
||||
// 获取修饰符 // Get modifier
|
||||
uint dwModifier = (uint)pCmd.attack_flag;
|
||||
|
||||
// 获取技能类型 // Get skill type
|
||||
int nDamage = -2; // 默认为-2,不会引起受伤动作 // Default to -2, will not cause wounded action
|
||||
|
||||
if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK)
|
||||
{
|
||||
// 只有攻击技能会引起受伤动作,伤害值为-1 // Only attack skill will cause wounded action, when damage is -1
|
||||
nDamage = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他技能不会引起受伤动作,伤害值设为-2 // Other skills will not cause wounded action, so we set damage to -2
|
||||
nDamage = -2;
|
||||
}
|
||||
|
||||
// 播放攻击效果 // Play attack effect
|
||||
int attackTime = 0;
|
||||
PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage,
|
||||
dwModifier & mask, 0, ref attackTime, pCmd.section);
|
||||
}
|
||||
|
||||
|
||||
public void OnMsgHstClearTessera(ECMSG Msg)
|
||||
{
|
||||
|
||||
@@ -555,6 +555,7 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_STARTATTACK: OnMsgHstStartAttack(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_STOPATTACK: OnMsgHstStopAttack(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SKILLRESULT: OnMsgHstSkillResult(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SKILLATTACKED: OnMsgHstSkillAttacked(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SETCOOLTIME: OnMsgHstSetCoolTime(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_ENCHANTRESULT: OnMsgEnchantResult(Msg); break;
|
||||
|
||||
+52
-17
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user