356 lines
14 KiB
C#
356 lines
14 KiB
C#
/*
|
||
* FILE: CECComboSkill.cs
|
||
*
|
||
* DESCRIPTION: Combo skill system for Perfect World client
|
||
*
|
||
* CONVERTED FROM: EC_ComboSkill.cpp/EC_ComboSkill.h
|
||
*
|
||
* CREATED BY: Duyuxin, 2005/12/26
|
||
*
|
||
* HISTORY:
|
||
*
|
||
* Copyright (c) 2005 Archosaur Studio, All Rights Reserved.
|
||
*/
|
||
|
||
using BrewMonster.Assets.PerfectWorld.Scripts.Players;
|
||
using BrewMonster.Network;
|
||
using BrewMonster.Scripts.Skills;
|
||
using CSNetwork;
|
||
using UnityEngine;
|
||
using static CECPlayerWrapper;
|
||
|
||
namespace BrewMonster
|
||
{
|
||
///////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Class CECComboSkill - 连招技能管理类 / Combo Skill Manager Class
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////
|
||
|
||
public class CECComboSkill
|
||
{
|
||
// Special skill id - 特殊技能ID / Special Skill IDs
|
||
public enum SpecialSkillID
|
||
{
|
||
SID_ATTACK = -1, // Normal attack - 普通攻击 / Normal attack
|
||
SID_LOOPSTART = -2, // Loop start flag - 循环开始标记 / Loop start flag
|
||
}
|
||
|
||
// Attributes - 成员变量 / Member Variables
|
||
|
||
protected CECHostPlayer m_pHost; // Host player object - 宿主玩家对象 / Host player object
|
||
protected EC_COMBOSKILL m_cs; // Combo skill data - 连招技能数据 / Combo skill data
|
||
|
||
protected int m_iGroup; // Group index - 组索引 / Group index
|
||
protected int m_iCursor; // 当前光标位置 / Current cursor position
|
||
protected bool m_bStop; // Stop flag - 停止标志 / Stop flag
|
||
protected int m_iLoopStart; // Loop start index - 循环开始索引 / Loop start index
|
||
protected int m_idTarget; // Attack target - 攻击目标 / Attack target
|
||
protected bool m_bForceAtk; // Force attack flag - 强制攻击标志 / Force attack flag
|
||
protected bool m_bIgnoreAtkLoop; // Ignore attack and loop flag - 忽略攻击和循环标志 / Ignore attack and loop flag
|
||
|
||
// Constructor - 构造函数 / Constructor
|
||
public CECComboSkill()
|
||
{
|
||
m_pHost = null;
|
||
m_iGroup = -1;
|
||
m_iCursor = 0;
|
||
m_bStop = false;
|
||
m_iLoopStart = -1;
|
||
m_idTarget = 0;
|
||
m_bForceAtk = false;
|
||
m_bIgnoreAtkLoop = false;
|
||
|
||
m_cs = new EC_COMBOSKILL(true);
|
||
}
|
||
|
||
// Initialize object - 初始化对象 / Initialize object
|
||
public bool Init(CECHostPlayer pHost, int iGroup, int idTarget,
|
||
bool bForceAttack, bool bIgnoreAtkLoop)
|
||
{
|
||
if (iGroup < 0 || iGroup >= EC_ConfigConstants.EC_COMBOSKILL_NUM)
|
||
{
|
||
BMLogger.LogError("CECComboSkill.Init: Invalid group index");
|
||
return false;
|
||
}
|
||
|
||
m_pHost = pHost;
|
||
m_iGroup = iGroup;
|
||
m_iCursor = 0;
|
||
m_bStop = false;
|
||
m_idTarget = idTarget;
|
||
m_bForceAtk = bForceAttack;
|
||
m_bIgnoreAtkLoop = bIgnoreAtkLoop;
|
||
|
||
// TODO: Get combo skill configuration from CECConfigs
|
||
CECConfigs pCfg = EC_Game.GetConfigs();
|
||
m_cs = pCfg.GetVideoSettings().comboSkill[iGroup];
|
||
|
||
m_iLoopStart = -1;
|
||
for (int i = 0; i < EC_ConfigConstants.EC_COMBOSKILL_LEN; i++)
|
||
{
|
||
if (m_cs.idSkill[i] == (short)SpecialSkillID.SID_LOOPSTART)
|
||
m_iLoopStart = i;
|
||
}
|
||
|
||
// Ensure there is valid skill id after loop start flag
|
||
// 确保循环标记后有有效的技能ID / Ensure there is valid skill id after loop start flag
|
||
if (m_iLoopStart >= 0)
|
||
{
|
||
int i;
|
||
for (i = m_iLoopStart + 1; i < EC_ConfigConstants.EC_COMBOSKILL_LEN; i++)
|
||
{
|
||
int id = m_cs.idSkill[i];
|
||
if (id > 0 || id == (short)SpecialSkillID.SID_ATTACK)
|
||
break;
|
||
}
|
||
|
||
// If no valid skill after loop start flag is found,
|
||
// disable this loop start flag
|
||
// 如果在循环标记后没有找到有效技能,禁用此循环标记
|
||
// If no valid skill after loop start flag is found, disable this loop start flag
|
||
if (i >= EC_ConfigConstants.EC_COMBOSKILL_LEN)
|
||
m_iLoopStart = -1;
|
||
}
|
||
|
||
// Move cursor to proper position - 移动光标到合适的位置 / Move cursor to proper position
|
||
StepCursor(true);
|
||
|
||
return true;
|
||
}
|
||
|
||
// Continue combo skill - 继续连招技能 / Continue combo skill
|
||
// Return true if combo skill will continues, false if combo skill stops
|
||
// 返回true表示连招将继续,false表示连招停止 / Return true if combo skill will continues, false if combo skill stops
|
||
// bMeleeing: true, player is being meleeing - 玩家正在进行近战 / true, player is being meleeing
|
||
public bool Continue(bool bMeleeing)
|
||
{
|
||
int nextSkill = GetNextSkill();
|
||
BMLogger.Log($"[COMBO] Continue ENTRY cursor={m_iCursor} nextSkill={nextSkill} m_bStop={m_bStop} nIcon={m_cs.nIcon} " +
|
||
$"target={m_idTarget} selTarget={m_pHost?.m_idSelTarget} bMeleeing={bMeleeing} group={m_iGroup}");
|
||
|
||
if (m_bStop || m_cs.nIcon == 0 || m_pHost == null ||
|
||
m_iCursor < 0 || m_iCursor >= EC_ConfigConstants.EC_COMBOSKILL_LEN ||
|
||
(m_idTarget != m_pHost.m_idSelTarget && !m_bIgnoreAtkLoop))
|
||
{
|
||
BMLogger.Log($"[COMBO] Continue EXIT early (guard) m_bStop={m_bStop} nIcon={m_cs.nIcon} cursor={m_iCursor} targetMatch={m_pHost != null && m_idTarget == m_pHost.m_idSelTarget}");
|
||
return false;
|
||
}
|
||
|
||
// TODO: Get PlayerWrapper from CECAutoPolicy
|
||
CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper();
|
||
|
||
int idSkill = nextSkill;
|
||
if (idSkill > 0)
|
||
{
|
||
BMLogger.Log($"[COMBO] Continue applying SKILL idSkill={idSkill}");
|
||
bool bRet = m_pHost.ApplySkillShortcut(idSkill, true, m_idTarget, m_bForceAtk ? 1 : 0);
|
||
if (!bRet)
|
||
{
|
||
// 施放失败,尝试施放下一个技能 / Cast failed, try to cast next skill
|
||
StepCursor(false);
|
||
if (!IsStop())
|
||
{
|
||
// TODO: Post message to continue combo skill
|
||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL, MANAGER_INDEX.MAN_PLAYER, 0, bMeleeing ? 1 : 0, m_iGroup);
|
||
}
|
||
else
|
||
{
|
||
// 连击技能停止 / Combo skill finish
|
||
AP_ActionEvent((int)AP_EVENT. AP_EVENT_COMBOFINISH);
|
||
}
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
// TODO: Handle auto policy events
|
||
if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled())
|
||
pWrapper.AddAttackError();
|
||
|
||
// 检测自己施放是否追加 / Check if self-cast should be tracked
|
||
int iSelfCureFlag = 0;
|
||
if (m_pHost.GetPrepSkill() != null)
|
||
iSelfCureFlag = 1;
|
||
|
||
AP_ActionEvent((int)AP_EVENT.AP_EVENT_COMBOCONTINUE, iSelfCureFlag);
|
||
}
|
||
BMLogger.Log($"[COMBO] Continue SKILL success, will StepCursor and return true");
|
||
}
|
||
else if (idSkill == (short)SpecialSkillID.SID_ATTACK)
|
||
{
|
||
BMLogger.Log($"[COMBO] Continue SID_ATTACK branch bMeleeing={bMeleeing} bIgnoreAtkLoop={m_bIgnoreAtkLoop}");
|
||
if (!bMeleeing && !m_bIgnoreAtkLoop)
|
||
{
|
||
BMLogger.Log($"[COMBO] Continue calling CmdNormalAttack for normal attack step");
|
||
bool bRet = m_pHost.CmdNormalAttack(false, true, m_idTarget, m_bForceAtk ? 1 : 0);
|
||
|
||
if (bRet)
|
||
{
|
||
// TODO: Handle auto policy events
|
||
if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled())
|
||
pWrapper.AddAttackError();
|
||
|
||
AP_ActionEvent((int)AP_EVENT.AP_EVENT_COMBOCONTINUE);
|
||
}
|
||
else
|
||
{
|
||
StepCursor(false);
|
||
if (!IsStop())
|
||
{
|
||
// TODO: Post message to continue combo skill
|
||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL, MANAGER_INDEX.MAN_PLAYER, 0, bMeleeing ? 1 : 0, m_iGroup);
|
||
}
|
||
else
|
||
{
|
||
// 连击技能停止 / Combo skill finish
|
||
AP_ActionEvent((int)AP_EVENT.AP_EVENT_COMBOFINISH);
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 当前是攻击,执行下一个元素 / Current is attack, execute next element
|
||
StepCursor(false);
|
||
if (!IsStop())
|
||
{
|
||
// TODO: Post message to continue combo skill
|
||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL, MANAGER_INDEX.MAN_PLAYER, 0, bMeleeing ? 1 : 0, m_iGroup);
|
||
}
|
||
else
|
||
{
|
||
// 连击技能停止 / Combo skill finish
|
||
AP_ActionEvent((int)AP_EVENT.AP_EVENT_COMBOFINISH);
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
BMLogger.LogError("CECComboSkill.Continue: Invalid skill id");
|
||
return false;
|
||
}
|
||
|
||
// Forward cursor - 前进光标 / Forward cursor
|
||
StepCursor(false);
|
||
BMLogger.Log($"[COMBO] Continue after StepCursor cursor={m_iCursor} m_bStop={m_bStop} returning true");
|
||
|
||
return true;
|
||
}
|
||
|
||
// Step cursor - 步进光标 / Step cursor
|
||
protected void StepCursor(bool bFirst)
|
||
{
|
||
if (bFirst)
|
||
m_iCursor = -1;
|
||
|
||
while (true)
|
||
{
|
||
m_iCursor++;
|
||
|
||
if (m_iCursor >= EC_ConfigConstants.EC_COMBOSKILL_LEN)
|
||
{
|
||
// If we has loop flag, jump to it
|
||
// 如果有循环标记,跳转到它 / If we has loop flag, jump to it
|
||
if (m_iLoopStart >= 0 && !m_bIgnoreAtkLoop)
|
||
m_iCursor = m_iLoopStart;
|
||
else
|
||
{
|
||
m_bStop = true;
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int id = m_cs.idSkill[m_iCursor];
|
||
if (id > 0 || (id == (short)SpecialSkillID.SID_ATTACK && !m_bIgnoreAtkLoop))
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Get id of skill next Continue() will trigger
|
||
// 获取下一次Continue()将触发的技能ID / Get id of skill next Continue() will trigger
|
||
public int GetNextSkill()
|
||
{
|
||
if (m_bStop || m_iCursor < 0 || m_iCursor >= EC_ConfigConstants.EC_COMBOSKILL_LEN)
|
||
return 0;
|
||
|
||
return m_cs.idSkill[m_iCursor];
|
||
}
|
||
|
||
// Get stop flag - 获取停止标志 / Get stop flag
|
||
public bool IsStop()
|
||
{
|
||
return m_bStop;
|
||
}
|
||
|
||
// Replace skill id - 替换技能ID / Replace skill id
|
||
public void ReplaceSkillID(int idOld, int idNew)
|
||
{
|
||
for (int i = 0; i < EC_ConfigConstants.EC_COMBOSKILL_LEN; i++)
|
||
{
|
||
if (m_cs.idSkill[i] == (short)idOld)
|
||
m_cs.idSkill[i] = (short)idNew;
|
||
}
|
||
}
|
||
|
||
// Replace skill id (multiple old IDs) - 替换技能ID(多个旧ID) / Replace skill id (multiple old IDs)
|
||
public void ReplaceSkillID(SkillArrayWrapper idOlds, int idNew)
|
||
{
|
||
for (int i = 0; i < idOlds.Count(); i++)
|
||
{
|
||
ReplaceSkillID((int)idOlds[i], idNew);
|
||
}
|
||
}
|
||
|
||
// Find skill ID in combo - 在连招中查找技能ID / Find skill ID in combo
|
||
public bool FindSkillID(int idSkill)
|
||
{
|
||
bool bFound = false;
|
||
if (idSkill > 0)
|
||
{
|
||
for (int i = 0; i < EC_ConfigConstants.EC_COMBOSKILL_LEN; i++)
|
||
{
|
||
if (m_cs.idSkill[i] == (short)idSkill)
|
||
{
|
||
bFound = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return bFound;
|
||
}
|
||
|
||
// Get the target - 获取目标 / Get the target
|
||
public int GetTarget()
|
||
{
|
||
return m_idTarget;
|
||
}
|
||
|
||
// Do we ignore the attack and loop flag ? - 是否忽略攻击和循环标志 / Do we ignore the attack and loop flag ?
|
||
public bool IsIgnoreAtkLoop()
|
||
{
|
||
return m_bIgnoreAtkLoop;
|
||
}
|
||
|
||
// Get group index - 获取组索引 / Get group index
|
||
public int GetGroupIndex()
|
||
{
|
||
return m_iGroup;
|
||
}
|
||
public void AP_ActionEvent(int iEvent, int iParam = 0)
|
||
{
|
||
if (!CECAutoPolicy.GetInstance().IsAutoPolicyEnabled())
|
||
return;
|
||
|
||
CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper();
|
||
if (pWrapper != null) pWrapper.OnActionEvent(iEvent, iParam);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|