Files

356 lines
14 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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);
}
}
}