Add requirement for play skill
Merge from develop
This commit is contained in:
@@ -67,6 +67,14 @@ namespace BrewMonster
|
||||
[SerializeField]
|
||||
private LogPanelAnimeScene logPanelAnimeScene;
|
||||
|
||||
[Header("Channeling (time_type = 2)")]
|
||||
[Tooltip("Stops durative/channeling skill repeat and allows other skills again.")]
|
||||
[SerializeField] private Button channelCancelButton;
|
||||
|
||||
private Coroutine _channelingCoroutine;
|
||||
private int _channelingSkillId;
|
||||
private bool _isChanneling;
|
||||
|
||||
/// <summary>
|
||||
/// World position of the draggable target marker, read by CECSkillGfxMan.get_pos_by_id.
|
||||
/// 可拖动目标标记的世界坐标,由 CECSkillGfxMan.get_pos_by_id 读取。
|
||||
@@ -79,11 +87,19 @@ namespace BrewMonster
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
<<<<<<< HEAD
|
||||
SkillStubs.Init();
|
||||
=======
|
||||
if (channelCancelButton != null)
|
||||
channelCancelButton.onClick.AddListener(CancelChanneling);
|
||||
>>>>>>> 6fde1d1583 (Add requirement for play skill)
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (channelCancelButton != null)
|
||||
channelCancelButton.onClick.RemoveListener(CancelChanneling);
|
||||
StopChanneling();
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
@@ -455,10 +471,81 @@ namespace BrewMonster
|
||||
return root.GetComponentInChildren<Image>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops channeling repeat and clears pending attack events (wire to cancel button).
|
||||
/// 停止引导重复并清理挂起的攻击事件(绑定到取消按钮)。
|
||||
/// </summary>
|
||||
public void CancelChanneling()
|
||||
{
|
||||
StopChanneling();
|
||||
}
|
||||
|
||||
private void StopChanneling()
|
||||
{
|
||||
_isChanneling = false;
|
||||
_channelingSkillId = 0;
|
||||
|
||||
if (_channelingCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_channelingCoroutine);
|
||||
_channelingCoroutine = null;
|
||||
}
|
||||
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
player.StopSkillAttackAction();
|
||||
EventBus.PublishChannel(player.GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true));
|
||||
|
||||
CECAttackerEvents attackerEvents =
|
||||
CECAttacksMan.Instance?.FindAttackByAttacker(player.GetPlayerInfo().cid);
|
||||
if (attackerEvents)
|
||||
attackerEvents.Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Durative skill: block other skills while an attack event has not fired yet.
|
||||
/// 引导技能:攻击事件尚未触发时,阻止其它技能。
|
||||
/// </summary>
|
||||
private bool ShouldBlockOtherSkillTrigger(CECSkill skill)
|
||||
{
|
||||
if (!_isChanneling || skill == null)
|
||||
return false;
|
||||
|
||||
if (skill.GetSkillID() == _channelingSkillId)
|
||||
return false;
|
||||
|
||||
return HasPendingChannelAttackEvent();
|
||||
}
|
||||
|
||||
private bool HasPendingChannelAttackEvent()
|
||||
{
|
||||
if (!_isChanneling || player == null)
|
||||
return false;
|
||||
|
||||
CECAttackerEvents attackerEvents =
|
||||
CECAttacksMan.Instance?.FindAttackByAttacker(player.GetPlayerInfo().cid);
|
||||
if (!attackerEvents)
|
||||
return false;
|
||||
|
||||
CECAttackEvent pAttack = attackerEvents.Find(_channelingSkillId, 0);
|
||||
return pAttack != null && !pAttack.m_bDoFired;
|
||||
}
|
||||
|
||||
public void LocalCastSkill(CECSkill skill)
|
||||
{
|
||||
if (player == null || skill == null)
|
||||
return;
|
||||
|
||||
if (ShouldBlockOtherSkillTrigger(skill))
|
||||
{
|
||||
Debug.LogWarning($"[SkillTriggerPanel] Blocked skill {skill.GetSkillID()} — channeling skill {_channelingSkillId} attack event pending.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isChanneling)
|
||||
StopChanneling();
|
||||
|
||||
logPanelAnimeScene.Reset();
|
||||
int skillId = skill.GetSkillID();
|
||||
logPanelAnimeScene.AddCopyTextButton("ID", skillId.ToString());
|
||||
@@ -493,56 +580,112 @@ namespace BrewMonster
|
||||
// Debug.LogWarning($"[SkillTriggerPanel] composerMan is null — VFX skipped for skill {skillId}.");
|
||||
// }
|
||||
|
||||
// 3. After 2s, play the release / 施放起+落 attack animation chain (local-only).
|
||||
// 2 秒后播放施放攻击动画链(仅本地)。
|
||||
StartCoroutine(DelayedPlaySkillAttackAction(player, skillId));
|
||||
// 3. After delay, play the release / 施放起+落 attack animation chain (local-only).
|
||||
// 延迟后播放施放攻击动画链(仅本地)
|
||||
if (skill.IsDurative())
|
||||
{
|
||||
_isChanneling = true;
|
||||
_channelingSkillId = skillId;
|
||||
_channelingCoroutine = StartCoroutine(ChannelingSkillRoutine(player, skillId));
|
||||
}
|
||||
else
|
||||
{
|
||||
StartCoroutine(DelayedPlaySkillAttackAction(player, skillId, 2f, replayAttackAnim: false));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator DelayedPlaySkillAttackAction(CECHostPlayer hostPlayer, int skillId)
|
||||
/// <summary>
|
||||
/// Durative (time_type = 2): first hit at 1s, then every 2s until cancel.
|
||||
/// 引导技能:1 秒首次命中,之后每 2 秒重复,直到按下取消。
|
||||
/// </summary>
|
||||
private IEnumerator ChannelingSkillRoutine(CECHostPlayer hostPlayer, int skillId)
|
||||
{
|
||||
|
||||
int attackTime = 0;
|
||||
yield return new WaitForSeconds(1f);
|
||||
if (!_isChanneling || hostPlayer == null)
|
||||
yield break;
|
||||
|
||||
TriggerLocalSkillAttack(hostPlayer, skillId, replayAttackAnim: false);
|
||||
|
||||
while (_isChanneling && hostPlayer != null)
|
||||
{
|
||||
yield return new WaitForSeconds(5f);
|
||||
if (!_isChanneling || hostPlayer == null)
|
||||
yield break;
|
||||
|
||||
while (_isChanneling && HasPendingChannelAttackEvent())
|
||||
yield return null;
|
||||
|
||||
if (!_isChanneling || hostPlayer == null)
|
||||
yield break;
|
||||
|
||||
TriggerLocalSkillAttack(hostPlayer, skillId, replayAttackAnim: true);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator DelayedPlaySkillAttackAction(CECHostPlayer hostPlayer, int skillId, float delaySecs, bool replayAttackAnim)
|
||||
{
|
||||
yield return new WaitForSeconds(delaySecs);
|
||||
if (hostPlayer == null)
|
||||
yield break;
|
||||
|
||||
TriggerLocalSkillAttack(hostPlayer, skillId, replayAttackAnim);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Local-only skill hit: mirrors <see cref="CECPlayer.PlayAttackEffect"/> for debug panel.
|
||||
/// When <paramref name="replayAttackAnim"/> is true (channeling tick), signal prior attack so anim replays.
|
||||
/// 本地技能命中:与 PlayAttackEffect 一致;引导重复 tick 时先 Signal 再重播攻击动作。
|
||||
/// </summary>
|
||||
private void TriggerLocalSkillAttack(CECHostPlayer hostPlayer, int skillId, bool replayAttackAnim)
|
||||
{
|
||||
int attackTime = 0;
|
||||
CECAttackEvent pAttack = null;
|
||||
|
||||
// first try to find if there is already a skill attack event in attackman
|
||||
int targetId = targetMarker != null
|
||||
? targetMarker.GetNPCID()
|
||||
: EncodeDebugNpcId();
|
||||
|
||||
CECAttackerEvents attackerEvents = CECAttacksMan.Instance.FindAttackByAttacker(hostPlayer.GetPlayerInfo().cid);
|
||||
if (attackerEvents)
|
||||
{
|
||||
pAttack = attackerEvents.Find(skillId, 0);
|
||||
if (pAttack != null)
|
||||
{
|
||||
// Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
|
||||
pAttack.AddTarget(DEBUG_TARGET_ID, 1, 1);
|
||||
goto EXIT;
|
||||
if (replayAttackAnim)
|
||||
attackerEvents.Signal();
|
||||
else
|
||||
{
|
||||
// 面攻击的非第一次伤害消息 / Non-first hit on same attack event
|
||||
pAttack.AddTarget(targetId, 1, 1);
|
||||
if (attackTime != 0)
|
||||
attackTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attackerEvents.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
if (ElementSkill.IsGoblinSkill((uint)skillId) &&
|
||||
ElementSkill.GetType((uint)skillId) == 2)
|
||||
ElementSkill.GetType((uint)skillId) == 2)
|
||||
{
|
||||
pAttack = CECAttacksMan.Instance.AddSkillAttack(
|
||||
hostPlayer.GetPlayerInfo().cid, hostPlayer.GetPlayerInfo().cid, hostPlayer.GetPlayerInfo().cid, hostPlayer.GetWeaponID(), skillId, 0, 0x0200, 0);
|
||||
hostPlayer.GetPlayerInfo().cid, hostPlayer.GetPlayerInfo().cid, hostPlayer.GetPlayerInfo().cid,
|
||||
hostPlayer.GetWeaponID(), skillId, 0, 0x0200, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// begin a skill attack
|
||||
pAttack = CECAttacksMan.Instance.AddSkillAttack(
|
||||
hostPlayer.GetPlayerInfo().cid, targetMarker.GetNPCID(), targetMarker.GetNPCID(), hostPlayer.GetWeaponID(), skillId, 0, 0x0200, 0);
|
||||
hostPlayer.GetPlayerInfo().cid, targetId, targetId,
|
||||
hostPlayer.GetWeaponID(), skillId, 0, 0x0200, 0);
|
||||
}
|
||||
|
||||
|
||||
bool ok = hostPlayer.PlaySkillAttackAction(skillId, 0, ref attackTime,0, pAttack);
|
||||
bool ok = hostPlayer.PlaySkillAttackAction(skillId, 0, ref attackTime, 0, pAttack);
|
||||
if (!ok)
|
||||
BMLogger.LogWarning($"[SkillTriggerPanel] PlaySkillAttackAction returned false for skill {skillId} after delay — attack anim may not play.");
|
||||
EXIT:
|
||||
// // For skill attacking, time is always set to 0
|
||||
BMLogger.LogWarning($"[SkillTriggerPanel] PlaySkillAttackAction returned false for skill {skillId} — attack anim may not play.");
|
||||
|
||||
if (attackTime != 0)
|
||||
attackTime = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user