convert for test done
This commit is contained in:
@@ -1,162 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ModelRenderer.Scripts.Common;
|
||||
|
||||
namespace BrewMonster.Common
|
||||
{
|
||||
public class CECStringTab
|
||||
{
|
||||
|
||||
private Dictionary<int, string> m_AStrTab = new Dictionary<int, string>();
|
||||
private Dictionary<int, string> m_WStrTab = new Dictionary<int, string>();
|
||||
|
||||
protected bool m_bInit = false;
|
||||
protected bool m_bUnicode = false;
|
||||
|
||||
public bool IsInitialized() => m_bInit;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_AStrTab.Clear();
|
||||
m_WStrTab.Clear();
|
||||
m_bInit = false;
|
||||
m_bUnicode = false;
|
||||
}
|
||||
|
||||
public bool Init(string szFile, bool bUnicode)
|
||||
{
|
||||
bool bRet = false;
|
||||
|
||||
if (bUnicode)
|
||||
{
|
||||
bRet = LoadWideStrings(szFile);
|
||||
}
|
||||
|
||||
if (!bRet)
|
||||
{
|
||||
BMLogger.LogError($"EC_StringTab::Init: {szFile} File load failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bInit = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool LoadWideStrings(string szFile)
|
||||
{
|
||||
AWScriptFile ScriptFile = new AWScriptFile();
|
||||
if (!ScriptFile.Open(szFile)) return false;
|
||||
|
||||
bool bIndex = false;
|
||||
bool bFileEnd = true;
|
||||
|
||||
// Read configs
|
||||
while (ScriptFile.GetNextToken(true))
|
||||
{
|
||||
string tokenStr = ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken);
|
||||
if (ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken).StartsWith("#_index"))
|
||||
bIndex = true;
|
||||
else if (ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken).StartsWith("#_begin"))
|
||||
{
|
||||
bFileEnd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFileEnd)
|
||||
{
|
||||
ScriptFile.Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bIndex)
|
||||
{
|
||||
// Every string has a preset index
|
||||
while (ScriptFile.PeekNextToken(true))
|
||||
{
|
||||
int n = ScriptFile.GetNextTokenAsInt(true);
|
||||
ScriptFile.GetNextToken(false);
|
||||
|
||||
string pstr = ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken);
|
||||
if (string.IsNullOrEmpty(pstr))
|
||||
{
|
||||
ScriptFile.Close();
|
||||
BMLogger.LogWarning($"EC_StringTab::LoadWideStrings: {szFile} Not enough memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_WStrTab.TryAdd(n, pstr))
|
||||
{
|
||||
BMLogger.LogWarning($"EC_StringTab::LoadWideStrings: {szFile} Failed to add string to dictionary");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int iCnt = 0;
|
||||
|
||||
// Read strings sequently
|
||||
while (ScriptFile.GetNextToken(true))
|
||||
{
|
||||
string pstr = ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken);
|
||||
if (string.IsNullOrEmpty(pstr))
|
||||
{
|
||||
ScriptFile.Close();
|
||||
BMLogger.LogError($"EC_StringTab::LoadWideStrings: {szFile} Not enough memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_WStrTab.TryAdd(iCnt++, pstr))
|
||||
{
|
||||
BMLogger.LogError($"EC_StringTab::LoadWideStrings: {szFile} Failed to add string to dictionary");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptFile.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string by index from the Unicode string table
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the string to retrieve</param>
|
||||
/// <returns>The string at the given index, or null if not found</returns>
|
||||
public string GetString(int index)
|
||||
{
|
||||
if (m_WStrTab.TryGetValue(index, out string result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string by index from the ANSI string table
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the string to retrieve</param>
|
||||
/// <returns>The string at the given index, or null if not found</returns>
|
||||
public string GetANSIString(int index)
|
||||
{
|
||||
if (m_AStrTab.TryGetValue(index, out string result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a string exists at the given index
|
||||
/// </summary>
|
||||
/// <param name="index">The index to check</param>
|
||||
/// <returns>True if a string exists at the index</returns>
|
||||
public bool HasString(int index)
|
||||
{
|
||||
return m_WStrTab.ContainsKey(index) || m_AStrTab.ContainsKey(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b95d268e43a5da14f9cf8e1ed98bfd73
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BrewMonster.Assets.PerfectWorld.Scripts.Common
|
||||
{
|
||||
public abstract class Singleton<T> where T : class, new()
|
||||
{
|
||||
private static readonly Lazy<T> _instance = new Lazy<T>(() => new T());
|
||||
public static T Instance => _instance.Value;
|
||||
|
||||
// Protected constructor prevents external instantiation
|
||||
protected Singleton()
|
||||
{
|
||||
if (_instance.IsValueCreated)
|
||||
throw new InvalidOperationException($"Singleton<{typeof(T).Name}> already created!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6034e7cce8bae674c88f8d3de26c06aa
|
||||
@@ -14,7 +14,7 @@ namespace BrewMonster.Common
|
||||
{
|
||||
m_pStringTab = new CECStringTab();
|
||||
}
|
||||
m_pStringTab.Clear();
|
||||
//m_pStringTab.Clear();
|
||||
string path = Path.Combine(Application.streamingAssetsPath, "configs/skillstr.txt");
|
||||
m_pStringTab.Init(path, true);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ namespace BrewMonster.Common
|
||||
m_pStringTab = new CECStringTab();
|
||||
}
|
||||
|
||||
m_pStringTab.Clear();
|
||||
//m_pStringTab.Clear();
|
||||
string path = Path.Combine(Application.streamingAssetsPath, "configs/item_desc.txt");
|
||||
m_pStringTab.Init(path, true);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace BrewMonster.Common
|
||||
m_pStringTab = new CECStringTab();
|
||||
}
|
||||
|
||||
m_pStringTab.Clear();
|
||||
//m_pStringTab.Clear();
|
||||
string path = Path.Combine(Application.streamingAssetsPath, "configs/fixed_msg.txt");
|
||||
m_pStringTab.Init(path, true);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using ModelRenderer.Scripts.GameData;
|
||||
using BrewMonster.Scripts.Task;
|
||||
using UnityEngine;
|
||||
using BrewMonster.Common;
|
||||
using BrewMonster;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
namespace BrewMonster.Network
|
||||
@@ -13,11 +13,11 @@ namespace BrewMonster.Network
|
||||
private static elementdataman m_pElementDataMan; // global element templates manager
|
||||
private static CECGameRun m_pGameRun; // Game running object
|
||||
|
||||
private static BrewMonster.Common.CECStringTab m_FixedMsgs; // Fixed message table
|
||||
private static BrewMonster.Common.CECStringTab m_ItemDesc; // Item desciption string table
|
||||
private static BrewMonster.Common.CECStringTab m_ItemExtDesc; // Item extend description string table
|
||||
private static BrewMonster.Common.CECStringTab m_SkillDesc; // Skill description string table
|
||||
private static BrewMonster.Common.CECStringTab m_BuffDesc; // Buff description string table
|
||||
private static BrewMonster.CECStringTab m_FixedMsgs; // Fixed message table
|
||||
private static BrewMonster.CECStringTab m_ItemDesc; // Item desciption string table
|
||||
private static BrewMonster.CECStringTab m_ItemExtDesc; // Item extend description string table
|
||||
private static BrewMonster.CECStringTab m_SkillDesc; // Skill description string table
|
||||
private static BrewMonster.CECStringTab m_BuffDesc; // Buff description string table
|
||||
private static Dictionary<int, ItemMsgMapEntry> m_ItemMsgMap; // TemplateId -> (MessageId, DisplayMode)
|
||||
#endregion
|
||||
|
||||
@@ -26,11 +26,11 @@ namespace BrewMonster.Network
|
||||
public static elementdataman GetElementDataMan() { return m_pElementDataMan; }
|
||||
|
||||
// String table getters
|
||||
public static BrewMonster.Common.CECStringTab GetFixedMsgs() { return m_FixedMsgs; }
|
||||
public static BrewMonster.Common.CECStringTab GetItemDesc() { return m_ItemDesc; }
|
||||
public static BrewMonster.Common.CECStringTab GetItemExtDesc() { return m_ItemExtDesc; }
|
||||
public static BrewMonster.Common.CECStringTab GetSkillDesc() { return m_SkillDesc; }
|
||||
public static BrewMonster.Common.CECStringTab GetBuffDesc() { return m_BuffDesc; }
|
||||
public static BrewMonster.CECStringTab GetFixedMsgs() { return m_FixedMsgs; }
|
||||
public static BrewMonster.CECStringTab GetItemDesc() { return m_ItemDesc; }
|
||||
public static BrewMonster.CECStringTab GetItemExtDesc() { return m_ItemExtDesc; }
|
||||
public static BrewMonster.CECStringTab GetSkillDesc() { return m_SkillDesc; }
|
||||
public static BrewMonster.CECStringTab GetBuffDesc() { return m_BuffDesc; }
|
||||
public static bool TryGetItemMsg(int templateId, out int messageId, out int displayMode)
|
||||
{
|
||||
messageId = 0;
|
||||
@@ -78,11 +78,11 @@ namespace BrewMonster.Network
|
||||
private static void InitializeStringTables()
|
||||
{
|
||||
// Initialize string table instances
|
||||
m_FixedMsgs = new BrewMonster.Common.CECStringTab();
|
||||
m_ItemDesc = new BrewMonster.Common.CECStringTab();
|
||||
m_ItemExtDesc = new BrewMonster.Common.CECStringTab();
|
||||
m_SkillDesc = new BrewMonster.Common.CECStringTab();
|
||||
m_BuffDesc = new BrewMonster.Common.CECStringTab();
|
||||
m_FixedMsgs = new BrewMonster.CECStringTab();
|
||||
m_ItemDesc = new BrewMonster.CECStringTab();
|
||||
m_ItemExtDesc = new BrewMonster.CECStringTab();
|
||||
m_SkillDesc = new BrewMonster.CECStringTab();
|
||||
m_BuffDesc = new BrewMonster.CECStringTab();
|
||||
|
||||
// Load string files from StreamingAssets/configs directory
|
||||
string dataPath = Application.streamingAssetsPath + "/configs/";
|
||||
|
||||
@@ -563,7 +563,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
var itemDesc = EC_Game.GetItemDesc();
|
||||
if (itemDesc != null && itemDesc.IsInitialized())
|
||||
{
|
||||
string description = itemDesc.GetString(messageId);
|
||||
string description = itemDesc.GetWideString(messageId);
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
{
|
||||
return description;
|
||||
@@ -576,7 +576,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
var itemDesc = EC_Game.GetItemDesc();
|
||||
if (itemDesc != null && itemDesc.IsInitialized())
|
||||
{
|
||||
string description = itemDesc.GetString(templateId);
|
||||
string description = itemDesc.GetWideString(templateId);
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
return description;
|
||||
}
|
||||
@@ -605,7 +605,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
var itemExtDesc = EC_Game.GetItemExtDesc();
|
||||
if (itemExtDesc != null && itemExtDesc.IsInitialized())
|
||||
{
|
||||
string extendedDesc = itemExtDesc.GetString(messageId);
|
||||
string extendedDesc = itemExtDesc.GetWideString(messageId);
|
||||
if (!string.IsNullOrEmpty(extendedDesc))
|
||||
{
|
||||
return extendedDesc;
|
||||
@@ -618,7 +618,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
var itemExtDesc = EC_Game.GetItemExtDesc();
|
||||
if (itemExtDesc != null && itemExtDesc.IsInitialized())
|
||||
{
|
||||
string extendedDesc = itemExtDesc.GetString(templateId);
|
||||
string extendedDesc = itemExtDesc.GetWideString(templateId);
|
||||
if (!string.IsNullOrEmpty(extendedDesc))
|
||||
return extendedDesc;
|
||||
}
|
||||
|
||||
@@ -1381,7 +1381,7 @@ namespace PerfectWorld.Scripts.Managers
|
||||
var tab = EC_Game.GetItemDesc();
|
||||
if (tab != null && tab.IsInitialized())
|
||||
{
|
||||
string s = tab.GetString(id);
|
||||
string s = tab.GetWideString(id);
|
||||
if (!string.IsNullOrEmpty(s)) return s;
|
||||
}
|
||||
// Fallback labels for common IDs when the table lacks #_index entries
|
||||
|
||||
@@ -1,6 +1,508 @@
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts.Skills;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
public class CECSkill
|
||||
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> Array;
|
||||
|
||||
public SkillArrayWrapper(Dictionary<uint, int> rhs)
|
||||
{
|
||||
Array = rhs ?? new Dictionary<uint, int>();
|
||||
RemoveInvalid();
|
||||
}
|
||||
|
||||
// Remove invalid skills (for example, those with ID == 0)
|
||||
public void RemoveInvalid()
|
||||
{
|
||||
if (Array == null) return;
|
||||
|
||||
var invalidKeys = Array
|
||||
.Where(kv => kv.Key == 0)
|
||||
.Select(kv => kv.Key)
|
||||
.ToList();
|
||||
|
||||
foreach (var key in invalidKeys)
|
||||
Array.Remove(key);
|
||||
}
|
||||
|
||||
public bool Find(uint id)
|
||||
{
|
||||
return Array != null && Array.ContainsKey(id);
|
||||
}
|
||||
|
||||
public bool Empty()
|
||||
{
|
||||
return Array == null || Array.Count == 0;
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
return Array?.Count ?? 0;
|
||||
}
|
||||
|
||||
public uint this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Array == null || index < 0 || index >= Array.Count)
|
||||
throw new System.IndexOutOfRangeException();
|
||||
|
||||
return Array.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();
|
||||
|
||||
// Constructor
|
||||
public CECSkill(int id, int iLevel)
|
||||
{
|
||||
|
||||
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()
|
||||
{
|
||||
// TODO: Implement GetNameDisplay - requires game instance access
|
||||
// return g_pGame->GetSkillDesc()->GetWideString(GetSkillID() * 10);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using static Unity.Burst.Intrinsics.X86.Avx;
|
||||
|
||||
namespace CSNetwork.C2SCommand
|
||||
{
|
||||
@@ -239,7 +240,6 @@ namespace CSNetwork.C2SCommand
|
||||
byte byDir, ushort wStamp, ushort iTime
|
||||
)
|
||||
{
|
||||
_logger.Log(LogType.Warning, $"HoangDev : vDest : {vDest}\n speed {FloatToFix8(FloatToFix8(fSpeed))} \n useTime : {iTime}\n moveMode: {iMoveMode} \n stamp: {wStamp}");
|
||||
var cmd = new CMD_StopMove
|
||||
{
|
||||
vCurPos = vDest,
|
||||
@@ -251,6 +251,25 @@ namespace CSNetwork.C2SCommand
|
||||
};
|
||||
return SerializeCommand(CommandID.STOP_MOVE, cmd);
|
||||
}
|
||||
public static Octets CreatePlayerCastSkill(int idSkill, byte byPVPMask, int iNumTarget, int aTargets)
|
||||
{
|
||||
var cmd = new CMD_CastSkill
|
||||
{
|
||||
skillId = idSkill,
|
||||
pvpMask = byPVPMask,
|
||||
targetCount = (byte)iNumTarget,
|
||||
};
|
||||
if(iNumTarget > 0)
|
||||
{
|
||||
if (iNumTarget > 0)
|
||||
{
|
||||
cmd.targets = new int[iNumTarget];
|
||||
cmd.targets[0] = aTargets;
|
||||
}
|
||||
}
|
||||
return SerializeCommand(CommandID.CAST_SKILL, cmd);
|
||||
}
|
||||
|
||||
public static short FloatToFix8(float x)
|
||||
{
|
||||
return (short)(x * 256.0f + 0.5f);
|
||||
|
||||
@@ -609,7 +609,7 @@ namespace CSNetwork.GPDataType
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_host_attacked
|
||||
public struct cmd_host_attacked
|
||||
{
|
||||
public int idAttacker;
|
||||
public int iDamage;
|
||||
@@ -754,7 +754,22 @@ namespace CSNetwork.GPDataType
|
||||
|
||||
public override string ToString() => $"({x}, {y}, {z})";
|
||||
}
|
||||
// PVP mask
|
||||
[Flags]
|
||||
public enum PVPMask
|
||||
{
|
||||
GP_PVPMASK_FORCE = 0x0001, // Ç¿Á¦¹¥»÷
|
||||
GP_PVPMASK_NOMAFIA = 0x0002,
|
||||
GP_PVPMASK_NOWHITE = 0x0004,
|
||||
GP_PVPMASK_NOALLIANCE = 0x0008,
|
||||
GP_PVPMASK_NOFORCE = 0x0010,//²»¹¥»÷Í¬ÊÆÁ¦µÄ
|
||||
|
||||
GP_BLSMASK_NORED = 0x0008,
|
||||
GP_BLSMASK_NOMAFIA = 0x0010,
|
||||
GP_BLSMASK_SELF = 0x0020,
|
||||
GP_BLSMASK_NOALLIANCE = 0x0040,
|
||||
GP_BLSMASK_NOFORCE = 0x0080, // ÊÆÁ¦ÆÁ±Î
|
||||
};
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_self_info_1
|
||||
{
|
||||
@@ -772,19 +787,19 @@ namespace CSNetwork.GPDataType
|
||||
//TO DO: Check Valid
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_self_info_00
|
||||
public struct cmd_self_info_00
|
||||
{
|
||||
public short sLevel;
|
||||
public byte State;
|
||||
public byte Level2;
|
||||
public int iHP;
|
||||
public int iMaxHP;
|
||||
public int iMP;
|
||||
public int iMaxMP;
|
||||
public int iExp;
|
||||
public int iSP;
|
||||
public int iAP;
|
||||
public int iMaxAP;
|
||||
public short sLevel;
|
||||
public byte State;
|
||||
public byte Level2;
|
||||
public int iHP;
|
||||
public int iMaxHP;
|
||||
public int iMP;
|
||||
public int iMaxMP;
|
||||
public int iExp;
|
||||
public int iSP;
|
||||
public int iAP;
|
||||
public int iMaxAP;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
@@ -940,7 +955,7 @@ namespace CSNetwork.GPDataType
|
||||
{
|
||||
public int cash_amount;
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_unfreeze_ivtr_slot
|
||||
{
|
||||
@@ -993,8 +1008,8 @@ namespace CSNetwork.GPDataType
|
||||
public int expire_date;
|
||||
public uint amount;
|
||||
public uint slot_amount;
|
||||
public byte where;
|
||||
public byte index;
|
||||
public byte where;
|
||||
public byte index;
|
||||
};
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct cmd_pickup_item
|
||||
|
||||
@@ -883,6 +883,15 @@ namespace CSNetwork
|
||||
C2SCommandFactory.CreatePlayerMove(vCurPos, vDest, (ushort)iTime, fSpeed, (byte)iMoveMode, wStamp);
|
||||
SendProtocol(gamedatasend);
|
||||
}
|
||||
public void c2s_CmdCastSkill(int idSkill, byte byPVPMask, int iNumTarget, int aTargets)
|
||||
{
|
||||
gamedatasend gamedatasend = new gamedatasend();
|
||||
|
||||
gamedatasend.Data =
|
||||
C2SCommandFactory.CreatePlayerCastSkill(idSkill, byPVPMask, iNumTarget, aTargets);
|
||||
|
||||
SendProtocol(gamedatasend);
|
||||
}
|
||||
|
||||
public void c2s_SendCmdStopMove(in Vector3 vDest, float fSpeed, int iMoveMode,
|
||||
byte byDir, ushort wStamp, int iTime)
|
||||
@@ -894,6 +903,7 @@ namespace CSNetwork
|
||||
SendProtocol(gamedatasend);
|
||||
}
|
||||
|
||||
|
||||
public void SendChatData(byte cChannel, in string szMsg, int iPack, int iSlot)
|
||||
{
|
||||
publicchat publicChat = new publicchat();
|
||||
|
||||
@@ -72,7 +72,10 @@ namespace BrewMonster.Network
|
||||
Instance._ip = ip;
|
||||
Instance._port = port;
|
||||
}
|
||||
|
||||
public static void c2s_CmdCastSkill(int idSkill, byte byPVPMask, int iNumTarget, int aTargets)
|
||||
{
|
||||
Instance._gameSession.c2s_CmdCastSkill(idSkill, byPVPMask, iNumTarget, aTargets);
|
||||
}
|
||||
public static async Task Login(string username, string password, Action<bool> onLoginComplete = null)
|
||||
{
|
||||
Instance._username = username;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster
|
||||
|
||||
{
|
||||
public enum ActionContextType
|
||||
{
|
||||
AC_NONE = 0,
|
||||
AC_RIDETOFLY,
|
||||
AC_RIDETOSKILL,
|
||||
AC_FLYTORIDE,
|
||||
AC_RIDETOUSETARGETITEM,
|
||||
}
|
||||
public class CECActionContext
|
||||
{
|
||||
public ActionContextType ContextType { get; set; }
|
||||
|
||||
public bool IsContext(ActionContextType contextType)
|
||||
{
|
||||
return ContextType == contextType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 540c5cee0c186fc468d10477343db08f
|
||||
@@ -0,0 +1,99 @@
|
||||
using BrewMonster.Assets.PerfectWorld.Scripts.Players;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster
|
||||
{
|
||||
public class CECActionSwitcher : CECActionSwitcherBase
|
||||
{
|
||||
private System.Collections.Generic.List<CECActionContext> m_actionContexts =
|
||||
new System.Collections.Generic.List<CECActionContext>();
|
||||
|
||||
public CECActionSwitcher(CECHostPlayer pHost) : base(pHost)
|
||||
{
|
||||
}
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
ProcessMessage();
|
||||
|
||||
// Convert DWORD to uint for milliseconds (Unity deltaTime is in seconds)
|
||||
uint dt = (uint)(deltaTime * 1000f);
|
||||
|
||||
// Iterate backwards to safely remove items during iteration
|
||||
for (int i = m_actionContexts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
CECActionContext pContext = m_actionContexts[i];
|
||||
|
||||
if (pContext != null)
|
||||
{
|
||||
/*pContext.Update(dt);
|
||||
if (pContext.NeedBeRemoved())
|
||||
{
|
||||
// In C#, we just remove from list - GC handles cleanup
|
||||
m_actionContexts.RemoveAt(i);
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
m_actionContexts.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ProcessMessage()
|
||||
{
|
||||
for (int i = 0; i < m_msgs.Count; i++)
|
||||
{
|
||||
EMsgActionSwitcher eMsg = (EMsgActionSwitcher)m_msgs[i];
|
||||
switch (eMsg)
|
||||
{
|
||||
/* case EMsgActionSwitcher.MSG_FLY:
|
||||
{
|
||||
OnFly();
|
||||
}
|
||||
break;
|
||||
case EMsgActionSwitcher.MSG_MOUNTPET:
|
||||
{
|
||||
OnRide();
|
||||
}
|
||||
break;*/
|
||||
case EMsgActionSwitcher.MSG_CASTSKILL:
|
||||
{
|
||||
OnCastSkill();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_msgs.Clear();
|
||||
}
|
||||
public void OnCastSkill()
|
||||
{
|
||||
RemoveRideFlyRelatedContext();
|
||||
}
|
||||
public void RemoveRideFlyRelatedContext()
|
||||
{
|
||||
// Iterate backwards to safely remove items while iterating
|
||||
for (int i = m_actionContexts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
CECActionContext context = m_actionContexts[i];
|
||||
if (context != null)
|
||||
{
|
||||
bool isRelated = context.IsContext(ActionContextType.AC_FLYTORIDE)
|
||||
|| context.IsContext(ActionContextType.AC_RIDETOSKILL)
|
||||
|| context.IsContext(ActionContextType.AC_RIDETOFLY)
|
||||
|| context.IsContext(ActionContextType.AC_RIDETOUSETARGETITEM);
|
||||
|
||||
if (isRelated)
|
||||
{
|
||||
// In C#, we don't need explicit delete - GC will handle it
|
||||
// But if context implements IDisposable, call Dispose() here
|
||||
if (context is System.IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
m_actionContexts.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04f7866e9c0cb8f49828b88ed3f8caeb
|
||||
@@ -10,24 +10,25 @@ namespace BrewMonster.Assets.PerfectWorld.Scripts.Players
|
||||
{
|
||||
CECHostPlayer m_pHostPlayer;
|
||||
bool m_bCanAddMsg;
|
||||
List<(int,int)> m_msgs = new List<(int,int)>();
|
||||
protected List<int> m_msgs = new List<int>();
|
||||
List<CECActionContext> m_actionContexts;
|
||||
public CECActionSwitcherBase(CECHostPlayer pHost)
|
||||
{
|
||||
m_pHostPlayer = pHost;
|
||||
}
|
||||
public virtual bool OnRideToSkillAction(int skill, bool bCom, int iSel, int iForceAtk) { return false; }
|
||||
public bool CanAddMessage() {return m_bCanAddMsg;}
|
||||
public bool CanAddMessage() { return m_bCanAddMsg; }
|
||||
public void PostMessge(int msg)
|
||||
{
|
||||
/* if (CanAddMessage())
|
||||
m_msgs.UniquelyAdd(msg);*/
|
||||
if (CanAddMessage())
|
||||
m_msgs.UniquelyAdd(msg);
|
||||
}
|
||||
}
|
||||
public enum EMsgActionSwitcher
|
||||
|
||||
{
|
||||
MSG_FLY = 0,
|
||||
MSG_MOUNTPET,
|
||||
MSG_CASTSKILL,
|
||||
};
|
||||
{
|
||||
MSG_FLY = 0,
|
||||
MSG_MOUNTPET,
|
||||
MSG_CASTSKILL,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.VisualScripting;
|
||||
using static BrewMonster.SkillArrayWrapper;
|
||||
|
||||
namespace BrewMonster.Assets.PerfectWorld.Scripts.Skills
|
||||
{
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BrewMonster.Assets.PerfectWorld.Scripts.Skills
|
||||
{
|
||||
public class CECSkill
|
||||
{
|
||||
public int m_idSkill;
|
||||
public int m_iLevel; // Skill level
|
||||
public int m_iCoolCnt; // Cooling time counter
|
||||
public int m_iCoolTime; // Total cooling time
|
||||
public bool m_bCooling; // In cooling state
|
||||
public int m_iChargeCnt; // Charging time counter
|
||||
public int m_iChargeMax;
|
||||
public bool m_bCharging;
|
||||
|
||||
public CECSkill(int id, int iLevel)
|
||||
{
|
||||
m_idSkill = id;
|
||||
}
|
||||
|
||||
public int GetSkillID() { return m_idSkill; }
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8ba4073670fa0344912b466d9ad7cba
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
namespace BrewMonster.Scripts.Skills
|
||||
@@ -99,7 +100,7 @@ namespace BrewMonster.Scripts.Skills
|
||||
|
||||
public class SkillStr
|
||||
{
|
||||
public virtual ushort[] Find(int id) { return new ushort[0]; }
|
||||
public virtual string Find(int id) { return ""; }
|
||||
}
|
||||
|
||||
public enum SKILL_STATE
|
||||
@@ -147,14 +148,14 @@ namespace BrewMonster.Scripts.Skills
|
||||
{
|
||||
return new Dictionary<uint, int>();
|
||||
}
|
||||
public virtual ushort[] GetName() { return null; }
|
||||
public virtual string GetName() { return null; }
|
||||
public virtual byte[] GetNativeName() { return null; }
|
||||
// �������?,��skill_type
|
||||
public virtual byte GetType() { return 1; }
|
||||
// ����ͼ��
|
||||
public virtual byte[] GetIcon() { return null; }
|
||||
public virtual string GetIcon() { return null; }
|
||||
// ����˵��
|
||||
public virtual ushort[] GetIntroduction(string buf, int len, SkillStr table) { return new ushort[0]; }
|
||||
public virtual string GetIntroduction(StringBuilder buf, int len, SkillStr table) { return ""; }
|
||||
// ����ְҵ����
|
||||
public virtual int GetCls() { return -1; }
|
||||
// ������ȴʱ�䣬��λ����
|
||||
|
||||
@@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||
|
||||
namespace BrewMonster.Scripts.Skills
|
||||
{
|
||||
|
||||
public class Range
|
||||
{
|
||||
/// <summary>0=point 1=line 2=self sphere 3=target sphere 4=cone 5=self</summary>
|
||||
@@ -54,12 +53,18 @@ namespace BrewMonster.Scripts.Skills
|
||||
{
|
||||
return stub.GetCls();
|
||||
}
|
||||
public override Dictionary<uint , int > GetJunior()
|
||||
public override Dictionary<uint, int> GetJunior()
|
||||
{
|
||||
return stub.is_senior != 0 ? stub.pre_skills : new Dictionary<uint, int>();
|
||||
return stub.is_senior != 0 ? stub.pre_skills : new Dictionary<uint, int>();
|
||||
}
|
||||
public override string GetIcon()
|
||||
{
|
||||
return stub.GetIcon();
|
||||
}
|
||||
public override string GetName() { return stub.GetName(); }
|
||||
}
|
||||
|
||||
|
||||
public abstract class SkillStub
|
||||
{
|
||||
public const int MIN_LEVEL = 1;
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
using BrewMonster.Assets.PerfectWorld.Scripts.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BrewMonster.Assets.PerfectWorld.Scripts.UI
|
||||
{
|
||||
public class CECUIConfig : Singleton<CECUIConfig>
|
||||
{
|
||||
GameUI m_gameUI;
|
||||
public GameUI GetGameUI()
|
||||
{
|
||||
return m_gameUI;
|
||||
}
|
||||
}
|
||||
|
||||
public struct RandomMapItem
|
||||
{
|
||||
public int itemID;
|
||||
public int count;
|
||||
|
||||
public RandomMapItem(int itemId, int itemCount)
|
||||
{
|
||||
itemID = itemId;
|
||||
count = itemCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Wallow hint info type
|
||||
public enum WallowHintType
|
||||
{
|
||||
WHT_DEFAULT = 0, // Default mode
|
||||
WHT_KOREA = 1, // Korean mode
|
||||
}
|
||||
|
||||
// Recommend shop item type
|
||||
public enum RecommendShopItemType
|
||||
{
|
||||
RECOMMEND_REFINE_1, // Equipment refinement level 1
|
||||
RECOMMEND_REFINE_2, // Equipment refinement level 2
|
||||
RECOMMEND_REFINE_3, // Equipment refinement level 3
|
||||
RECOMMEND_REFINE_4, // Equipment refinement level 4
|
||||
RECOMMEND_REFINE_5, // Equipment refinement level 5
|
||||
RECOMMEND_SAVE_LIFE, // Save life
|
||||
RECOMMEND_ACTIVITY, // Activity reminder
|
||||
}
|
||||
|
||||
// Game logic and UI related configuration
|
||||
public struct GameUI
|
||||
{
|
||||
public bool bMailToFriendsSwitch; // Mail to friends
|
||||
public int nMailToFriendsDaysNoLogin; // Days not logged in to trigger mail to friends
|
||||
public int nMailToFriendsLevel; // Level required to use mail to friends
|
||||
public int nMailToFriendsDaysSendMail; // Days interval to send mail again
|
||||
|
||||
public bool bActivityReminder; // Activity reminder
|
||||
public int nActivityReminderLevel; // Level requirement
|
||||
public int nActivityReminderMaxLevelSoFar; // Historical maximum level requirement
|
||||
public int nActivityReminderLevel2; // Second level requirement
|
||||
public int nActivityReminderReincarnationTimes;// Reincarnation times requirement
|
||||
public int nActivityReminderRealmLevel; // Realm level requirement
|
||||
public int nActivityReminderReputation; // Reputation requirement
|
||||
public DateTime tActivityReminderStartTime; // Start time (local time)
|
||||
public DateTime tActivityReminderEndTime; // End time (local time)
|
||||
|
||||
public bool bEnableTalkToGM; // Enable sending non-standard messages to GM
|
||||
public bool bEnableTrashPwdRemind; // Enable trash password reminder for users
|
||||
|
||||
public WallowHintType nWallowHintType; // Wallow hint display type
|
||||
|
||||
public bool bEnableIE; // Enable IE to display web pages
|
||||
public bool bEnableShowIP; // Whether to show last login information
|
||||
public bool bEnableCompleteAccount; // Whether to show account completion information
|
||||
public bool bEnableFortressBuildDestroy; // Whether to enable fortress build/destroy facilities
|
||||
public List<int> nCountryWarBonus; // Country war bonus levels
|
||||
public bool bShowNameInCountryWar; // Whether to show player names in country war
|
||||
public int nCountryWarEnterLevel; // Country war entry level requirement
|
||||
public int nCountryWarEnterItem; // Country war entry item id
|
||||
public int nCountryWarEnterItemCount; // Country war entry item count
|
||||
public bool bEnableQuickPay; // Enable quick payment
|
||||
public int nEquipMarkMinInkNum; // Minimum ink number required for equipment mark modification
|
||||
public bool bEnableReportPlayerSpeakToGM; // Enable reporting player speech to GM
|
||||
public bool bEnableReportPluginWithFeedback; // Enable plugin reporting with feedback
|
||||
public uint nGTLoginCoolDown; // Game GT account login cooldown time (in seconds)
|
||||
public bool bEnableGTOnSpecialServer; // Whether to enable GT on special servers
|
||||
public int nCrossServerEnterLevel; // Cross server entry level requirement
|
||||
public int nCrossServerEnterLevel2; // Cross server entry level requirement 2
|
||||
public bool bEnableWebTradeSort; // Enable sorting when searching for items in web trade
|
||||
public bool bEnablePlayerRename; // Enable player rename
|
||||
public bool bEnableCheckNewbieGift; // Enable newbie gift display
|
||||
public bool bEnableQShopFilter; // Enable QShop filter display function (filtered by player level)
|
||||
public bool bEnableGivingFor; // Enable QShop gift and receive function
|
||||
public bool bEnableGivingForTaskLimitedItem; // Enable QShop certain task-limited items gift and receive function
|
||||
public List<int> nCountryWarPlayerLimit; // Country war battle player count limit
|
||||
public int nCountryWarKingMaxDomainLimit; // Country war king maximum domain limit
|
||||
public int nFashionSplitCost; // Fashion split cost
|
||||
public bool bEnableTouch; // Touch shop enable
|
||||
public bool bEnableOptimize; // Whether to enable client optimization
|
||||
public int nMemoryUsageLow; // Low memory value, system will automatically restore normal model
|
||||
public int nMemoryUsageHigh; // High memory value, system will automatically reduce level model
|
||||
public int nAutoSimplifySpeed; // Auto simplify speed after long time
|
||||
public List<int> nTouchEnabledMap; // TOUCH shop enabled maps
|
||||
public bool bEnableTWRecharge; // Shop recharge button (for Taiwan region recharge platform)
|
||||
public string strTWRechargeAppID; // Taiwan recharge platform parameter AppID (developer code)
|
||||
public string strTWRechargeGame; // Taiwan recharge platform parameter Game (game code)
|
||||
public string strTWRechargeKey; // Taiwan recharge platform parameter Key (additional verification key)
|
||||
public bool bEnableTitle; // Enable Title UI
|
||||
public List<int> nAutoTeamTransmitEnabledMap; // Auto team transmit enabled map IDs
|
||||
public int nChariotApplyLevel; // Chariot application level requirement
|
||||
public int nChariotApplyLevel2; // Chariot application level requirement 2
|
||||
public int nChariotApplyReincarnation; // Chariot application reincarnation requirement
|
||||
public int nChariotReviveTimeout; // Chariot revive timeout
|
||||
public int nChariotAmount; // Chariot battle chariot count
|
||||
public int nHistoryQueryTimeInterval; // History query time interval
|
||||
public bool bEnableAutoWiki; // Auto wiki enable
|
||||
public int nExitAutoExtractWikiStateTime; // Auto wiki: exit auto extract time
|
||||
public int nCloseWikiPopDlgTime; // Auto wiki: close time
|
||||
public int nCloseWikiMsgInfoTime; // Auto wiki: message disappear time
|
||||
public int nOpenWikiPopDlgTime; // Auto wiki: open time
|
||||
public List<int> nTaskDisabledInMiniClient; // Tasks disabled in mini client
|
||||
public List<int> nItemDisabledInMiniClient; // Items disabled in mini client
|
||||
public List<int> nMeridianFreeItem; // Meridian free item ID list
|
||||
public List<int> nMeridianNotFreeItem; // Meridian not free item ID list
|
||||
public int nMonsterSpiritGatherTimesPerWeekMax;// Maximum monster spirit gather times per week
|
||||
public bool bEnableAutoPolicy; // Auto policy system enable
|
||||
public bool bEnablePWService; // Enable PW service page
|
||||
public bool bEnableActionSwitch; // Action switch enable (attack->defense, defense->attack, auto return before using skill)
|
||||
public int nCountryWarLiveShowUpdateInterval; // Country war live show data update interval
|
||||
public List<int> nDefaultSystemModuleIndex; // System module default function index
|
||||
public bool bEnableRecommendQShopItem; // Recommend QShop items when appropriate
|
||||
public List<int> nRecommendShopItems; // Recommended shop items list
|
||||
public bool bEnableRandShop; // Whether to enable random shop (in new version, old version follows original agreement, this function is disabled)
|
||||
public int nPokerShopConfig; // Poker shop config table ID
|
||||
public int nPokerShopLevelLimit; // Poker shop usage level requirement
|
||||
public int nContributionTaskLevelLimit; // Contribution task system usage level requirement
|
||||
public List<string> strFashionShopAdImage; // Fashion shop advertisement images
|
||||
public bool bEnableQShopFashionShop; // QShop fashion shop enable
|
||||
public bool bEnableBackShopFashionShop; // Back shop fashion shop enable
|
||||
public bool bEnableCeilPriceBeforeDiscountToGold; // Shop discount item original price only shows gold, if original price can be converted to gold, show original price (except market)
|
||||
public List<string> strFullScreenGfxForeground; // Full screen effect foreground effect
|
||||
public List<string> strFullScreenGfxBackground; // Full screen effect background effect
|
||||
public List<int> nRandomMaps; // Random maps
|
||||
public List<int> nTaskIDForDisableWayPointUITips; // Task IDs that need to disable waypoint tip display when doing these tasks
|
||||
public RandomMapItem DefaultRandomMapItem; // Default random map item distribution item
|
||||
public Dictionary<int, RandomMapItem> SpecialRandomMapItems; // Specific random map special random map item distribution item
|
||||
public int nMaxFriendRemarksNameLength; // Friend remarks name maximum length
|
||||
public bool bEnableQShopFashionShopFlashSale; // QShop fashion shop flash sale enable
|
||||
public bool bEnableBackShopFashionShopFlashSale; // Back shop fashion shop flash sale enable
|
||||
public string strQShopFashionShopFlashSaleTitle; // QShop fashion shop flash sale button title
|
||||
public string strBackShopFashionShopFlashSaleTitle; // Back shop fashion shop flash sale button title
|
||||
public bool bEnablePlayerChangeGender;
|
||||
|
||||
public int GetCountryWarBonusLevel(int currentBonus)
|
||||
{
|
||||
// Get country war current bonus level, starting from level 0, return -1 if invalid
|
||||
int level = -1;
|
||||
while (level + 1 < nCountryWarBonus.Count && currentBonus > nCountryWarBonus[level + 1])
|
||||
{
|
||||
level++;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
public int GetCountryWarPlayerLimit(int warType)
|
||||
{
|
||||
if (warType >= 0 && warType < nCountryWarPlayerLimit.Count)
|
||||
{
|
||||
return nCountryWarPlayerLimit[warType];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool GetCanShowTouchShop(int idInst)
|
||||
{
|
||||
return nTouchEnabledMap.Contains(idInst);
|
||||
}
|
||||
|
||||
public bool IsTaskDisabledInMiniClient(int task_id)
|
||||
{
|
||||
return nTaskDisabledInMiniClient.Contains(task_id);
|
||||
}
|
||||
|
||||
public bool IsItemDisabledInMiniClient(int item_id)
|
||||
{
|
||||
return nItemDisabledInMiniClient.Contains(item_id);
|
||||
}
|
||||
|
||||
public bool IsMeridianFreeItem(int item_id)
|
||||
{
|
||||
return nMeridianFreeItem.Contains(item_id);
|
||||
}
|
||||
|
||||
public bool IsMeridianNotFreeItem(int item_id)
|
||||
{
|
||||
return nMeridianNotFreeItem.Contains(item_id);
|
||||
}
|
||||
|
||||
public bool IsRandomMap(int mapid)
|
||||
{
|
||||
return nRandomMaps.Contains(mapid);
|
||||
}
|
||||
|
||||
public int GetRandomMapCount()
|
||||
{
|
||||
return nRandomMaps.Count;
|
||||
}
|
||||
|
||||
public int GetRandomMapID(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx < nRandomMaps.Count)
|
||||
{
|
||||
return nRandomMaps[idx];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool GetRandomMapItemInfo(int mapID, out RandomMapItem info)
|
||||
{
|
||||
if (SpecialRandomMapItems.TryGetValue(mapID, out info))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If not found in special items, return false (not using default)
|
||||
info = default(RandomMapItem);
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetTaskIDDisableWayPointsUITipsCount()
|
||||
{
|
||||
return nTaskIDForDisableWayPointUITips.Count;
|
||||
}
|
||||
|
||||
public int GetTaskIDDisableWayPointsUITips(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx < nTaskIDForDisableWayPointUITips.Count)
|
||||
{
|
||||
return nTaskIDForDisableWayPointUITips[idx];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetRecommendShopItem(RecommendShopItemType type)
|
||||
{
|
||||
int index = (int)type;
|
||||
if (index >= 0 && index < nRecommendShopItems.Count)
|
||||
{
|
||||
return nRecommendShopItems[index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2db7d5cd42386b448927779069efcf1c
|
||||
+321
-231
@@ -1,5 +1,6 @@
|
||||
using BrewMonster;
|
||||
using BrewMonster.Assets.PerfectWorld.Scripts.Players;
|
||||
using BrewMonster.Assets.PerfectWorld.Scripts.Skills;
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts;
|
||||
@@ -56,9 +57,13 @@ public class CECHostPlayer : CECPlayer
|
||||
private int m_iRoleCreateTime;
|
||||
private int m_iRoleLastLoginTime; // Role last login time
|
||||
private int m_iAccountTotalCash;
|
||||
|
||||
private List<CECObject> m_aTabSels = new List<CECObject>();
|
||||
private List<CECSkill> m_aPtSkills = new List<CECSkill>();
|
||||
private List<CECSkill> m_aEquipSkills = new List<CECSkill>();
|
||||
private List<CECSkill> m_aGoblinSkills = new List<CECSkill>();
|
||||
|
||||
|
||||
private CECSkill m_pPrepSkill;
|
||||
private float playerSpeed = 5.0f;
|
||||
private float jumpHeight = 1.5f;
|
||||
private float gravityValue = -9.81f;
|
||||
@@ -965,9 +970,9 @@ public class CECHostPlayer : CECPlayer
|
||||
return;
|
||||
}
|
||||
|
||||
if (false /*CECUIConfig::Instance().GetGameUI().bEnableActionSwitch*/)
|
||||
{ //m_pActionSwitcher = new CECActionSwitcher(this);
|
||||
|
||||
if (true /*CECUIConfig::Instance().GetGameUI().bEnableActionSwitch*/)
|
||||
{
|
||||
m_pActionSwitcher = new CECActionSwitcher(this);
|
||||
}
|
||||
else
|
||||
m_pActionSwitcher = new CECActionSwitcherBase(this);
|
||||
@@ -1455,274 +1460,308 @@ public class CECHostPlayer : CECPlayer
|
||||
{
|
||||
return m_ExtProps.mv.swim_speed;
|
||||
}
|
||||
public bool ApplySkillShortcut(int idSkill, bool bCombo = false /* false */,
|
||||
int idSelTarget = 0/* 0 */, int iForceAtk = -1/* -1 */)
|
||||
public bool ApplySkillShortcut(int idSkill, bool bCombo = false /* false */,
|
||||
int idSelTarget = 0/* 0 */, int iForceAtk = -1/* -1 */)
|
||||
{
|
||||
//StackChecker::ACTrace(4);
|
||||
|
||||
/* if (m_pActionSwitcher != null)
|
||||
m_pActionSwitcher.PostMessge(EMsgActionSwitcher.MSG_CASTSKILL);
|
||||
if (m_pActionSwitcher != null)
|
||||
m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_CASTSKILL);
|
||||
|
||||
// Return-town skill is very special, handle it separately
|
||||
if (idSkill == ID_RETURNTOWN_SKILL)
|
||||
return ReturnToTargetTown(0, bCombo);
|
||||
//if (idSkill == ID_RETURNTOWN_SKILL)
|
||||
// return ReturnToTargetTown(0, bCombo);
|
||||
|
||||
if (idSkill == ID_SUMMONPLAYER_SKILL)
|
||||
return SummonPlayer(idSelTarget, bCombo);
|
||||
//if (idSkill == ID_SUMMONPLAYER_SKILL)
|
||||
// return SummonPlayer(idSelTarget, bCombo);
|
||||
|
||||
if (!CanDo(CANDO_SPELLMAGIC))
|
||||
return false;
|
||||
//if (!CanDo(CANDO_SPELLMAGIC))
|
||||
// return false;
|
||||
|
||||
if (InSlidingState())
|
||||
return false;
|
||||
//if (InSlidingState())
|
||||
// return false;
|
||||
|
||||
if (!bCombo)
|
||||
ClearComboSkill();
|
||||
//ClearComboSkill();
|
||||
|
||||
if (!idSelTarget)
|
||||
idSelTarget = m_idSelTarget;
|
||||
if (idSelTarget == 0)
|
||||
idSelTarget = m_idSelTarget;
|
||||
|
||||
CECSkill* pSkill = GetPositiveSkillByID(idSkill);
|
||||
if (!pSkill) pSkill = GetEquipSkillByID(idSkill);
|
||||
if (!pSkill) pSkill = CECComboSkillState::Instance().GetInherentSkillByID(idSkill);
|
||||
if (!pSkill)
|
||||
CECSkill pSkill = GetPositiveSkillByID(idSkill);
|
||||
if (pSkill == null) pSkill = GetEquipSkillByID(idSkill);
|
||||
if (pSkill == null) pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill);
|
||||
if (pSkill == null)
|
||||
{
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we press a chargeable skill again when it's being charged,
|
||||
// we cast it out at once
|
||||
if (IsSpellingMagic() && m_pCurSkill && m_pCurSkill->IsCharging() &&
|
||||
m_pCurSkill->GetSkillID() == pSkill->GetSkillID())
|
||||
{
|
||||
m_pCurSkill->EndCharging();
|
||||
g_pGame->GetGameSession()->c2s_CmdContinueAction();
|
||||
return true;
|
||||
}
|
||||
//// If we press a chargeable skill again when it's being charged,
|
||||
//// we cast it out at once
|
||||
//if (IsSpellingMagic() && m_pCurSkill && m_pCurSkill->IsCharging() &&
|
||||
// m_pCurSkill->GetSkillID() == pSkill->GetSkillID())
|
||||
//{
|
||||
// m_pCurSkill->EndCharging();
|
||||
// g_pGame->GetGameSession()->c2s_CmdContinueAction();
|
||||
// return true;
|
||||
//}
|
||||
|
||||
int iCon = CheckSkillCastCondition(pSkill);
|
||||
if (iCon)
|
||||
{
|
||||
ProcessSkillCondition(iCon);
|
||||
return false;
|
||||
}
|
||||
//int iCon = CheckSkillCastCondition(pSkill);
|
||||
//if (iCon)
|
||||
//{
|
||||
// ProcessSkillCondition(iCon);
|
||||
// return false;
|
||||
//}
|
||||
|
||||
// Get force attack flag
|
||||
bool bForceAttack;
|
||||
if (iForceAtk < 0)
|
||||
bForceAttack = glb_GetForceAttackFlag(NULL);
|
||||
else
|
||||
bForceAttack = iForceAtk > 0 ? true : false;
|
||||
//// Get force attack flag
|
||||
bool bForceAttack = true;
|
||||
//if (iForceAtk < 0)
|
||||
// bForceAttack = glb_GetForceAttackFlag(0);
|
||||
//else
|
||||
// bForceAttack = iForceAtk > 0 ? true : false;
|
||||
|
||||
// Check negative effect skill
|
||||
if (pSkill->GetType() == CECSkill::TYPE_ATTACK || pSkill->GetType() == CECSkill::TYPE_CURSE)
|
||||
{
|
||||
if (idSelTarget == m_PlayerInfo.cid)
|
||||
{
|
||||
// Host cannot spell negative effect magic to himself.
|
||||
g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT);
|
||||
return false;
|
||||
}
|
||||
else if (idSelTarget)
|
||||
{
|
||||
if (AttackableJudge(idSelTarget, bForceAttack) != 1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//// Check negative effect skill
|
||||
//if (pSkill->GetType() == CECSkill::TYPE_ATTACK || pSkill->GetType() == CECSkill::TYPE_CURSE)
|
||||
//{
|
||||
// if (idSelTarget == m_PlayerInfo.cid)
|
||||
// {
|
||||
// // Host cannot spell negative effect magic to himself.
|
||||
// g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT);
|
||||
// return false;
|
||||
// }
|
||||
// else if (idSelTarget)
|
||||
// {
|
||||
// if (AttackableJudge(idSelTarget, bForceAttack) != 1)
|
||||
// return false;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Check whether target type match
|
||||
int idCastTarget = idSelTarget;
|
||||
int iTargetType = pSkill->GetTargetType();
|
||||
//// Check whether target type match
|
||||
//int idCastTarget = idSelTarget;
|
||||
//int iTargetType = pSkill->GetTargetType();
|
||||
|
||||
if (pSkill->GetType() == CECSkill::TYPE_BLESS ||
|
||||
pSkill->GetType() == CECSkill::TYPE_NEUTRALBLESS)
|
||||
{
|
||||
if (!iTargetType || !ISPLAYERID(idSelTarget))
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
//if (pSkill->GetType() == CECSkill::TYPE_BLESS ||
|
||||
// pSkill->GetType() == CECSkill::TYPE_NEUTRALBLESS)
|
||||
//{
|
||||
// if (!iTargetType || !ISPLAYERID(idSelTarget))
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
|
||||
// In some case, we shouldn't add bless effect to other players
|
||||
if (ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid)
|
||||
{
|
||||
// If host has set bless skill filter only to himself, bless skill couldn't add to other players
|
||||
BYTE byBLSMask = glb_BuildBLSMask();
|
||||
// // In some case, we shouldn't add bless effect to other players
|
||||
// if (ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid)
|
||||
// {
|
||||
// // If host has set bless skill filter only to himself, bless skill couldn't add to other players
|
||||
// BYTE byBLSMask = glb_BuildBLSMask();
|
||||
|
||||
if (pSkill->GetRangeType() == CECSkill::RANGE_POINT)
|
||||
{
|
||||
if (!IsTeamMember(idCastTarget))
|
||||
{
|
||||
if (byBLSMask & GP_BLSMASK_SELF)
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
else
|
||||
{
|
||||
CECElsePlayer* pPlayer = (CECElsePlayer*)g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idCastTarget);
|
||||
if (!pPlayer)
|
||||
{
|
||||
// Ä¿±êÏûʧ
|
||||
return false;
|
||||
}
|
||||
// if (pSkill->GetRangeType() == CECSkill::RANGE_POINT)
|
||||
// {
|
||||
// if (!IsTeamMember(idCastTarget))
|
||||
// {
|
||||
// if (byBLSMask & GP_BLSMASK_SELF)
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
// else
|
||||
// {
|
||||
// CECElsePlayer* pPlayer = (CECElsePlayer*)g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idCastTarget);
|
||||
// if (!pPlayer)
|
||||
// {
|
||||
// // Ä¿±êÏûʧ
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (pPlayer->IsInvader() || pPlayer->IsPariah())
|
||||
{
|
||||
if (byBLSMask & GP_BLSMASK_NORED)
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
}
|
||||
// if (pPlayer->IsInvader() || pPlayer->IsPariah())
|
||||
// {
|
||||
// if (byBLSMask & GP_BLSMASK_NORED)
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
// }
|
||||
|
||||
if (!IsFactionMember(pPlayer->GetFactionID()))
|
||||
{
|
||||
if (byBLSMask & GP_BLSMASK_NOMAFIA)
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
}
|
||||
// if (!IsFactionMember(pPlayer->GetFactionID()))
|
||||
// {
|
||||
// if (byBLSMask & GP_BLSMASK_NOMAFIA)
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
// }
|
||||
|
||||
if (!IsFactionAllianceMember(pPlayer->GetFactionID()))
|
||||
{
|
||||
if (byBLSMask & GP_BLSMASK_NOALLIANCE)
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
}
|
||||
if (GetForce() != pPlayer->GetForce())
|
||||
{
|
||||
if (byBLSMask & GP_BLSMASK_NOFORCE)
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (!IsFactionAllianceMember(pPlayer->GetFactionID()))
|
||||
// {
|
||||
// if (byBLSMask & GP_BLSMASK_NOALLIANCE)
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
// }
|
||||
// if (GetForce() != pPlayer->GetForce())
|
||||
// {
|
||||
// if (byBLSMask & GP_BLSMASK_NOFORCE)
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// If host is in duel, bless skill couldn't add to opponent
|
||||
if (IsInDuel() && idSelTarget == m_pvp.idDuelOpp)
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
// // If host is in duel, bless skill couldn't add to opponent
|
||||
// if (IsInDuel() && idSelTarget == m_pvp.idDuelOpp)
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
|
||||
// If host is in battle, bless skill couldn't add to enemies
|
||||
if (IsInBattle())
|
||||
{
|
||||
CECElsePlayer* pPlayer = m_pPlayerMan->GetElsePlayer(idCastTarget);
|
||||
if (!InSameBattleCamp(pPlayer))
|
||||
idCastTarget = m_PlayerInfo.cid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pSkill->GetType() == CECSkill::TYPE_BLESSPET)
|
||||
{
|
||||
CECPet* pPet = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetPetByID(idSelTarget);
|
||||
if (!pPet || pPet->GetMasterID() == GetCharacterID())
|
||||
{
|
||||
// Spell skill on host's pet
|
||||
CECPetData* pPetData = m_pPetCorral->GetActivePet();
|
||||
if (!pPetData ||
|
||||
pPetData->GetClass() != GP_PET_CLASS_COMBAT &&
|
||||
pPetData->GetClass() != GP_PET_CLASS_SUMMON &&
|
||||
pPetData->GetClass() != GP_PET_CLASS_EVOLUTION)
|
||||
return false;
|
||||
// // If host is in battle, bless skill couldn't add to enemies
|
||||
// if (IsInBattle())
|
||||
// {
|
||||
// CECElsePlayer* pPlayer = m_pPlayerMan->GetElsePlayer(idCastTarget);
|
||||
// if (!InSameBattleCamp(pPlayer))
|
||||
// idCastTarget = m_PlayerInfo.cid;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//else if (pSkill->GetType() == CECSkill::TYPE_BLESSPET)
|
||||
//{
|
||||
// CECPet* pPet = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetPetByID(idSelTarget);
|
||||
// if (!pPet || pPet->GetMasterID() == GetCharacterID())
|
||||
// {
|
||||
// // Spell skill on host's pet
|
||||
// CECPetData* pPetData = m_pPetCorral->GetActivePet();
|
||||
// if (!pPetData ||
|
||||
// pPetData->GetClass() != GP_PET_CLASS_COMBAT &&
|
||||
// pPetData->GetClass() != GP_PET_CLASS_SUMMON &&
|
||||
// pPetData->GetClass() != GP_PET_CLASS_EVOLUTION)
|
||||
// return false;
|
||||
|
||||
idCastTarget = m_pPetCorral->GetActivePetNPCID();
|
||||
}
|
||||
// Only fighting pet can be blessed.
|
||||
if (pPet && !pPet->CanBeAttacked())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iTargetType != 0 && !idCastTarget)
|
||||
return false;
|
||||
}
|
||||
// idCastTarget = m_pPetCorral->GetActivePetNPCID();
|
||||
// }
|
||||
// // Only fighting pet can be blessed.
|
||||
// if (pPet && !pPet->CanBeAttacked())
|
||||
// return false;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// if (iTargetType != 0 && !idCastTarget)
|
||||
// return false;
|
||||
//}
|
||||
|
||||
// iTargetType == 4 means target must be pet. The problem is that pet will
|
||||
// disappear from world after it died, so GetWorld()->GetObject() will return
|
||||
// NULL when host spells revive-pet skill on his dead pet. So, the target
|
||||
// type of revive-pet skill should be 0
|
||||
if (iTargetType)
|
||||
{
|
||||
// Target shoundn't be a corpse ?
|
||||
int iAliveFlag = 0;
|
||||
if (iTargetType == 1)
|
||||
iAliveFlag = 1;
|
||||
else if (iTargetType == 2)
|
||||
iAliveFlag = 2;
|
||||
//// iTargetType == 4 means target must be pet. The problem is that pet will
|
||||
//// disappear from world after it died, so GetWorld()->GetObject() will return
|
||||
//// NULL when host spells revive-pet skill on his dead pet. So, the target
|
||||
//// type of revive-pet skill should be 0
|
||||
//if (iTargetType)
|
||||
//{
|
||||
// // Target shoundn't be a corpse ?
|
||||
// int iAliveFlag = 0;
|
||||
// if (iTargetType == 1)
|
||||
// iAliveFlag = 1;
|
||||
// else if (iTargetType == 2)
|
||||
// iAliveFlag = 2;
|
||||
|
||||
CECObject* pObject = g_pGame->GetGameRun()->GetWorld()->GetObject(idCastTarget, iAliveFlag);
|
||||
if (!pObject)
|
||||
return false;
|
||||
}
|
||||
// CECObject* pObject = g_pGame->GetGameRun()->GetWorld()->GetObject(idCastTarget, iAliveFlag);
|
||||
// if (!pObject)
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (!IsMeleeing() && !IsSpellingMagic() &&
|
||||
(!iTargetType || idCastTarget == m_PlayerInfo.cid))
|
||||
{
|
||||
// Cast this skill need't checking cast distance
|
||||
if (!pSkill->ReadyToCast())
|
||||
return false;
|
||||
//if (!IsMeleeing() && !IsSpellingMagic() &&
|
||||
// (!iTargetType || idCastTarget == m_PlayerInfo.cid))
|
||||
//{
|
||||
// // Cast this skill need't checking cast distance
|
||||
// if (!pSkill->ReadyToCast())
|
||||
// return false;
|
||||
|
||||
// Prepare to cast skill, if skill isn't INSTANT and FLASHMOVE,
|
||||
// we must stop moving and stand
|
||||
if (!pSkill->IsInstant() && pSkill->GetType() != CECSkill::TYPE_FLASHMOVE)
|
||||
{
|
||||
if (!NaturallyStopMoving())
|
||||
return false; // Couldn't stop naturally, so cancel casting skill
|
||||
}
|
||||
else if (pSkill->GetType() == CECSkill::TYPE_FLASHMOVE)
|
||||
{
|
||||
if (!CanDo(CANDO_FLASHMOVE))
|
||||
return false;
|
||||
}
|
||||
// // Prepare to cast skill, if skill isn't INSTANT and FLASHMOVE,
|
||||
// // we must stop moving and stand
|
||||
// if (!pSkill->IsInstant() && pSkill->GetType() != CECSkill::TYPE_FLASHMOVE)
|
||||
// {
|
||||
// if (!NaturallyStopMoving())
|
||||
// return false; // Couldn't stop naturally, so cancel casting skill
|
||||
// }
|
||||
// else if (pSkill->GetType() == CECSkill::TYPE_FLASHMOVE)
|
||||
// {
|
||||
// if (!CanDo(CANDO_FLASHMOVE))
|
||||
// return false;
|
||||
// }
|
||||
|
||||
m_pPrepSkill = pSkill;
|
||||
CastSkill(m_PlayerInfo.cid, bForceAttack);
|
||||
}
|
||||
else if (IsSpellingMagic() && m_pCurSkill == pSkill)
|
||||
{
|
||||
// If we are casting the same skill and it's in cooling time
|
||||
return false;
|
||||
}
|
||||
else // Have to trace selected object before cast skill
|
||||
{
|
||||
if (!pSkill->ReadyToCast())
|
||||
return false;
|
||||
// m_pPrepSkill = pSkill;
|
||||
CastSkill(m_PlayerInfo.cid, bForceAttack);
|
||||
//}
|
||||
//else if (IsSpellingMagic() && m_pCurSkill == pSkill)
|
||||
//{
|
||||
// // If we are casting the same skill and it's in cooling time
|
||||
// return false;
|
||||
//}
|
||||
//else // Have to trace selected object before cast skill
|
||||
//{
|
||||
// if (!pSkill->ReadyToCast())
|
||||
// return false;
|
||||
|
||||
if (CECCastSkillWhenMove::Instance().IsSkillSupported(pSkill->GetSkillID(), this) &&
|
||||
m_pWorkMan->IsMovingToPosition() &&
|
||||
m_pWorkMan->CanCastSkillImmediately(pSkill->GetSkillID()))
|
||||
{
|
||||
m_pPrepSkill = pSkill;
|
||||
return CastSkill(idCastTarget, bForceAttack);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bTraceOK = false;
|
||||
bool bUseAutoPF = false;
|
||||
CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper();
|
||||
if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper->GetAttackError() >= 2)
|
||||
bUseAutoPF = true;
|
||||
// if (CECCastSkillWhenMove::Instance().IsSkillSupported(pSkill->GetSkillID(), this) &&
|
||||
// m_pWorkMan->IsMovingToPosition() &&
|
||||
// m_pWorkMan->CanCastSkillImmediately(pSkill->GetSkillID()))
|
||||
// {
|
||||
// m_pPrepSkill = pSkill;
|
||||
// return CastSkill(idCastTarget, bForceAttack);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// bool bTraceOK = false;
|
||||
// bool bUseAutoPF = false;
|
||||
// CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper();
|
||||
// if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper->GetAttackError() >= 2)
|
||||
// bUseAutoPF = true;
|
||||
|
||||
if (!idCastTarget)
|
||||
{
|
||||
idCastTarget = GetCharacterID(); // ±ÜÃâË²ÒÆµÈ¼¼ÄÜʱ idCastTarget Ϊ0µ¼Ö CECWorkTrace::CreateTraceTarget ·µ»Ø¿Õ
|
||||
}
|
||||
if (CECHPWork * pWork = m_pWorkMan->GetWork(CECHPWork::WORK_TRACEOBJECT))
|
||||
{
|
||||
CECHPWorkTrace* pWorkTrace = dynamic_cast<CECHPWorkTrace*>(pWork);
|
||||
if (pWorkTrace->GetTraceReason() == CECHPWorkTrace::TRACE_SPELL &&
|
||||
pWorkTrace->GetTarget() == idCastTarget &&
|
||||
pWorkTrace->GetPrepSkill() == pSkill)
|
||||
return false; // We are just doing the same thing
|
||||
// if (!idCastTarget)
|
||||
// {
|
||||
// idCastTarget = GetCharacterID(); // ±ÜÃâË²ÒÆµÈ¼¼ÄÜʱ idCastTarget Ϊ0µ¼Ö CECWorkTrace::CreateTraceTarget ·µ»Ø¿Õ
|
||||
// }
|
||||
// if (CECHPWork * pWork = m_pWorkMan->GetWork(CECHPWork::WORK_TRACEOBJECT))
|
||||
// {
|
||||
// CECHPWorkTrace* pWorkTrace = dynamic_cast<CECHPWorkTrace*>(pWork);
|
||||
// if (pWorkTrace->GetTraceReason() == CECHPWorkTrace::TRACE_SPELL &&
|
||||
// pWorkTrace->GetTarget() == idCastTarget &&
|
||||
// pWorkTrace->GetPrepSkill() == pSkill)
|
||||
// return false; // We are just doing the same thing
|
||||
|
||||
pWorkTrace->SetTraceTarget(pWorkTrace->CreatTraceTarget(idCastTarget, CECHPWorkTrace::TRACE_SPELL, bForceAttack), bUseAutoPF);
|
||||
pWorkTrace->SetPrepSkill(pSkill);
|
||||
bTraceOK = true;
|
||||
}
|
||||
else if (m_pWorkMan->CanStartWork(CECHPWork::WORK_TRACEOBJECT))
|
||||
{
|
||||
CECHPWorkTrace* pWork = (CECHPWorkTrace*)m_pWorkMan->CreateWork(CECHPWork::WORK_TRACEOBJECT);
|
||||
pWork->SetTraceTarget(pWork->CreatTraceTarget(idCastTarget, CECHPWorkTrace::TRACE_SPELL, bForceAttack), bUseAutoPF);
|
||||
pWork->SetPrepSkill(pSkill);
|
||||
m_pWorkMan->StartWork_p1(pWork);
|
||||
bTraceOK = true;
|
||||
}
|
||||
// pWorkTrace->SetTraceTarget(pWorkTrace->CreatTraceTarget(idCastTarget, CECHPWorkTrace::TRACE_SPELL, bForceAttack), bUseAutoPF);
|
||||
// pWorkTrace->SetPrepSkill(pSkill);
|
||||
// bTraceOK = true;
|
||||
// }
|
||||
// else if (m_pWorkMan->CanStartWork(CECHPWork::WORK_TRACEOBJECT))
|
||||
// {
|
||||
// CECHPWorkTrace* pWork = (CECHPWorkTrace*)m_pWorkMan->CreateWork(CECHPWork::WORK_TRACEOBJECT);
|
||||
// pWork->SetTraceTarget(pWork->CreatTraceTarget(idCastTarget, CECHPWorkTrace::TRACE_SPELL, bForceAttack), bUseAutoPF);
|
||||
// pWork->SetPrepSkill(pSkill);
|
||||
// m_pWorkMan->StartWork_p1(pWork);
|
||||
// bTraceOK = true;
|
||||
// }
|
||||
|
||||
if (!bTraceOK) return false;
|
||||
}
|
||||
}*/
|
||||
// if (!bTraceOK) return false;
|
||||
// }
|
||||
//}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CastSkill(int idTarget, bool bForceAttack, CECObject pTarget = null)
|
||||
{
|
||||
byte byPVPMask = glb_BuildPVPMask(bForceAttack);
|
||||
UnityGameSession.c2s_CmdCastSkill(m_pPrepSkill.GetSkillID(), byPVPMask, 1, idTarget);
|
||||
}
|
||||
public byte glb_BuildPVPMask(bool bForceAttack)
|
||||
{
|
||||
byte byMask = 0;
|
||||
if (bForceAttack)
|
||||
byMask |= (byte)PVPMask.GP_PVPMASK_FORCE;
|
||||
else
|
||||
{
|
||||
/* CECConfigs pConfigs = EC_Game.GetConfigs();
|
||||
|
||||
if (pConfigs->GetGameSettings().bAtk_Player)
|
||||
{
|
||||
byMask |= GP_PVPMASK_FORCE;
|
||||
|
||||
if (pConfigs->GetGameSettings().bAtk_NoMafia)
|
||||
byMask |= GP_PVPMASK_NOMAFIA;
|
||||
|
||||
if (pConfigs->GetGameSettings().bAtk_NoWhite)
|
||||
byMask |= GP_PVPMASK_NOWHITE;
|
||||
|
||||
if (pConfigs->GetGameSettings().bAtk_NoAlliance)
|
||||
byMask |= GP_PVPMASK_NOALLIANCE;
|
||||
|
||||
if (pConfigs->GetGameSettings().bAtk_NoForce)
|
||||
byMask |= GP_PVPMASK_NOFORCE;
|
||||
}*/
|
||||
}
|
||||
|
||||
return byMask;
|
||||
}
|
||||
public bool SelectTarget(int idTarget)
|
||||
{
|
||||
BMLogger.LogError("HoangDev: HostPlayer SelectTarget");
|
||||
@@ -1746,7 +1785,45 @@ public class CECHostPlayer : CECPlayer
|
||||
|
||||
return bRet;
|
||||
}
|
||||
public CECSkill GetPositiveSkillByID(int id, bool bSenior = false)
|
||||
{
|
||||
CECSkill pSenior = null;
|
||||
|
||||
for (int i = 0; i < m_aPtSkills.Count; i++)
|
||||
{
|
||||
if (m_aPtSkills[i].GetSkillID() == id)
|
||||
return m_aPtSkills[i];
|
||||
else if (m_aPtSkills[i].GetJunior().Find((uint)id))
|
||||
pSenior = m_aPtSkills[i];
|
||||
}
|
||||
|
||||
if (bSenior && pSenior != null)
|
||||
return pSenior;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// C# conversion of CECHostPlayer::GetEquipSkillByID
|
||||
// Assumes: GetEquipSkillNum() returns the count of equipment skills
|
||||
// GetEquipSkillByIndex(int) returns a CECSkill at the given index
|
||||
public CECSkill GetEquipSkillByID(int id)
|
||||
{
|
||||
CECSkill pRet = null;
|
||||
|
||||
for (int i = 0; i < GetEquipSkillNum(); i++)
|
||||
{
|
||||
CECSkill pSkill = GetEquipSkillByIndex(i);
|
||||
if (pSkill != null && pSkill.GetSkillID() == id)
|
||||
{
|
||||
pRet = pSkill;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
public int GetEquipSkillNum() { return m_aEquipSkills.Count; }
|
||||
public CECSkill GetEquipSkillByIndex(int n) { return m_aEquipSkills[n]; }
|
||||
bool CanSelectTarget(int idTarget)
|
||||
{
|
||||
if (idTarget == 0 || idTarget == this.GetCharacterID())
|
||||
@@ -2038,7 +2115,20 @@ public class CECHostPlayer : CECPlayer
|
||||
{
|
||||
m_idSelTarget = id;
|
||||
}
|
||||
public bool glb_GetForceAttackFlag(uint pdwParam)
|
||||
{
|
||||
|
||||
/*bool bForceAttack = false;
|
||||
CECInputCtrl* pInputCtrl = g_pGame->GetGameRun()->GetInputCtrl();
|
||||
|
||||
if (pdwParam)
|
||||
bForceAttack = pInputCtrl->IsCtrlPressed(*pdwParam);
|
||||
else
|
||||
bForceAttack = pInputCtrl->KeyIsBeingPressed(VK_CONTROL);
|
||||
|
||||
return bForceAttack;*/
|
||||
return true;
|
||||
}
|
||||
//public float GetSwimSpeedSev()
|
||||
//{
|
||||
// float fSpeedSev = GetSwimSpeed();
|
||||
|
||||
+158
-155
@@ -5,184 +5,187 @@ using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine; // thêm để dùng Resources & TextAsset
|
||||
|
||||
public class CECStringTab
|
||||
namespace BrewMonster
|
||||
{
|
||||
private readonly Dictionary<int, string> m_AStrTab = new Dictionary<int, string>();
|
||||
private readonly Dictionary<int, string> m_WStrTab = new Dictionary<int, string>();
|
||||
|
||||
private bool m_bInit = false;
|
||||
private bool m_bUnicode = false;
|
||||
|
||||
public CECStringTab() { }
|
||||
~CECStringTab() { Release(); }
|
||||
|
||||
public bool Init(string szFile, bool bUnicode)
|
||||
public class CECStringTab
|
||||
{
|
||||
Release();
|
||||
m_bUnicode = bUnicode;
|
||||
private readonly Dictionary<int, string> m_AStrTab = new Dictionary<int, string>();
|
||||
private readonly Dictionary<int, string> m_WStrTab = new Dictionary<int, string>();
|
||||
|
||||
try
|
||||
private bool m_bInit = false;
|
||||
private bool m_bUnicode = false;
|
||||
|
||||
public CECStringTab() { }
|
||||
~CECStringTab() { Release(); }
|
||||
|
||||
public bool Init(string szFile, bool bUnicode)
|
||||
{
|
||||
bool ok = bUnicode ? LoadWideStrings(szFile) : LoadANSIStrings(szFile);
|
||||
m_bInit = ok;
|
||||
return ok;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[CECStringTab] Init failed: {e}");
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_bUnicode = bUnicode;
|
||||
|
||||
public void Release()
|
||||
{
|
||||
m_AStrTab.Clear();
|
||||
m_WStrTab.Clear();
|
||||
m_bInit = false;
|
||||
m_bUnicode = false;
|
||||
}
|
||||
|
||||
public string GetANSIString(int n) => m_AStrTab.TryGetValue(n, out var s) ? s : null;
|
||||
public string GetWideString(int n) => m_WStrTab.TryGetValue(n, out var s) ? s : null;
|
||||
public string GetWideStringObject(int n) => GetWideString(n);
|
||||
public bool IsInitialized() => m_bInit;
|
||||
|
||||
// ==== Đọc từ Resources thay vì đường dẫn ====
|
||||
|
||||
protected bool LoadANSIStrings(string resourceName)
|
||||
{
|
||||
TextAsset textAsset = Resources.Load<TextAsset>(resourceName);
|
||||
if (textAsset == null)
|
||||
{
|
||||
Debug.LogError($"[CECStringTab] Resource not found: {resourceName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Giải mã bytes -> string (ANSI: dùng Encoding.Default)
|
||||
string content = ByteToStringUtils.ByteArrayToCP936String(textAsset.bytes);
|
||||
using var sr = new StringReader(content);
|
||||
return ParseIntoDict(sr, isWide: false);
|
||||
}
|
||||
|
||||
protected bool LoadWideStrings(string resourceName)
|
||||
{
|
||||
TextAsset textAsset = Resources.Load<TextAsset>(resourceName);
|
||||
if (textAsset == null)
|
||||
{
|
||||
Debug.LogError($"[CECStringTab] Resource not found: {resourceName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unity TextAsset mặc định đã decode text UTF8 -> textAsset.text
|
||||
// nhưng để chắc chắn BOM/Unicode thì đọc từ bytes
|
||||
string content;
|
||||
content = ByteToStringUtils.ByteArrayToUnicodeString(textAsset.bytes);
|
||||
|
||||
using var sr = new StringReader(content);
|
||||
return ParseIntoDict(sr, isWide: true);
|
||||
}
|
||||
|
||||
private static Encoding DetectEncoding(byte[] bom)
|
||||
{
|
||||
if (bom.Length >= 3 && bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) return Encoding.UTF8;
|
||||
if (bom.Length >= 2 && bom[0] == 0xFF && bom[1] == 0xFE) return Encoding.Unicode;
|
||||
if (bom.Length >= 2 && bom[0] == 0xFE && bom[1] == 0xFF) return Encoding.BigEndianUnicode;
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ParseIntoDict(StringReader sr, bool isWide)
|
||||
{
|
||||
bool bIndexMode = false;
|
||||
bool bBegan = false;
|
||||
int autoIndex = 0;
|
||||
|
||||
var allLines = new List<string>();
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
allLines.Add(line);
|
||||
}
|
||||
|
||||
for (int i = 0; i < allLines.Count; i++)
|
||||
{
|
||||
var ln = allLines[i].Trim();
|
||||
if (ln.Length == 0) continue;
|
||||
|
||||
if (ln.Equals("#_index", StringComparison.OrdinalIgnoreCase))
|
||||
try
|
||||
{
|
||||
bIndexMode = true;
|
||||
bool ok = bUnicode ? LoadWideStrings(szFile) : LoadANSIStrings(szFile);
|
||||
m_bInit = ok;
|
||||
return ok;
|
||||
}
|
||||
else if (ln.Equals("#_begin", StringComparison.OrdinalIgnoreCase))
|
||||
catch (Exception e)
|
||||
{
|
||||
bBegan = true;
|
||||
Debug.LogError($"[CECStringTab] Init failed: {e}");
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = i + 1; j < allLines.Count; j++)
|
||||
public void Release()
|
||||
{
|
||||
m_AStrTab.Clear();
|
||||
m_WStrTab.Clear();
|
||||
m_bInit = false;
|
||||
m_bUnicode = false;
|
||||
}
|
||||
|
||||
public string GetANSIString(int n) => m_AStrTab.TryGetValue(n, out var s) ? s : null;
|
||||
public string GetWideString(int n) => m_WStrTab.TryGetValue(n, out var s) ? s : null;
|
||||
public string GetWideStringObject(int n) => GetWideString(n);
|
||||
public bool IsInitialized() => m_bInit;
|
||||
|
||||
// ==== Đọc từ Resources thay vì đường dẫn ====
|
||||
|
||||
protected bool LoadANSIStrings(string resourceName)
|
||||
{
|
||||
TextAsset textAsset = Resources.Load<TextAsset>(resourceName);
|
||||
if (textAsset == null)
|
||||
{
|
||||
Debug.LogError($"[CECStringTab] Resource not found: {resourceName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Giải mã bytes -> string (ANSI: dùng Encoding.Default)
|
||||
string content = ByteToStringUtils.ByteArrayToCP936String(textAsset.bytes);
|
||||
using var sr = new StringReader(content);
|
||||
return ParseIntoDict(sr, isWide: false);
|
||||
}
|
||||
|
||||
protected bool LoadWideStrings(string resourceName)
|
||||
{
|
||||
TextAsset textAsset = Resources.Load<TextAsset>(resourceName);
|
||||
if (textAsset == null)
|
||||
{
|
||||
Debug.LogError($"[CECStringTab] Resource not found: {resourceName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unity TextAsset mặc định đã decode text UTF8 -> textAsset.text
|
||||
// nhưng để chắc chắn BOM/Unicode thì đọc từ bytes
|
||||
string content;
|
||||
content = ByteToStringUtils.ByteArrayToUnicodeString(textAsset.bytes);
|
||||
|
||||
using var sr = new StringReader(content);
|
||||
return ParseIntoDict(sr, isWide: true);
|
||||
}
|
||||
|
||||
private static Encoding DetectEncoding(byte[] bom)
|
||||
{
|
||||
if (bom.Length >= 3 && bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) return Encoding.UTF8;
|
||||
if (bom.Length >= 2 && bom[0] == 0xFF && bom[1] == 0xFE) return Encoding.Unicode;
|
||||
if (bom.Length >= 2 && bom[0] == 0xFE && bom[1] == 0xFF) return Encoding.BigEndianUnicode;
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ParseIntoDict(StringReader sr, bool isWide)
|
||||
{
|
||||
bool bIndexMode = false;
|
||||
bool bBegan = false;
|
||||
int autoIndex = 0;
|
||||
|
||||
var allLines = new List<string>();
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
allLines.Add(line);
|
||||
}
|
||||
|
||||
for (int i = 0; i < allLines.Count; i++)
|
||||
{
|
||||
var ln = allLines[i].Trim();
|
||||
if (ln.Length == 0) continue;
|
||||
|
||||
if (ln.Equals("#_index", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var payload = allLines[j].Trim();
|
||||
if (payload.Length == 0) continue;
|
||||
if (payload.StartsWith("#")) continue;
|
||||
if (payload.StartsWith("//")) continue;
|
||||
|
||||
|
||||
if (bIndexMode)
|
||||
{
|
||||
if (!TrySplitIndexAndText(payload, out int idx, out string text))
|
||||
continue;
|
||||
PutString(idx, text, isWide);
|
||||
}
|
||||
else
|
||||
{
|
||||
PutString(autoIndex++, payload, isWide);
|
||||
}
|
||||
bIndexMode = true;
|
||||
}
|
||||
else if (ln.Equals("#_begin", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
bBegan = true;
|
||||
|
||||
for (int j = i + 1; j < allLines.Count; j++)
|
||||
{
|
||||
var payload = allLines[j].Trim();
|
||||
if (payload.Length == 0) continue;
|
||||
if (payload.StartsWith("#")) continue;
|
||||
if (payload.StartsWith("//")) continue;
|
||||
|
||||
|
||||
if (bIndexMode)
|
||||
{
|
||||
if (!TrySplitIndexAndText(payload, out int idx, out string text))
|
||||
continue;
|
||||
PutString(idx, text, isWide);
|
||||
}
|
||||
else
|
||||
{
|
||||
PutString(autoIndex++, payload, isWide);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return bBegan;
|
||||
}
|
||||
|
||||
return bBegan;
|
||||
}
|
||||
|
||||
private static bool TrySplitIndexAndText(string line, out int index, out string text)
|
||||
{
|
||||
index = 0; text = null;
|
||||
|
||||
int eq = line.IndexOf('=');
|
||||
if (eq >= 0)
|
||||
private static bool TrySplitIndexAndText(string line, out int index, out string text)
|
||||
{
|
||||
var left = line.Substring(0, eq).Trim();
|
||||
var right = line.Substring(eq + 1);
|
||||
if (int.TryParse(left, out index))
|
||||
index = 0; text = null;
|
||||
|
||||
int eq = line.IndexOf('=');
|
||||
if (eq >= 0)
|
||||
{
|
||||
text = right;
|
||||
var left = line.Substring(0, eq).Trim();
|
||||
var right = line.Substring(eq + 1);
|
||||
if (int.TryParse(left, out index))
|
||||
{
|
||||
text = right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int sp = FirstWhiteSpaceIndex(line);
|
||||
if (sp <= 0) return false;
|
||||
|
||||
var left2 = line.Substring(0, sp).Trim();
|
||||
var right2 = line.Substring(sp).TrimStart();
|
||||
if (int.TryParse(left2, out index))
|
||||
{
|
||||
text = right2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int sp = FirstWhiteSpaceIndex(line);
|
||||
if (sp <= 0) return false;
|
||||
|
||||
var left2 = line.Substring(0, sp).Trim();
|
||||
var right2 = line.Substring(sp).TrimStart();
|
||||
if (int.TryParse(left2, out index))
|
||||
private static int FirstWhiteSpaceIndex(string s)
|
||||
{
|
||||
text = right2;
|
||||
return true;
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
if (char.IsWhiteSpace(s[i])) return i;
|
||||
return -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int FirstWhiteSpaceIndex(string s)
|
||||
{
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
if (char.IsWhiteSpace(s[i])) return i;
|
||||
return -1;
|
||||
private void PutString(int id, string value, bool isWide)
|
||||
{
|
||||
if (isWide) m_WStrTab[id] = value;
|
||||
else m_AStrTab[id] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void PutString(int id, string value, bool isWide)
|
||||
{
|
||||
if (isWide) m_WStrTab[id] = value;
|
||||
else m_AStrTab[id] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-403
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user