stun logic
This commit is contained in:
@@ -324,6 +324,9 @@ namespace BrewMonster
|
||||
public const int EFF_FACEPILL = 1;
|
||||
}
|
||||
private BaseVfxObject _levelUpVfx;
|
||||
// [中文] 当前激活的状态效果 GFX,以 (路径+挂点) 为键
|
||||
// [English] Currently active state-effect GFX objects, keyed by (path + hook)
|
||||
private Dictionary<string, BaseVfxObject> _stateGfxObjects = new Dictionary<string, BaseVfxObject>();
|
||||
protected GameObject[] m_pModels = new GameObject[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX];
|
||||
protected int[] m_aShapeID = new int[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX];
|
||||
|
||||
@@ -895,91 +898,103 @@ namespace BrewMonster
|
||||
// !CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID()))
|
||||
// return;
|
||||
|
||||
//static const char* szBasePath = "������\\״̬Ч��\\";
|
||||
// [中文] 策划联入\状态效果\ (状态效果 GFX 的基础路径)
|
||||
// [English] Designer-integrated state effect GFX base path
|
||||
const string szBasePath = "策划联入/状态效果/";
|
||||
|
||||
const int bitSize = sizeof(uint) * 8;
|
||||
BMLogger.LogError($"[CECPlayer] ShowExtendStates: start: {start}, count: {count}, bitSize: {bitSize}");
|
||||
for (int index = 0; index<count; index++)
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
int idState = index + start;
|
||||
for (int i=0; i < bitSize; i++)
|
||||
for (int i = 0; i < bitSize; i++)
|
||||
{
|
||||
int dwMask = 1 << i;
|
||||
int dwFlag1 = (int)(m_aExtStatesShown[idState] & dwMask);
|
||||
int dwFlag2 = (int)(pData[index] & dwMask);
|
||||
|
||||
// [中文] 两者相同(都激活或都未激活),跳过
|
||||
// [English] Both unchanged (both on or both off), skip
|
||||
if ((dwFlag1 == 0 && dwFlag2 == 0) || (dwFlag1 != 0 && dwFlag2 != 0))
|
||||
continue;
|
||||
|
||||
BMLogger.LogError($"[CECPlayer] ShowExtendStates: idState: {idState}, bitIndex: {i}, i + idState*bitSize: {i + idState * bitSize}");
|
||||
//TODO: Implement visible state
|
||||
// const GNET::VisibleState* pvs = GNET::VisibleState::Query(m_iProfession, i + idState*bitSize);
|
||||
// if (!pvs)
|
||||
// continue;
|
||||
// [中文] 查询可见状态(profession 参数被忽略,仅按 id 查找)
|
||||
// [English] Query visible state (profession is ignored; keyed by id only)
|
||||
VisibleState pvs = VisibleState.Query(m_iProfession, i + idState * bitSize);
|
||||
if (pvs == null)
|
||||
continue;
|
||||
|
||||
// AString strGFXFile = pvs->GetEffect();
|
||||
// if (!strGFXFile.GetLength())
|
||||
// continue;
|
||||
string strEffect = pvs.GetEffect();
|
||||
if (string.IsNullOrEmpty(strEffect))
|
||||
continue;
|
||||
|
||||
// strGFXFile = szBasePath + strGFXFile;
|
||||
string strGFXFile = szBasePath + strEffect;
|
||||
|
||||
// if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState*bitSize))
|
||||
// continue;
|
||||
// [中文] TestProcessPetCureGFX — 宠愈 GFX 系统尚未移植,跳过(等价于始终返回 false)
|
||||
// [English] TestProcessPetCureGFX — pet-cure GFX system not ported yet; skip (equivalent to always false)
|
||||
// if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState * bitSize)) continue;
|
||||
|
||||
if (dwFlag1 != 0)
|
||||
{
|
||||
// [中文] 移除旧状态效果
|
||||
// [English] Remove old state GFX
|
||||
if (SkillGfxMan.InstanceSub != null)
|
||||
{
|
||||
SkillGfxMan.InstanceSub.RemoveAllTraceTargetGfx();
|
||||
}
|
||||
// //TODO: Implement remove old state
|
||||
|
||||
// CECModel *pWeapon = NULL;
|
||||
// bool bLeft (false);
|
||||
// if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
|
||||
// {
|
||||
// // ��������Ч
|
||||
// if (pWeapon)
|
||||
// {
|
||||
// const char * gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
// pWeapon->RemoveGfx(strGFXFile, gfxHook);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
/*bool bLeft = false;
|
||||
CECModel pWeapon = null;
|
||||
if (IsWeaponHookPos(pvs.GetHH(), out bLeft, out pWeapon))
|
||||
{
|
||||
// ģ������Ч
|
||||
// RemoveGfx(strGFXFile, pvs->GetHH(), PLAYERMODEL_TYPEALL);
|
||||
// [中文] 武器上的效果
|
||||
// [English] GFX on weapon model
|
||||
if (pWeapon != null)
|
||||
{
|
||||
string gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
RemoveStateGfxFromModel(pWeapon, strGFXFile, gfxHook);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// [中文] 模型上的效果
|
||||
// [English] GFX on player model
|
||||
RemoveGfx(strGFXFile, pvs.GetHH(), (uint)PLAYERMODEL_TYPE.PLAYERMODEL_TYPEALL);
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// [中文] 添加新状态效果
|
||||
// [English] Add new state GFX
|
||||
string szHH = pvs.GetHH();
|
||||
float fScale;
|
||||
|
||||
// [中文] 根据挂点类型获取模型缩放数据
|
||||
// [English] Determine GFX scale from model outer data based on hook type
|
||||
CECModel majorModel = GetMajorModel()?.GetComponent<CECModel>();
|
||||
if (majorModel != null && szHH.Equals("HH_Head", StringComparison.OrdinalIgnoreCase))
|
||||
fScale = majorModel.GetOuterData()[0];
|
||||
else if (majorModel != null && szHH.Equals("HH_Spine", StringComparison.OrdinalIgnoreCase))
|
||||
fScale = majorModel.GetOuterData()[1];
|
||||
else
|
||||
fScale = 1.0f;
|
||||
|
||||
bool bLeft = false;
|
||||
CECModel pWeapon = null;
|
||||
if (IsWeaponHookPos(szHH, out bLeft, out pWeapon))
|
||||
{
|
||||
// [中文] 武器上的效果
|
||||
// [English] GFX on weapon model
|
||||
if (pWeapon != null)
|
||||
{
|
||||
string gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
PlayStateGfxOnModel(pWeapon, strGFXFile, gfxHook, fScale);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// [中文] 玩家模型上的效果
|
||||
// [English] GFX on player model
|
||||
PlayGfx(strGFXFile, pvs.GetHH(), fScale, (uint)PLAYERMODEL_TYPE.PLAYERMODEL_TYPEALL, true);
|
||||
}
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// // Add new state
|
||||
|
||||
// const char* szHH = pvs->GetHH();
|
||||
// float fScale;
|
||||
|
||||
// if (stricmp("HH_Head", szHH) == 0)
|
||||
// fScale = GetMajorModel()->GetOuterData()[0];
|
||||
// else if (stricmp("HH_Spine", szHH) == 0)
|
||||
// fScale = GetMajorModel()->GetOuterData()[1];
|
||||
// else
|
||||
// fScale = 1.0f;
|
||||
|
||||
// CECModel *pWeapon = NULL;
|
||||
// bool bLeft (false);
|
||||
// if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
|
||||
// {
|
||||
// if (pWeapon)
|
||||
// {
|
||||
// const char *gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
// pWeapon->PlayGfx(strGFXFile, gfxHook, fScale);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// PlayGfx(strGFXFile, pvs->GetHH(), fScale, PLAYERMODEL_TYPEALL, true);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,6 +1011,68 @@ namespace BrewMonster
|
||||
int bitOffset = n % bitSize;
|
||||
return (m_aExtStates[index] & (1 << bitOffset)) != 0;
|
||||
}
|
||||
|
||||
// [中文] 判断挂点是否为武器挂点,并返回对应武器模型和左右手标志
|
||||
// [English] Check if hook pos is a weapon hook; output the corresponding weapon model and left-hand flag
|
||||
protected bool IsWeaponHookPos(string szHH, out bool bLeft, out CECModel pWeapon)
|
||||
{
|
||||
bLeft = false;
|
||||
pWeapon = null;
|
||||
if (string.IsNullOrEmpty(szHH)) return false;
|
||||
|
||||
// [中文] 左手武器挂点(手持或肩部)
|
||||
// [English] Left-hand weapon hook positions (held or shoulder)
|
||||
if (szHH.Equals("HH_lefthandweapon", StringComparison.OrdinalIgnoreCase) ||
|
||||
szHH.Equals("HH_leftsword", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
bLeft = true;
|
||||
pWeapon = GetLeftHandWeapon();
|
||||
return true;
|
||||
}
|
||||
|
||||
// [中文] 右手武器挂点(手持、肩部或镰刀)
|
||||
// [English] Right-hand weapon hook positions (held, shoulder, or sickle/nickle)
|
||||
if (szHH.Equals("HH_righthandweapon", StringComparison.OrdinalIgnoreCase) ||
|
||||
szHH.Equals("HH_rightsword", StringComparison.OrdinalIgnoreCase) ||
|
||||
szHH.Equals("HH_weapon", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
pWeapon = GetRightHandWeapon();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// [中文] 获取左手武器模型(武器 CECModel 未接入时返回 null)
|
||||
// [English] Get left-hand weapon model (returns null until weapon CECModel tracking is wired)
|
||||
protected virtual CECModel GetLeftHandWeapon() => null;
|
||||
|
||||
// [中文] 获取右手武器模型(武器 CECModel 未接入时返回 null)
|
||||
// [English] Get right-hand weapon model (returns null until weapon CECModel tracking is wired)
|
||||
protected virtual CECModel GetRightHandWeapon() => null;
|
||||
|
||||
// [中文] 获取武器上用于挂载 GFX 的挂点名称
|
||||
// [English] Get the GFX hook position name on the weapon model
|
||||
protected string GetWeaponGFXHookPos(CECModel pModel, bool bLeft)
|
||||
{
|
||||
// [中文] 武器 CECModel 挂点逻辑未接入,暂时返回 null
|
||||
// [English] Weapon CECModel hook logic not wired yet; return null for now
|
||||
return null;
|
||||
}
|
||||
|
||||
// [中文] 从玩家模型上移除状态效果 GFX
|
||||
// [English] Remove a state-effect GFX from the player model
|
||||
protected void RemoveGfx(string szPath, string szHook, uint iShapeTypeMask)
|
||||
{
|
||||
string key = szPath + szHook;
|
||||
if (_stateGfxObjects.TryGetValue(key, out BaseVfxObject vfx) && vfx != null)
|
||||
{
|
||||
vfx.Stop();
|
||||
Destroy(vfx.gameObject);
|
||||
_stateGfxObjects.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetUpPlayer()
|
||||
{
|
||||
m_dwResFlags = 0;
|
||||
@@ -1708,15 +1785,15 @@ namespace BrewMonster
|
||||
//swing sfx
|
||||
//workaround for sound effect delay, it need to trigger via weapon combine action
|
||||
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundPath, Vector3.zero,iTransTime/1000f).Forget();
|
||||
|
||||
|
||||
szAct = EC_Utility.BuildActionName(action, weapon_type, "落");
|
||||
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
|
||||
|
||||
|
||||
//hit sfx
|
||||
//workaround for sound effect delay, it need to trigger via weapon combine action
|
||||
//.1f is a magic number to make sure the sound effect is triggered after the action is finished
|
||||
SFXManager.Instance.PlaySkillSfxAtPointAsync(hitSoundPath, Vector3.zero,iTransTime/1000f+.1f).Forget();
|
||||
|
||||
|
||||
//PlayNonSkillActionWithName(iAction, szAct, true, 200, true, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);gagága
|
||||
/*
|
||||
if (pRightHandWeapon != null && IsUsingMagicWeapon())
|
||||
@@ -2832,10 +2909,53 @@ namespace BrewMonster
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
PlayLevelUpGfx(szPath);
|
||||
// [中文] 路由到状态 GFX 播放(支持多 GFX 同时激活)
|
||||
// [English] Route to state GFX playback (supports multiple concurrent GFX)
|
||||
_ = PlayStateGfxAsync(szPath, szHook, fScale);
|
||||
return false;
|
||||
}
|
||||
|
||||
// [中文] 异步加载并播放状态效果 GFX,以 (路径+挂点) 为键去重
|
||||
// [English] Asynchronously load and play a state-effect GFX; keyed by (path+hook) to deduplicate
|
||||
private async Task PlayStateGfxAsync(string path, string hook, float fScale)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return;
|
||||
string key = path + hook;
|
||||
if (_stateGfxObjects.ContainsKey(key)) return; // [中文] 已激活,跳过 / [English] Already active, skip
|
||||
|
||||
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
|
||||
if (prefab == null)
|
||||
{
|
||||
BMLogger.LogWarning($"[StateGFX] Failed to load prefab: {path}");
|
||||
return;
|
||||
}
|
||||
|
||||
// [中文] 实例化挂载在玩家 transform 下,初始位置归零
|
||||
// [English] Instantiate parented to player transform with zeroed local position
|
||||
BaseVfxObject vfx = Instantiate(prefab, transform).GetComponent<BaseVfxObject>();
|
||||
if (vfx == null) return;
|
||||
|
||||
vfx.transform.localPosition = Vector3.zero;
|
||||
vfx.SetScale(fScale);
|
||||
vfx.Play();
|
||||
_stateGfxObjects[key] = vfx;
|
||||
BMLogger.Log($"[StateGFX] Playing: {path}, hook: {hook}, scale: {fScale}");
|
||||
}
|
||||
|
||||
// [中文] 在武器 CECModel 上移除状态效果 GFX(武器挂点逻辑未接入,暂存桩)
|
||||
// [English] Remove state-effect GFX from weapon CECModel (weapon hook not wired yet; stub)
|
||||
private void RemoveStateGfxFromModel(CECModel model, string path, string hook)
|
||||
{
|
||||
// TODO: implement when weapon CECModel GFX tracking is available
|
||||
}
|
||||
|
||||
// [中文] 在武器 CECModel 上播放状态效果 GFX(武器挂点逻辑未接入,暂存桩)
|
||||
// [English] Play state-effect GFX on weapon CECModel (weapon hook not wired yet; stub)
|
||||
private void PlayStateGfxOnModel(CECModel model, string path, string hook, float fScale)
|
||||
{
|
||||
// TODO: implement when weapon CECModel GFX tracking is available
|
||||
}
|
||||
|
||||
private async void PlayLevelUpGfx(string path)
|
||||
{
|
||||
// Usage: Load the prefab asynchronously using AddressableManager
|
||||
@@ -3967,7 +4087,7 @@ namespace BrewMonster
|
||||
public CECAttackEvent AttackEvent;
|
||||
public bool IsHitAnim;
|
||||
public bool IsForceStopPrevious;
|
||||
public bool IsLoop;
|
||||
public bool IsLoop;
|
||||
public QueueActionEvent(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
|
||||
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
|
||||
{
|
||||
|
||||
@@ -127,7 +127,7 @@ public class CECModelStaticData
|
||||
SrcBlend = A3DBLEND.A3DBLEND_SRCALPHA,
|
||||
DestBlend = A3DBLEND.A3DBLEND_INVSRCALPHA
|
||||
};
|
||||
private readonly float[] m_OuterData = new float[CECModelConstants.OUTER_DATA_COUNT];
|
||||
public float[] m_OuterData = new float[CECModelConstants.OUTER_DATA_COUNT];
|
||||
private bool m_bCanCastShadow = true;
|
||||
private bool m_bRenderSkinModel = true;
|
||||
private bool m_bRenderEdge = true;
|
||||
@@ -524,6 +524,7 @@ public class CECModel
|
||||
}
|
||||
return hook;
|
||||
}
|
||||
public float[] GetOuterData() { return m_pMapModel.m_OuterData; }
|
||||
|
||||
/// <summary>
|
||||
/// Invalidate hook cache (call when model reloads)
|
||||
|
||||
@@ -612,7 +612,13 @@ namespace BrewMonster.Scripts.Skills
|
||||
public virtual string GetName() { return null; }
|
||||
public virtual string GetHH() { return null; }
|
||||
public virtual string GetEffect() { return null; }
|
||||
public static VisibleState Query(int profession, int id) { return null; }
|
||||
public static VisibleState Query(int profession, int id)
|
||||
{
|
||||
// [中文] C++ 实现同样忽略 profession,只按 id 查找
|
||||
// [English] C++ impl also ignores profession; keyed by id only
|
||||
GNET.VisibleState.TryGetValue(id, out var result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public class TeamState
|
||||
{
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"header": 1992,
|
||||
"param": 0,
|
||||
"hasParam": false,
|
||||
"describe": "Buff rage",
|
||||
"lastUsedUtcTicks": 639134653927186702
|
||||
},
|
||||
{
|
||||
"header": 1988,
|
||||
"param": 0,
|
||||
@@ -20,13 +27,6 @@
|
||||
"hasParam": true,
|
||||
"describe": "NoCooldown",
|
||||
"lastUsedUtcTicks": 639123542141980400
|
||||
},
|
||||
{
|
||||
"header": 1992,
|
||||
"param": 0,
|
||||
"hasParam": false,
|
||||
"describe": "Buff rage",
|
||||
"lastUsedUtcTicks": 639119244650372830
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -578,6 +578,7 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_SETMOVESTAMP: OnMsgHstSetMoveStamp(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SANCTUARY: OnMsgHstSanctuary(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_RECEIVEEXP: OnMsgHstReceiveExp(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_ROOTNOTIFY: OnMsgHstRootNotify(Msg) ; break;
|
||||
default:
|
||||
// Uncomment to debug unhandled messages
|
||||
// Debug.LogWarning($"[CECHostPlayer] ProcessMessage: Unhandled message {msg}");
|
||||
@@ -604,6 +605,39 @@ namespace BrewMonster
|
||||
}*/
|
||||
}
|
||||
|
||||
private void OnMsgHstRootNotify(in ECMSG Msg)
|
||||
{
|
||||
if ((int)Msg.dwParam2 == CommandID.HOST_NOTIFY_ROOT)
|
||||
{
|
||||
cmd_host_notify_root pCmd = GPDataTypeHelper.FromBytes<cmd_host_notify_root>((byte[])Msg.dwParam1);
|
||||
m_dwLIES |=(uint) (1 << pCmd.type);
|
||||
|
||||
if (pCmd.type != 3)
|
||||
{
|
||||
// Force pull host to specified position
|
||||
SetPos(EC_Utility.ToVector3(pCmd.pos));
|
||||
}
|
||||
|
||||
if (IsRooting())
|
||||
{
|
||||
if (m_pWorkMan.IsFollowing()){
|
||||
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_FOLLOW);
|
||||
}
|
||||
if (m_pWorkMan.IsMovingToPosition()){
|
||||
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_MOVETOPOS);
|
||||
}
|
||||
if (m_pWorkMan.IsTracing()){
|
||||
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_TRACEOBJECT);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((int)Msg.dwParam2 == CommandID.HOST_DISPEL_ROOT)
|
||||
{
|
||||
cmd_host_dispel_root pCmd = GPDataTypeHelper.FromBytes<cmd_host_dispel_root>((byte[])Msg.dwParam1);
|
||||
m_dwLIES &=(uint) ~(1 << pCmd.type);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMsgHstPickupMoney(ECMSG msg)
|
||||
{
|
||||
var data = msg.dwParam1 as byte[];
|
||||
|
||||
Reference in New Issue
Block a user