509 lines
14 KiB
C#
509 lines
14 KiB
C#
using BrewMonster.Network;
|
|
using BrewMonster.Scripts.Skills;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
namespace BrewMonster
|
|
{
|
|
|
|
// CECSkillStr class - inherits from SkillStr
|
|
public class CECSkillStr : SkillStr
|
|
{
|
|
public override string Find(int id)
|
|
{
|
|
// TODO: Implement GetNameDisplay - requires game instance access
|
|
BrewMonster.CECStringTab pStrTab = EC_Game.GetSkillDesc();
|
|
string str = pStrTab.GetWideString(id);
|
|
return string.IsNullOrEmpty(str) ? str : string.Empty;
|
|
}
|
|
}
|
|
|
|
// Skill array wrapper structure
|
|
public struct SkillArrayWrapper
|
|
{
|
|
public Dictionary<uint, int> skillDic;
|
|
|
|
public SkillArrayWrapper(Dictionary<uint, int> rhs)
|
|
{
|
|
skillDic = rhs ?? new Dictionary<uint, int>();
|
|
RemoveInvalid();
|
|
}
|
|
|
|
// Remove invalid skills (for example, those with ID == 0)
|
|
public void RemoveInvalid()
|
|
{
|
|
if (skillDic == null) return;
|
|
|
|
var invalidKeys = skillDic
|
|
.Where(kv => kv.Key == 0)
|
|
.Select(kv => kv.Key)
|
|
.ToList();
|
|
|
|
foreach (var key in invalidKeys)
|
|
skillDic.Remove(key);
|
|
}
|
|
|
|
public bool Find(uint id)
|
|
{
|
|
return skillDic != null && skillDic.ContainsKey(id);
|
|
}
|
|
|
|
public bool Empty()
|
|
{
|
|
return skillDic == null || skillDic.Count == 0;
|
|
}
|
|
|
|
public int Count()
|
|
{
|
|
return skillDic?.Count ?? 0;
|
|
}
|
|
|
|
public uint this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (skillDic == null || index < 0 || index >= skillDic.Count)
|
|
throw new System.IndexOutOfRangeException();
|
|
|
|
return skillDic.ElementAt(index).Key;
|
|
}
|
|
}
|
|
}
|
|
// CECSkill class
|
|
public class CECSkill
|
|
{
|
|
// Skill type enum
|
|
public enum SkillType
|
|
{
|
|
TYPE_ATTACK = 1, // 攻击技能
|
|
TYPE_BLESS, // 祝福技能
|
|
TYPE_CURSE, // 诅咒技能
|
|
TYPE_SUMMON, // 召唤
|
|
TYPE_PASSIVE, // 被动
|
|
TYPE_ENABLED, // 启用
|
|
TYPE_LIVE, // 生活
|
|
TYPE_FLASHMOVE, // 瞬移
|
|
TYPE_PRODUCE, // 生产
|
|
TYPE_BLESSPET, // 宠物祝福
|
|
TYPE_NEUTRALBLESS, // 中立祝福
|
|
}
|
|
|
|
// Range type enum
|
|
public enum RangeType
|
|
{
|
|
RANGE_POINT = 0, // 点
|
|
RANGE_LINE, // 线
|
|
RANGE_SELFSPHERE, // 自身为圆心的圆
|
|
RANGE_TARGETSPHERE, // 目标为圆心的圆
|
|
RANGE_TAPER, // 圆锥
|
|
RANGE_SLEF, // 自身
|
|
}
|
|
|
|
// Attributes
|
|
private ElementSkill m_pSkillCore;
|
|
private int m_idSkill; // Skill ID
|
|
private int m_iLevel; // Skill level
|
|
private int m_iCoolCnt; // Cooling time counter
|
|
private int m_iCoolTime; // Total cooling time
|
|
private bool m_bCooling; // In cooling state
|
|
private int m_iChargeCnt; // Charging time counter
|
|
private int m_iChargeMax; // Charging time maximum count value
|
|
private bool m_bCharging; // In charging state
|
|
|
|
// Static skill string provider
|
|
private static CECSkillStr l_SkillStr = new CECSkillStr();
|
|
|
|
// Public accessor for skill core (for CheckSkillCastCondition)
|
|
public ElementSkill SkillCore => m_pSkillCore;
|
|
|
|
// Constructor
|
|
public CECSkill(int id, int iLevel)
|
|
{
|
|
if (iLevel < 0) return;
|
|
m_pSkillCore = ElementSkill.Create((uint)id, iLevel);
|
|
if (m_pSkillCore == null)
|
|
{
|
|
// Fallback to default skill
|
|
m_pSkillCore = ElementSkill.Create(1, 1);
|
|
}
|
|
|
|
m_idSkill = id;
|
|
m_iLevel = iLevel;
|
|
m_iCoolTime = m_pSkillCore != null ? m_pSkillCore.GetCoolingTime() : 0;
|
|
m_iCoolCnt = 0;
|
|
m_bCooling = false;
|
|
m_iChargeCnt = 0;
|
|
m_iChargeMax = 0;
|
|
m_bCharging = false;
|
|
}
|
|
|
|
// Tick routine
|
|
public void Tick(float deltaTime)
|
|
{
|
|
// Convert deltaTime (seconds) to milliseconds
|
|
int tickTime = (int)(deltaTime * 1000f);
|
|
|
|
if (m_bCooling)
|
|
{
|
|
// In cooling state
|
|
m_iCoolCnt -= tickTime;
|
|
if (m_iCoolCnt <= 0)
|
|
{
|
|
m_iCoolCnt = 0;
|
|
m_bCooling = false;
|
|
// TODO: do something here ?
|
|
}
|
|
}
|
|
|
|
if (m_bCharging)
|
|
{
|
|
// In charging state
|
|
m_iChargeCnt += tickTime;
|
|
if (m_iChargeCnt >= m_iChargeMax)
|
|
{
|
|
m_iChargeCnt = m_iChargeMax;
|
|
m_bCharging = false;
|
|
// TODO: do something here ?
|
|
}
|
|
}
|
|
}
|
|
|
|
// Skill level up
|
|
public void LevelUp()
|
|
{
|
|
m_iLevel++;
|
|
if (m_pSkillCore != null)
|
|
{
|
|
m_pSkillCore.SetLevel(m_iLevel);
|
|
}
|
|
}
|
|
|
|
// Set Skill level
|
|
public void SetLevel(int iLevel)
|
|
{
|
|
m_iLevel = iLevel;
|
|
if (m_pSkillCore != null)
|
|
{
|
|
m_pSkillCore.SetLevel(m_iLevel);
|
|
}
|
|
}
|
|
|
|
// Start into cooling state
|
|
// iTotalTime: total cooling time, 0 means to use cooling time in database
|
|
public void StartCooling(int iTotalTime, int iStartCnt)
|
|
{
|
|
m_iCoolTime = iTotalTime != 0 ? iTotalTime : GetCoreCoolingTime();
|
|
m_iCoolCnt = iStartCnt;
|
|
m_bCooling = true;
|
|
}
|
|
|
|
// Ready to be cast ?
|
|
public bool ReadyToCast()
|
|
{
|
|
return !m_bCooling;
|
|
}
|
|
|
|
// Get cooling time counter
|
|
public int GetCoolingCnt()
|
|
{
|
|
return m_iCoolCnt;
|
|
}
|
|
|
|
// Get total cooling time
|
|
public int GetCoolingTime()
|
|
{
|
|
return m_iCoolTime;
|
|
}
|
|
|
|
// Start charging
|
|
public void StartCharging(int iChargeMax)
|
|
{
|
|
if (m_pSkillCore != null && m_pSkillCore.IsWarmup())
|
|
{
|
|
m_iChargeMax = iChargeMax;
|
|
m_iChargeCnt = 0;
|
|
m_bCharging = true;
|
|
}
|
|
}
|
|
|
|
// End charging
|
|
public void EndCharging()
|
|
{
|
|
m_bCharging = false;
|
|
}
|
|
|
|
// Get charging flag
|
|
public bool IsCharging()
|
|
{
|
|
return m_bCharging;
|
|
}
|
|
|
|
// Get charging counter
|
|
public int GetChargingCnt()
|
|
{
|
|
return m_iChargeCnt;
|
|
}
|
|
|
|
// Get charging maximum count
|
|
public int GetChargingMax()
|
|
{
|
|
return m_iChargeMax;
|
|
}
|
|
|
|
// Charge full
|
|
public bool ChargeFull()
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.IsWarmup() && m_iChargeCnt >= m_iChargeMax;
|
|
}
|
|
|
|
// Get skill ID
|
|
public int GetSkillID()
|
|
{
|
|
return m_idSkill;
|
|
}
|
|
|
|
// Get skill level
|
|
public int GetSkillLevel()
|
|
{
|
|
return m_iLevel;
|
|
}
|
|
|
|
// Get skill icon file
|
|
public string GetIconFile()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetIcon() ?? string.Empty : string.Empty;
|
|
}
|
|
|
|
public string GetName()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetName() ?? string.Empty : string.Empty;
|
|
}
|
|
|
|
public string GetNameDisplay()
|
|
{
|
|
return EC_Game.GetSkillDesc().GetWideString(GetSkillID() * 10);
|
|
}
|
|
|
|
public string GetDesc()
|
|
{
|
|
if (m_pSkillCore == null || l_SkillStr == null)
|
|
return string.Empty;
|
|
|
|
StringBuilder sb = new StringBuilder(1024);
|
|
var skillStr = l_SkillStr as SkillStr;
|
|
string result = m_pSkillCore.GetIntroduction(sb, 1024, skillStr);
|
|
return result;
|
|
}
|
|
|
|
public int GetCoreCoolingTime()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetCoolingTime() : 0;
|
|
}
|
|
|
|
public int GetExecuteTime()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetExecuteTime() : 0;
|
|
}
|
|
|
|
public int GetType()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetType() : 0;
|
|
}
|
|
|
|
public int GetRangeType()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRangeType() : 0;
|
|
}
|
|
|
|
public float GetCastRange(float fAtkDist, float fPrayDistancePlus)
|
|
{
|
|
|
|
return m_pSkillCore != null ? m_pSkillCore.GetPrayRange(fAtkDist, fPrayDistancePlus) : 0f;
|
|
}
|
|
public string GetEffect()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetEffect() ?? string.Empty : string.Empty;
|
|
}
|
|
|
|
public int GetTargetType()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetTargetType() : 0;
|
|
}
|
|
|
|
public int GetCastEnv()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetCastEnv() : 0;
|
|
}
|
|
|
|
/* public int[] GetRequiredGenius()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRequiredGenius(m_idSkill) ?? new int[0] : new int[0];
|
|
}*/
|
|
|
|
public int GetShowOrder()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetShowOrder() : 0;
|
|
}
|
|
|
|
public bool IsChargeable()
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.IsWarmup();
|
|
}
|
|
|
|
/* public string GetNativeName()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetNativeName() ?? string.Empty : string.Empty;
|
|
}*/
|
|
|
|
public bool ValidWeapon(int idWeapon)
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.ValidWeapon(idWeapon);
|
|
}
|
|
/*
|
|
public bool ValidShape(int iShape)
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.IsValidForm((char)iShape);
|
|
}*/
|
|
|
|
public bool ChangeToMelee()
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.IsAutoAttack();
|
|
}
|
|
|
|
public bool IsInstant()
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.IsInstant();
|
|
}
|
|
|
|
public bool IsDurative()
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.IsDurative();
|
|
}
|
|
|
|
public SkillArrayWrapper GetJunior()
|
|
{
|
|
var juniorList = m_pSkillCore.GetJunior();
|
|
return new SkillArrayWrapper(juniorList);
|
|
}
|
|
|
|
public int GetRequiredLevel()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRequiredLevel() : 0;
|
|
}
|
|
|
|
public int GetRequiredSp()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRequiredSp() : 0;
|
|
}
|
|
|
|
public int GetRequiredBook()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRequiredBook() : 0;
|
|
}
|
|
|
|
/* public SkillArrayWrapper GetRequiredSkill()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRequiredSkill() : new SkillArrayWrapper(new List<SkillArrayWrapper.IDLevelPair>());
|
|
}*/
|
|
|
|
public int GetRequiredMoney()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRequiredMoney() : 0;
|
|
}
|
|
|
|
/* public int GetRequiredItem()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetItemCost() : 0;
|
|
}*/
|
|
|
|
// 获取技能公共冷却mask,其中bit0-4为技能公共冷却,bit5-9为物品公共冷却
|
|
/* public int GetCommonCoolDown()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetCommonCoolDown() : 0;
|
|
}*/
|
|
|
|
// 获取技能公共冷却时间,单位毫秒
|
|
/* public int GetCommonCoolDownTime()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetCommonCoolDownTime() : 0;
|
|
}*/
|
|
|
|
// Get skill description (static method)
|
|
public static bool GetDesc(int idSkill, int iLevel, out string szText, int iBufLen)
|
|
{
|
|
szText = string.Empty;
|
|
|
|
if (iBufLen <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CECSkill pSkill = new CECSkill(idSkill, iLevel);
|
|
if (pSkill == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string sz = pSkill.GetDesc();
|
|
if (sz != null && sz.Length < iBufLen)
|
|
{
|
|
szText = sz;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Check skill type
|
|
public bool IsGoblinSkill()
|
|
{
|
|
return m_pSkillCore != null && m_pSkillCore.GetCls() == 258;
|
|
}
|
|
|
|
public bool IsPlayerSkill()
|
|
{
|
|
// TODO: NUM_PROFESSION should be defined elsewhere
|
|
const int NUM_PROFESSION = 256; // Placeholder
|
|
int cls = m_pSkillCore != null ? m_pSkillCore.GetCls() : -1;
|
|
return cls >= 0 && cls < NUM_PROFESSION;
|
|
}
|
|
|
|
public bool IsGeneralSkill()
|
|
{
|
|
return GetCls() == 255;
|
|
}
|
|
|
|
public int GetCls()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetCls() : -1;
|
|
}
|
|
|
|
// 技能等级
|
|
public int GetRank()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetRank() : 0;
|
|
}
|
|
|
|
// 技能最大等级
|
|
public int GetMaxLevel()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetMaxLevel() : 0;
|
|
}
|
|
|
|
/* public int GetComboSkPreSkill()
|
|
{
|
|
return m_pSkillCore != null ? m_pSkillCore.GetComboSkPreSkill() : 0;
|
|
}*/
|
|
|
|
public bool IsPositiveSkill()
|
|
{
|
|
int t = GetType();
|
|
return t != (int)SkillType.TYPE_PASSIVE
|
|
&& t != (int)SkillType.TYPE_PRODUCE
|
|
&& t != (int)SkillType.TYPE_LIVE;
|
|
}
|
|
}
|
|
} |