Merge pull request 'feature/useItem' (#140) from feature/useItem into develop

Reviewed-on: https://git.brew.monster/Unity/perfect-world-unity/pulls/140
This commit is contained in:
hainh
2026-01-29 10:12:19 +00:00
35 changed files with 11740 additions and 1980 deletions
@@ -663,7 +663,7 @@ namespace BrewMonster.Common
{
int piMax = -1;
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
if (pHost.GetCoolTime((int)CSNetwork.GPDataType.CoolTimeIndex.GP_CT_QUERY_MAFIA_PVP_INFO, ref piMax) == 0)
if (pHost.GetCoolTime((int)CSNetwork.GPDataType.CoolTimeIndex.GP_CT_QUERY_MAFIA_PVP_INFO, out piMax) == 0)
{
UnityGameSession.Instance.GameSession.c2s_SendCmdQueryFactionPVPInfo(idFaction);
}
@@ -601,7 +601,7 @@ namespace BrewMonster.Scripts
case CECHPWork.Host_work_ID.WORK_TRACEOBJECT: pWork = new CECHPWorkTrace(this); break;
case CECHPWork.Host_work_ID.WORK_HACKOBJECT: pWork = new CECHPWorkMelee(this); break;
case CECHPWork.Host_work_ID.WORK_SPELLOBJECT: pWork = new CECHPWorkSpell(this); break;
//case CECHPWork.Host_work_ID.WORK_USEITEM: pWork = new CECHPWorkUse(this); break;
case CECHPWork.Host_work_ID.WORK_USEITEM: pWork = new CECHPWorkUse(this); break;
//case CECHPWork.Host_work_ID.WORK_DEAD: pWork = new CECHPWorkDead(this); break;
//case CECHPWork.Host_work_ID.WORK_FOLLOW: pWork = new CECHPWorkFollow(this); break;
case CECHPWork.Host_work_ID.WORK_FLYOFF: pWork = new CECHPWorkFly(this); break;
@@ -0,0 +1,189 @@
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using CSNetwork.GPDataType;
using UnityEngine;
namespace BrewMonster.Scripts
{
/// <summary>
/// Host player work: Use item
/// 主角玩家工作:使用物品
/// </summary>
public class CECHPWorkUse : CECHPWork
{
// Fields / 字段
private int m_idItem; // Item template ID / 物品模板ID
private int m_idTarget; // Target object ID / 目标对象ID
private bool m_bWorkForMonsterSpirit; // Is this work for monster spirit gathering? / 是否为命轮采集工作
private CECCounter m_UseTimeCnt; // Use time counter / 使用时间计数器
/// <summary>
/// Constructor / 构造函数
/// </summary>
public CECHPWorkUse(CECHPWorkMan pWorkMan) : base(Host_work_ID.WORK_USEITEM, pWorkMan)
{
m_dwMask = Work_mask.MASK_USEITEM;
m_dwTransMask = Work_mask.MASK_STAND | Work_mask.MASK_MOVETOPOS;
Reset();
}
/// <summary>
/// Reset work / 重置工作
/// </summary>
public override void Reset()
{
base.Reset();
m_idItem = 0;
m_idTarget = 0;
m_bWorkForMonsterSpirit = false;
if (m_UseTimeCnt == null)
m_UseTimeCnt = new CECCounter();
m_UseTimeCnt.SetPeriod(100);
m_UseTimeCnt.Reset();
}
/// <summary>
/// Copy work data / 复制工作数据
/// </summary>
public override bool CopyData(CECHPWork pWork)
{
if (!base.CopyData(pWork))
return false;
CECHPWorkUse pSrc = pWork as CECHPWorkUse;
if (pSrc == null)
return false;
m_idItem = pSrc.m_idItem;
m_idTarget = pSrc.m_idTarget;
m_bWorkForMonsterSpirit = pSrc.m_bWorkForMonsterSpirit;
m_UseTimeCnt.SetPeriod(pSrc.m_UseTimeCnt.GetPeriod());
m_UseTimeCnt.SetCounter(pSrc.m_UseTimeCnt.GetCounter());
return true;
}
/// <summary>
/// On first tick / 第一帧执行
/// </summary>
protected override void OnFirstTick()
{
if (m_pHost == null)
return;
m_pHost.m_iMoveMode = (int)MoveMode.MOVE_STAND;
EC_IvtrItem pItem = EC_IvtrItem.CreateItem(m_idItem, 0, 1);
if (pItem == null)
return;
if (m_bWorkForMonsterSpirit)
{
// Play gather monster spirit action / 播放采集命轮动作
// TODO: Implement PlayGatherMonsterSpiritAction if needed
// m_pHost.PlayGatherMonsterSpiritAction();
Debug.Log($"[CECHPWorkUse] Playing gather monster spirit action for item {m_idItem}");
}
else
{
// Play start use item action / 播放开始使用物品动作
// TODO: Implement PlayStartUseItemAction if needed
// m_pHost.PlayStartUseItemAction(m_idItem);
Debug.Log($"[CECHPWorkUse] Playing start use item action for item {m_idItem}");
}
}
/// <summary>
/// Work is cancelled / 工作被取消
/// </summary>
public override void Cancel()
{
if (m_idTarget != 0 && m_pHost != null)
{
m_pHost.TurnFaceTo(0);
}
base.Cancel();
// TODO: Implement AP_ActionEvent if needed
// AP_ActionEvent(AP_EVENT_STOPUSEITEM);
Debug.Log("[CECHPWorkUse] Work cancelled - STOPUSEITEM event");
}
/// <summary>
/// Set parameters / 设置参数
/// </summary>
/// <param name="idItem">Item template ID / 物品模板ID</param>
/// <param name="dwUseTime">Use time in milliseconds / 使用时间(毫秒)</param>
/// <param name="idTarget">Target object ID / 目标对象ID</param>
/// <param name="bWorkForMonsterSpirit">Is for monster spirit gathering / 是否为命轮采集</param>
public void SetParams(int idItem, float dwUseTime, int idTarget, bool bWorkForMonsterSpirit)
{
m_idItem = idItem;
m_idTarget = idTarget;
m_bWorkForMonsterSpirit = bWorkForMonsterSpirit;
m_UseTimeCnt.SetPeriod(dwUseTime);
m_UseTimeCnt.Reset();
}
/// <summary>
/// Tick routine / 每帧更新
/// </summary>
public override bool Tick(float dwDeltaTime)
{
base.Tick(dwDeltaTime);
// Update use time counter / 更新使用时间计数器
if (m_UseTimeCnt.IncCounter(dwDeltaTime))
{
m_UseTimeCnt.Reset(true);
m_bFinished = true;
}
// Turn face to target if needed / 如果有目标则面向目标
if (m_idTarget != 0 && m_pHost != null)
{
m_pHost.TurnFaceTo(m_idTarget);
}
return true;
}
/// <summary>
/// Get item template ID / 获取物品模板ID
/// </summary>
public int GetItem()
{
return m_idItem;
}
/// <summary>
/// Get target object ID / 获取目标对象ID
/// </summary>
public int GetTarget()
{
return m_idTarget;
}
/// <summary>
/// Is this work for monster spirit gathering? / 是否为命轮采集工作
/// </summary>
public bool IsWorkForMonsterSpirit()
{
return m_bWorkForMonsterSpirit;
}
/// <summary>
/// Get use time counter / 获取使用时间计数器
/// </summary>
public CECCounter GetUseTimeCnt()
{
return m_UseTimeCnt;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 965c8f617755486429a9f1bb88521065
@@ -134,6 +134,66 @@ namespace BrewMonster.Scripts.Managers
{
RefreshAll();
}
UpdateCooldownOverlays();
}
/// <summary>
/// Update all cooldown overlays
/// 更新所有冷却遮罩
/// </summary>
public void UpdateCooldownOverlays()
{
// Update inventory pack cooldowns
// 更新背包冷却
UpdatePackageCooldowns(inventoryPackButtons, PKG_INVENTORY);
}
/// <summary>
/// Update cooldown overlays for a specific package
/// 更新特定包裹的冷却遮罩
/// </summary>
private void UpdatePackageCooldowns(List<Button> buttons, byte package)
{
if (buttons == null)
{
Debug.LogWarning($"[UpdatePackageCooldowns] Buttons list is null for package {package}");
return;
}
var items = model.GetInventoryData(package);
if (items == null)
{
Debug.LogWarning($"[UpdatePackageCooldowns] Items dictionary is null for package {package}");
return;
}
Debug.Log($"[UpdatePackageCooldowns] Updating package {package} with {buttons.Count} buttons and {items.Count} items");
for (int slot = 0; slot < buttons.Count; slot++)
{
var button = buttons[slot];
if (button == null)
continue;
// Get item at this slot
// 获取此槽位的物品
EC_IvtrItem itemData = null;
bool hasItem = items.TryGetValue(slot, out itemData) && itemData != null;
if (hasItem)
{
// Use InventoryView's method to update cooldown
// 使用 InventoryView 的方法更新冷却
view.UpdateCooldownOverlay(button, itemData);
}
else
{
//// Hide overlay for empty slots
//// 空槽位隐藏遮罩
//view.HideCooldownOverlay(button);
}
}
}
public void RefreshAll()
@@ -335,14 +395,23 @@ namespace BrewMonster.Scripts.Managers
{
if (currentSelectedItem == null)
{
Debug.LogWarning("[InventoryUI] No item selected for equip/unequip operation");
Debug.LogWarning("[InventoryUI] No item selected for operation");
return;
}
if (currentSelectedPackage == PKG_INVENTORY)
{
// Equipping from inventory
EquipItem();
// Check if item is equipment
if (currentSelectedItem.IsEquipment())
{
// Equipping from inventory
EquipItem();
}
else
{
// Use item from inventory
UseItem();
}
}
else if (currentSelectedPackage == PKG_EQUIPMENT)
{
@@ -351,7 +420,56 @@ namespace BrewMonster.Scripts.Managers
}
else
{
Debug.LogWarning($"[InventoryUI] Equip/Unequip not supported for package {currentSelectedPackage}");
Debug.LogWarning($"[InventoryUI] Operation not supported for package {currentSelectedPackage}");
}
}
/// <summary>
/// Use the currently selected item from inventory
/// </summary>
private void UseItem()
{
if (currentSelectedItem == null)
{
Debug.LogWarning("[InventoryUI] No item selected for use");
return;
}
if (currentSelectedPackage != PKG_INVENTORY)
{
Debug.LogWarning("[InventoryUI] Can only use items from inventory package");
return;
}
Debug.Log($"[UseItem] Attempting to use item {currentSelectedItem.m_tid} from slot {currentSelectedSlot}");
// Get host player to call UseItemInPack
var host = CECGameRun.Instance?.GetHostPlayer();
if (host == null)
{
Debug.LogError("[InventoryUI] Cannot get host player");
return;
}
// Call UseItemInPack with current package and slot
bool success = host.UseItemInPack(currentSelectedPackage, currentSelectedSlot, true);
if (success)
{
Debug.Log($"[UseItem] Successfully used item {currentSelectedItem.m_tid} from slot {currentSelectedSlot}");
// Close detail panel after using item
ShowDetailPanel(false);
// Refresh inventory to reflect changes
RefreshAll();
Debug.Log($"[UseItem] Calling UpdateCooldownOverlays after item use");
UpdateCooldownOverlays();
}
else
{
Debug.LogWarning($"[UseItem] Failed to use item {currentSelectedItem.m_tid} from slot {currentSelectedSlot}");
}
}
@@ -598,6 +716,8 @@ namespace BrewMonster.Scripts.Managers
{
private static readonly Dictionary<Image, Sprite> _defaultSprites = new Dictionary<Image, Sprite>();
private static readonly Dictionary<Button, Image> _overlayImages = new Dictionary<Button, Image>();
public void RenderPackage(List<Button> buttons, Dictionary<int, EC_IvtrItem> items, byte package, System.Action<byte, int> onClick, System.Func<int, EC_IvtrItem, string> getDisplayText)
{
if (buttons == null)
@@ -615,34 +735,41 @@ namespace BrewMonster.Scripts.Managers
EC_IvtrItem itemData = null;
bool hasItem = items != null && items.TryGetValue(slot, out itemData);
button.onClick.RemoveAllListeners();
int capturedSlot = slot;
button.onClick.AddListener(() => onClick(package, capturedSlot));
// Optional visual tweaks based on state/count
// Update icon and count
var image = button.GetComponent<Image>();
if (image != null)
{
// Store the default sprite if we haven't seen this image before
// Store default sprite
if (!_defaultSprites.ContainsKey(image))
{
_defaultSprites[image] = image.sprite;
}
// Set icon sprite based on item TemplateId
// Set icon sprite based on item
if (hasItem && itemData != null && itemData.m_iCount > 0)
{
var sprite = EC_IvtrItemUtils.Instance.ResolveItemIconSprite(itemData.m_tid);
image.sprite = sprite;
image.enabled = true;
UpdateItemCountText(button, itemData.m_iCount);
}
else
{
// Restore the default sprite instead of setting to null
// Restore default sprite
image.sprite = _defaultSprites[image];
image.enabled = true;
UpdateItemCountText(button, 0);
}
}
// Setup drag-drop events
var eventTrigger = button.GetComponent<EventTrigger>();
if (eventTrigger == null)
eventTrigger = button.gameObject.AddComponent<EventTrigger>();
@@ -662,6 +789,166 @@ namespace BrewMonster.Scripts.Managers
AddEvent(EventTriggerType.Drop, (data) => ((EC_InventoryUI)button.GetComponentInParent<EC_InventoryUI>()).OnDrop((PointerEventData)data));
}
}
/// <summary>
/// Update cooldown overlay for item
/// 更新物品冷却遮罩
/// </summary>
public void UpdateCooldownOverlay(Button button, EC_IvtrItem itemData)
{
if (button == null || itemData == null)
{
Debug.LogWarning("[UpdateCooldownOverlay] Button or itemData is null");
return;
}
// Find or cache overlay image
// 查找或缓存遮罩图片
Image overlay = null;
if (_overlayImages.TryGetValue(button, out overlay))
{
if (overlay == null)
{
// Cached but destroyed, remove and search again
// 已缓存但被销毁,移除并重新查找
Debug.LogWarning($"[UpdateCooldownOverlay] Cached overlay was destroyed for button {button.name}");
_overlayImages.Remove(button);
}
}
if (overlay == null)
{
// Find image_overlay in button's children
// 在按钮子物体中查找 image_overlay
var overlayTransform = button.transform.Find("image_overlay");
if (overlayTransform != null)
{
overlay = overlayTransform.GetComponent<Image>();
if (overlay != null)
{
_overlayImages[button] = overlay;
}
else
{
Debug.LogWarning($"[UpdateCooldownOverlay] Found transform but no Image component on image_overlay for button {button.name}");
}
}
else
{
Debug.LogWarning($"[UpdateCooldownOverlay] Cannot find image_overlay child in button {button.name}");
}
}
if (overlay == null)
{
return;
}
// Get cooldown info from item
// 从物品获取冷却信息
int maxCooldown = -1;
int currentCooldown = itemData.GetCoolTime(out maxCooldown);
if (currentCooldown > 0)
{
// Show overlay and set fill amount
// 显示遮罩并设置填充量
overlay.gameObject.SetActive(true);
// Calculate fill amount (1 = full cooldown, 0 = ready)
// 计算填充量(1=完全冷却,0=就绪)
if (maxCooldown > 0)
{
float fillAmount = (float)currentCooldown / maxCooldown;
overlay.fillAmount = fillAmount;
}
}
else
{
// Hide overlay when not in cooldown
// 不在冷却时隐藏遮罩
overlay.gameObject.SetActive(false);
}
}
/// <summary>
/// Hide cooldown overlay
/// 隐藏冷却遮罩
/// </summary>
public void HideCooldownOverlay(Button button)
{
if (button == null)
return;
Image overlay = null;
if (_overlayImages.TryGetValue(button, out overlay) && overlay != null)
{
overlay.gameObject.SetActive(false);
}
}
/// <summary>
/// Update or create text component to show item count on the button
/// </summary>
/// <param name="button">The inventory button</param>
/// <param name="count">Item count (0 to hide)</param>
private void UpdateItemCountText(Button button, int count)
{
if (button == null) return;
TMPro.TextMeshProUGUI tmpText = null;
Text legacyText = null;
// Find text component
var textTransform = button.transform.Find("text_quality");
if (textTransform != null)
{
tmpText = textTransform.GetComponent<TMPro.TextMeshProUGUI>();
legacyText = textTransform.GetComponent<Text>();
}
else
{
// Fallback: find any text in children
tmpText = button.GetComponentInChildren<TMPro.TextMeshProUGUI>();
if (tmpText == null)
{
legacyText = button.GetComponentInChildren<Text>();
}
}
// Update text
if (count > 1)
{
string countText = count.ToString();
if (tmpText != null)
{
tmpText.text = countText;
tmpText.gameObject.SetActive(true);
}
else if (legacyText != null)
{
legacyText.text = countText;
legacyText.gameObject.SetActive(true);
}
}
else
{
// Hide when count <= 1
if (tmpText != null)
{
tmpText.text = "";
tmpText.gameObject.SetActive(false);
}
else if (legacyText != null)
{
legacyText.text = "";
legacyText.gameObject.SetActive(false);
}
}
}
}
// === Detail Panel Helpers ===
@@ -165,10 +165,11 @@ namespace PerfectWorld.Scripts.Managers
}
// Get item cool time
public int GetCoolTime(ref int piMax)
public override int GetCoolTime(out int piMax)
{
piMax = 0;
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
return pHost != null ? pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_AUTOHP, ref piMax) : 0;
return pHost != null ? pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_AUTOHP, out piMax) : 0;
}
}
}
@@ -168,7 +168,7 @@ namespace PerfectWorld.Scripts.Managers
public int GetCoolTime(ref int piMax)
{
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
return pHost != null ? pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_AUTOMP, ref piMax) : 0;
return pHost != null ? pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_AUTOMP, out piMax) : 0;
}
}
}
@@ -1,8 +1,11 @@
using BrewMonster;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
{
public class EC_IvtrDoubleExp : EC_IvtrItem
{
private DOUBLE_EXP_ESSENCE m_pDBEssence;
/// <summary>
/// Not create logic yet (add summary later)
/// </summary>
@@ -15,6 +18,11 @@ namespace PerfectWorld.Scripts.Managers
public EC_IvtrDoubleExp(EC_IvtrDoubleExp other) : base(other)
{
}
public DOUBLE_EXP_ESSENCE GetDBEssence()
{
return m_pDBEssence;
}
}
}
@@ -1138,9 +1138,9 @@ namespace BrewMonster.Scripts.Managers
}
/// <summary>Get item cool time in milliseconds (0 by default).</summary>
public virtual int GetCoolTime(out int? piMax)
public virtual int GetCoolTime(out int piMax)
{
piMax = null;
piMax = -1;
return 0;
}
@@ -65,8 +65,9 @@ namespace PerfectWorld.Scripts.Managers
{
return m_pDBEssence.Name;
}
public int GetCoolTime(ref int piMax/* NULL */)
public override int GetCoolTime(out int piMax/* NULL */)
{
piMax = 1;
CECHostPlayer pHost = CECGameRun.Instance.GetHostPlayer();
if (!pHost)
return 0;
@@ -75,11 +76,11 @@ namespace PerfectWorld.Scripts.Managers
switch (m_pDBMajorType.id)
{
case 1810: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_REJUVENATION_POTION, ref piMax); break;
case 1794: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_HP_POTION, ref piMax); break;
case 1802: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_MP_POTION, ref piMax); break;
case 1810: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_REJUVENATION_POTION, out piMax); break;
case 1794: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_HP_POTION, out piMax); break;
case 1802: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_MP_POTION, out piMax); break;
case 1815:
case 2038: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_ANTIDOTE_POTION, ref piMax); break;
case 2038: iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_ANTIDOTE_POTION, out piMax); break;
}
return iTime;
@@ -80,7 +80,7 @@ namespace PerfectWorld.Scripts.Managers
if (!pHost)
return 0;
int iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_FEED_PET, ref piMax);
int iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_FEED_PET, out piMax);
return iTime;
}
@@ -1,8 +1,14 @@
using BrewMonster;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
{
public class EC_IvtrTargetItem : EC_IvtrItem
{
private CECSkill m_pTargetSkill;
private TARGET_ITEM_ESSENCE m_pDBEssence;
private bool m_bEssenceLoaded = false; // Flag to track if essence is loaded
/// <summary>
/// Not create logic yet (add summary later)
/// </summary>
@@ -15,6 +21,33 @@ namespace PerfectWorld.Scripts.Managers
public EC_IvtrTargetItem(EC_IvtrTargetItem other) : base(other)
{
}
public TARGET_ITEM_ESSENCE GetDBEssence()
{
if (!m_bEmbeddable)
{
DATA_TYPE DataType = DATA_TYPE.DT_INVALID;
var pDataBuf = ElementDataManProvider.GetElementDataMan()
.get_data_ptr((uint)m_tid, ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
if (DataType == DATA_TYPE.DT_TARGET_ITEM_ESSENCE && pDataBuf != null)
{
m_pDBEssence = (TARGET_ITEM_ESSENCE)pDataBuf;
m_bEssenceLoaded = true;
}
}
return m_pDBEssence;
}
public bool IsEssenceLoaded()
{
return m_bEssenceLoaded;
}
public CECSkill GetTargetSkill()
{
return m_pTargetSkill;
}
}
}
@@ -1,3 +1,4 @@
using BrewMonster;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
{
@@ -15,6 +16,13 @@ namespace PerfectWorld.Scripts.Managers
public EC_IvtrTossMat(EC_IvtrTossMat other) : base(other)
{
}
protected TOSSMATTER_ESSENCE m_pDBEssence;
public TOSSMATTER_ESSENCE GetDBEssence()
{
return m_pDBEssence;
}
}
}
@@ -55,7 +55,7 @@ namespace PerfectWorld.Scripts.Managers
public int GetCoolTime(ref int piMax)
{
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
return pHost ? pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_TOWNSCROLL, ref piMax) : 0;
return pHost ? pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_TOWNSCROLL, out piMax) : 0;
}
protected override string GetNormalDesc(bool bRepair)
@@ -56,7 +56,7 @@ namespace PerfectWorld.Scripts.Managers
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
if (!pHost)
return 0;
int iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_TOWNSCROLL, ref piMax);
int iTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_TOWNSCROLL, out piMax);
return iTime;
}
@@ -58,6 +58,7 @@ namespace BrewMonster
protected ROLEBASICPROP m_BasicProps;
public int m_iMoveEnv = Move_environment.MOVEENV_GROUND; // Move environment
public bool m_bWalkRun = true;
public bool m_bInSanctuary = true;
public A3DAABB m_aabbServer = new A3DAABB(); // Óë·þÎñÆ÷±£³ÖÒ»ÖµÄaabb£¬ ²»ÊÜËõ·ÅÓ°Ïì
public A3DAABB m_aabb = new A3DAABB(); // Player's aabb£¬ÓÃÓÚÏÔʾµÄaabb£¬ÊÜËõ·ÅÓ°Ïì
public int m_iProfession; // Profession
@@ -261,6 +262,11 @@ namespace BrewMonster
return (m_dwStates & PlayerNPCState.GP_STATE_INVISIBLE) != 0;
}
public bool IsInSanctuary()
{
return m_bInSanctuary;
}
public bool IsValidAction(int iIndex)
{
return (iIndex >= 0 && iIndex < (int)PLAYER_ACTION_TYPE.ACT_MAX) ? true : false;
@@ -244,8 +244,6 @@ public class CECNPCServer : CECNPC
if (idTask <= 0)
continue;
BMLogger.Log($"[UpdateCurTaskIcon] Check OUT task {idTask}, CanShow={pTask.CanShowTask(idTask)}, CanDeliver={pTask.CanDeliverTask(idTask)}");
if (!pTask.CanShowTask(idTask))
continue;
@@ -258,7 +256,6 @@ public class CECNPCServer : CECNPC
if (pTaskTemp.IsKeyTask())
{
m_TaskIcon = IconTaskType.QI_OUT_K;
BMLogger.Log($"[UpdateCurTaskIcon] Set icon QI_OUT_K for task {idTask}");
UpdateTaskIconUI();
return;
}
@@ -2,6 +2,7 @@ using BrewMonster;
using CSNetwork.GPDataType;
using CSNetwork.S2CCommand;
using System;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
@@ -825,6 +826,25 @@ namespace CSNetwork.C2SCommand
return SerializeCommand(CommandID.USE_ITEM, pCmd);
}
public static Octets CreateUseItemWithTarget(byte byPackage, byte bySlot, int tid, byte byPVPMask)
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
// Write command header
writer.Write((ushort)CommandID.USE_ITEM_T);
// Write cmd_use_item structure
writer.Write(byPackage); // where
writer.Write((byte)1); // byCount (always 1 for target items)
writer.Write((ushort)bySlot); // index
writer.Write(tid); // item_id
writer.Write(byPVPMask); // pvp_mask
return new Octets(stream.ToArray());
}
}
public static Octets CreateGivePresentCmd(int roleid, int mail_id, int goods_id, int goods_index, int goods_slot)
{
cmd_player_give_present pCmd = new cmd_player_give_present();
@@ -872,6 +872,15 @@ namespace CSNetwork.GPDataType
public int line;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct cmd_host_use_item
{
public byte byPackage;
public byte bySlot;
public int item_id;
public ushort use_count;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct cmd_matter_pickup
{
@@ -474,6 +474,13 @@ namespace CSNetwork
SendProtocol(gamedatasendRequest);
}
public void c2s_SendCmdUseItemWithTarget(byte byPackage, byte bySlot, int tid, byte byPVPMask)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateUseItemWithTarget(byPackage, bySlot, tid, byPVPMask);
SendProtocol(gamedatasend);
}
public void RequestOwnItemInfoAsync(
byte byPackage,
byte bySlot,
@@ -957,6 +964,9 @@ namespace CSNetwork
case CommandID.SET_COOLDOWN:
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SETCOOLTIME, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
break;
case CommandID.HOST_USE_ITEM:
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_USEITEM, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
break;
case CommandID.COMBO_SKILL_PREPARE:
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_COMBO_SKILL_PREPARE, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, dwDataSize);
break;
@@ -235,6 +235,10 @@ namespace BrewMonster.Network
{
Instance._gameSession.RequestReviveByPlayer();
}
public static void c2s_SendCmdUseItemWithTarget(byte byPackage, byte bySlot, int tid, byte byPVPMask)
{
Instance._gameSession.c2s_SendCmdUseItemWithTarget(byPackage, bySlot, tid, byPVPMask);
}
public void RequestMallShopping(uint count, int good_id, int good_index, int good_pos)
{
@@ -787,6 +787,17 @@ namespace BrewMonster
return new CECShortcut();
}
public virtual bool Execute() { return true; }
public virtual int GetCoolTime(ref int piMax)
{
piMax = 0;
return 0;
}
public virtual string GetIconFile()
{
return "";
}
}
public class CECSCCommand : CECShortcut
@@ -15,6 +15,8 @@ namespace BrewMonster.UI
protected AUIManager m_pAUIManager = null;
string m_szName;
private bool m_bUpdateRenderTarget = false;
public virtual void Show(bool value)
{
gameObject.SetActive(value);
@@ -140,5 +142,20 @@ namespace BrewMonster.UI
/// <summary>Override in dialogs that support attribute-point reset (e.g. DlgCharacter). No-op by default.</summary>
public virtual void ResetPoints() { }
public virtual void UpdateRenderTarget()
{
m_bUpdateRenderTarget = true;
}
public bool NeedRenderTargetUpdate()
{
return m_bUpdateRenderTarget;
}
public void ResetRenderTargetFlag()
{
m_bUpdateRenderTarget = false;
}
}
}
@@ -1,4 +1,5 @@
using System;
using BrewMonster.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -20,6 +21,12 @@ namespace BrewMonster.Assets.PerfectWorld.Scripts.UI.GamePlay
[SerializeField] int cooldownTime;
[SerializeField] AUIClockIcon m_ClockCounter;
private Color m_color = Color.white;
private bool m_bUpdateRenderTarget;
private bool m_bForceDynamicRender;
private AUIDialog m_pParent;
private void Awake()
{
if (skillbutton == null)
@@ -27,6 +34,7 @@ namespace BrewMonster.Assets.PerfectWorld.Scripts.UI.GamePlay
Debug.LogError("Skill Button is not assigned in AUIImagePicture");
}
skillbutton.onClick.AddListener(Execute);
m_pParent = GetComponentInParent<AUIDialog>();
}
public void SetDataPtr(CECShortcut pvData, string strName)
{
@@ -69,6 +77,24 @@ namespace BrewMonster.Assets.PerfectWorld.Scripts.UI.GamePlay
skillbutton.interactable = true;
}
public AUIClockIcon GetClockIcon() => m_ClockCounter;
public void SetColor(Color color)
{
if (m_color != color)
UpdateRenderTargert();
m_color = color;
}
private void UpdateRenderTargert()
{
if (!NeedDynamicRender())
m_pParent.UpdateRenderTarget();
}
private bool NeedDynamicRender()
{
return m_bUpdateRenderTarget || m_bForceDynamicRender;
}
}
public struct OpenSkillUIEvent
{
@@ -1,8 +1,10 @@
using BrewMonster.Assets.PerfectWorld.Scripts.UI.GamePlay;
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Skills;
using BrewMonster.UI;
using CSNetwork.GPDataType;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -197,6 +199,125 @@ namespace BrewMonster
pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 128));
}
}*/
else if(pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_ITEM)
{
iIconFile = (int)EC_GAMEUI_ICONS.ICONS_INVENTORY;
pCell.SetColor(new Color(1f, 1f, 1f));
CECSCItem pSCItem = (CECSCItem)pSC;
EC_Inventory pIvtr = pHost.GetPack(pSCItem.GetInventory());
EC_IvtrItem pItem = pIvtr?.GetItem(pSCItem.GetIvtrSlot());
if (pItem != null)
{
int maxNullable = -1;
int coolTime = pItem.GetCoolTime(out maxNullable);
nMax = maxNullable > 0 ? maxNullable: 0;
if (coolTime > 0)
{
pClock.SetProgressRange(0, nMax);
pClock.SetProgressPos(nMax - coolTime);
pClock.SetColor(new Color32(0, 0, 0, 128));
}
}
//if (pSCItem.GetInventory == InventoryConst.IVTRTYPE_EQUIPPACK)
//{
// pCell.SetColor(new Color(128, 128, 255, 128));
//}
if (pItem != null)
{
string itemIcon = pItem.GetIconFile();
GetGameUIMan().SetCover(pCell, itemIcon, EC_GAMEUI_ICONS.ICONS_INVENTORY);
}
}
//else if(pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_PET)
//{
// // Pet shortcut handling
// CECSCPet pSCPet = (CECSCPet)pSC;
// EC_PetCorral pPetCorral = pHost.GetPetCorral();
// CECPetData pPet = pPetCorral?.GetPetData(pSCPet.GetPetIndex());
// iIconFile = (int)EC_GAMEUI_ICONS.ICONS_INVENTORY;
// //pCell.SetColor(new Color(1f, 1f, 1f)); // RGB(255, 255, 255)
// if (pPet != null)
// {
// // Dead combat pet - grayscale
// if ((pPet.GetClass() == (int)PetClass.GP_PET_CLASS_COMBAT ||
// pPet.GetClass() == (int)PetClass.GP_PET_CLASS_EVOLUTION) &&
// pPet.GetHPFactor() == 0.0f)
// {
// //pCell.SetColor(new Color32(128, 128, 128, 255));
// }
// // Current active pet - yellow highlight
// else if (pSCPet.IsActivePet())
// {
// //pCell.SetColor(new Color32(255, 255, 0, 255));
// }
// }
// // Set pet icon
// if (pPet != null)
// {
// slotIndex++;
// string petIcon = pSCPet.GetIconFile();
// GetGameUIMan().SetCover(pCell, petIcon, EC_GAMEUI_ICONS.ICONS_INVENTORY);
// }
//}
else if(pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_AUTOFASHION)
{
iIconFile = (int)EC_GAMEUI_ICONS.ICONS_SUITE;
int fashionCoolTime = pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_EQUIP_FASHION_ITEM, out int fashionCoolTimeMax);
pCell.SetColor(new Color(1f, 1f, 1f));
if (fashionCoolTimeMax > 0)
{
pClock.SetProgressRange(0, fashionCoolTimeMax);
pClock.SetProgressPos(fashionCoolTimeMax - fashionCoolTime);
pClock.SetColor(new Color32(0, 0, 0, 175));
}
}
else
{
iIconFile = (int)EC_GAMEUI_ICONS.ICONS_ACTION;
if (pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_COMMAND)
{
CECSCCommand pCommandSC = (CECSCCommand)pSC;
if (pHost.IsInvisible())
{
if (pCommandSC.GetCommandID() == (int)CECSCCommand.CommandID.CMD_STARTTRADE ||
pCommandSC.GetCommandID() == (int)CECSCCommand.CommandID.CMD_SELLBOOTH ||
pCommandSC.GetCommandID() == (int)CECSCCommand.CommandID.CMD_BINDBUDDY)
{
pCell.SetColor(new Color(128, 128, 128, 255));
}
else
{
pCell.SetColor(new Color(1f, 1f, 1f));
}
}
else
{
pCell.SetColor(new Color(1f, 1f, 1f));
}
}
nMax = 0;
int cmdCoolTime = pSC.GetCoolTime(ref nMax);
if (cmdCoolTime > 0)
{
pClock.SetProgressRange(0, nMax);
pClock.SetProgressPos(nMax - cmdCoolTime);
pClock.SetColor(new Color32(0, 0, 0, 128));
}
string cmdIcon = pSC.GetIconFile();
GetGameUIMan().SetCover(pCell, cmdIcon, EC_GAMEUI_ICONS.ICONS_ACTION);
}
if (pSC != null)
{
pCell.SetDataPtr(pSC, "ptr_CECShortcut");
@@ -11,6 +11,8 @@ namespace BrewMonster
[SerializeField] private int m_iMax;
[SerializeField] private int m_iPos;
private Color m_dwCol;
public Image GetClockIcon() => m_ClockIcon;
public void SetProgressPos(int progress)
{
@@ -36,5 +38,9 @@ namespace BrewMonster
m_ClockIcon.fillAmount = progress;
}
public void SetColor(Color dwCol)
{
m_dwCol = dwCol;
}
}
}
@@ -0,0 +1,242 @@
using BrewMonster.Network;
using BrewMonster.Scripts.Skills;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.VisualScripting;
using static BrewMonster.SkillArrayWrapper;
using UnityEngine;
using BrewMonster.Scripts.Managers;
using UnityEditorInternal.Profiling.Memory.Experimental;
using BrewMonster.Scripts;
namespace BrewMonster
{
// Item shortcut class - represents a shortcut to an inventory item
public class CECSCItem : CECShortcut
{
private int m_iIvtr;
private int m_iSlot;
private int m_tidItem;
private string m_strIconFile;
private bool m_bAutoFind;
// Constructor
public CECSCItem() : base()
{
m_iSCType = (int)ShortcutType.SCT_ITEM;
m_iIvtr = 0;
m_iSlot = 0;
m_tidItem = 0;
m_strIconFile = "";
m_bAutoFind = false;
}
// Copy constructor
public CECSCItem(CECSCItem src) : base()
{
m_iSCType = (int)ShortcutType.SCT_ITEM;
m_iIvtr = src.m_iIvtr;
m_iSlot = src.m_iSlot;
m_tidItem = src.m_tidItem;
m_strIconFile = src.m_strIconFile;
m_bAutoFind = src.m_bAutoFind;
}
// Initialize object
public bool Init(int iIvtr, int iSlot, EC_IvtrItem pItem)
{
m_iIvtr = iIvtr;
m_iSlot = iSlot;
if (pItem != null)
{
m_tidItem = pItem.GetTemplateID();
m_strIconFile = pItem.GetIconFile();
}
else
{
m_tidItem = 0;
m_strIconFile = "";
}
return true;
}
// Clone this shortcut
public override CECShortcut Clone()
{
return new CECSCItem(this);
}
// Execute this shortcut - use the item
public override bool Execute()
{
CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
if(pHost == null)
return false;
EC_IvtrItem pItem = GetItem();
if (pItem == null)
{
if (m_bAutoFind)
{
if(!AutoFindItem())
return false;
pItem = GetItem();
if(pItem == null)
return false;
}
else
{
return false;
}
}
return pHost.UseItemInPack(m_iIvtr, m_iSlot);
}
public virtual string GetIconFile()
{
return m_strIconFile;
}
public virtual string GetDesc()
{
EC_IvtrItem pItem = GetItem();
if (pItem != null)
{
return pItem.GetDesc();
}
return "";
}
public virtual int GetCoolTime(ref int piMax)
{
EC_IvtrItem pItem = GetItem();
if (pItem != null)
{
int maxNullable = -1;
int result = pItem.GetCoolTime(out maxNullable);
piMax = maxNullable >0 ? maxNullable: 0;
return result;
}
piMax = 0;
return 0;
}
public int GetInventory()
{
return m_iIvtr;
}
public int GetIvtrSlot()
{
return m_iSlot;
}
public int GetItemTID()
{
return m_tidItem;
}
public void MoveItem(int iIvtr, int iSlot)
{
m_iIvtr = iIvtr;
m_iSlot = iSlot;
UpdateItemData();
}
public bool GetAutoFindFlag()
{
return m_bAutoFind;
}
public void SetAutoFindFlag(bool bAutoFind)
{
m_bAutoFind = bAutoFind;
}
// Update item associated data after m_iIvtr or m_iSlot changed
private void UpdateItemData()
{
EC_IvtrItem pItem = GetItem();
if (pItem != null)
{
m_tidItem = pItem.GetTemplateID();
m_strIconFile = pItem.GetIconFile();
}
else
{
m_tidItem = 0;
m_strIconFile = "";
}
}
// Auto find item in all inventory slots by template ID
private bool AutoFindItem()
{
if(m_tidItem == 0)
return false;
CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
if(pHost == null)
return false;
EC_Inventory pPack = pHost.GetPack(EC_Inventory.Inventory_type.IVTRTYPE_PACK);
if (pPack != null)
{
int iSlot = pPack.FindItem(m_tidItem);
if (iSlot >= 0)
{
m_iIvtr = EC_Inventory.Inventory_type.IVTRTYPE_PACK;
m_iSlot = iSlot;
UpdateItemData();
return true;
}
}
EC_Inventory pEquipPack = pHost.GetPack(EC_Inventory.Inventory_type.IVTRTYPE_EQUIPPACK);
if (pEquipPack != null)
{
int iSlot = pPack.FindItem(m_tidItem);
if (iSlot >= 0)
{
m_iIvtr = InventoryConst.IVTRTYPE_EQUIPPACK;
m_iSlot = iSlot;
UpdateItemData();
return true;
}
}
EC_Inventory pTaskPack = pHost.GetPack(EC_Inventory.Inventory_type.IVTRTYPE_TASKPACK);
if (pTaskPack != null)
{
int iSlot = pPack.FindItem(m_tidItem);
if (iSlot >= 0)
{
m_iIvtr = InventoryConst.IVTRTYPE_TASKPACK;
m_iSlot = iSlot;
UpdateItemData();
return true;
}
}
return false;
}
private EC_IvtrItem GetItem()
{
CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
if(pHost == null)
return null;
EC_Inventory pIvtr = pHost.GetPack(m_iIvtr);
if (pIvtr == null)
return null;
return pIvtr.GetItem(m_iSlot);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 05cde8ef04e79fd449fdb73d3f3fdc0f
@@ -0,0 +1,197 @@
using BrewMonster.Assets.PerfectWorld.Scripts.Players;
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using ModelRenderer.Scripts.Common;
using ModelRenderer.Scripts.GameData;
using UnityEngine;
namespace BrewMonster
{
/// <summary>
/// Pet shortcut for quick summoning/recalling pets
/// </summary>
public class CECSCPet : CECShortcut
{
/*#region Fields
private int m_iPetIndex = -1; // Pet index in pet corral
private PET_ESSENCE m_pPetEssence; // Pet essence data
private bool m_bHasEssence = false; // Whether the pet essence has been loaded
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public CECSCPet()
{
m_iSCType = (int)ShortcutType.SCT_PET;
m_iPetIndex = -1;
m_bHasEssence = false;
}
/// <summary>
/// Copy constructor
/// </summary>
/// <param name="src">Source pet shortcut to copy from</param>
public CECSCPet(CECSCPet src)
{
m_iSCType = src.m_iSCType;
m_iPetIndex = src.m_iPetIndex;
m_pPetEssence = src.m_pPetEssence;
m_bHasEssence = src.m_bHasEssence;
}
#endregion
#region Initialization
/// <summary>
/// Initialize the pet shortcut with a pet index
/// </summary>
/// <param name="iPetIndex">Index of the pet in the pet corral</param>
/// <returns>True if initialization succeeded</returns>
public bool Init(int iPetIndex)
{
CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
if (pHost == null)
return false;
EC_PetCorral pPetCorral = pHost.GetPetCorral();
if (pPetCorral == null)
return false;
//CECPetData pPet = pPetCorral.GetPetData(iPetIndex);
if (pPet == null)
return false;
elementdataman pDB = ElementDataManProvider.GetElementDataMan();
if (pDB == null)
return false;
DATA_TYPE dataType = DATA_TYPE.DT_INVALID;
object essenceObj = pDB.get_data_ptr((uint)pPet.GetTemplateID(), ID_SPACE.ID_SPACE_ESSENCE, ref dataType);
if (essenceObj == null || !(essenceObj is PET_ESSENCE))
return false;
m_pPetEssence = (PET_ESSENCE)essenceObj;
m_bHasEssence = true;
m_iPetIndex = iPetIndex;
return true;
}
#endregion
#region CECShortcut Overrides
/// <summary>
/// Clone this pet shortcut
/// </summary>
/// <returns>A new instance with the same data</returns>
public override CECShortcut Clone()
{
return new CECSCPet(this);
}
/// <summary>
/// Execute the pet shortcut - summon or recall the pet
/// </summary>
/// <returns>True if execution succeeded</returns>
public override bool Execute()
{
if (m_iPetIndex < 0)
return false;
CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
if (pHost == null)
return false;
EC_PetCorral pPetCorral = pHost.GetPetCorral();
if (pPetCorral == null)
return false;
//if (pPetCorral.GetActivePetIndex() == m_iPetIndex)
//{
// // If this pet is the active one, recall it
// pHost.RecallPet();
//}
else
{
// Check action switcher for fly-to-ride transition
CECActionSwitcherBase pSwitcher = pHost.GetActionSwitcher();
//if (pSwitcher != null && pSwitcher.OnFlyToRideAction(m_iPetIndex))
//{
// return true;
//}
// Summon this pet
//pHost.SummonPet(m_iPetIndex);
}
return true;
}
/// <summary>
/// Get the icon file path for this pet
/// </summary>
/// <returns>Icon file path</returns>
//public override string GetIconFile()
//{
// return m_pPetEssence?.file_icon ?? string.Empty;
//}
/// <summary>
/// Get the description text for this pet
/// </summary>
/// <returns>Pet description</returns>
//public override string GetDesc()
//{
// // TODO: Implement pet description retrieval
//}
#endregion
#region Public Methods
/// <summary>
/// Check if this pet is currently active
/// </summary>
/// <returns>True if this pet is the active pet</returns>
//public bool IsActivePet()
//{
// EC_PetCorral pPetCorral = EC_Game.GetGameRun()?.GetHostPlayer()?.GetPetCorral();
// if (pPetCorral == null)
// return false;
// return pPetCorral.GetActivePetIndex() == m_iPetIndex;
//}
#endregion
#region Properties
/// <summary>
/// Get the pet index in pet corral
/// </summary>
/// <returns>Pet index</returns>
public int GetPetIndex()
{
return m_iPetIndex;
}
/// <summary>
/// Get the pet essence data
/// </summary>
/// <returns>Pet essence</returns>
public PET_ESSENCE GetPetEssence()
{
return m_pPetEssence;
}
#endregion*/
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0c1e98ce7d055204587eff3f6438ddc3
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,173 @@
fileFormatVersion: 2
guid: b404da7f8f4b96f459d1c8caa65f7cf8
TextureImporter:
internalIDToNameTable:
- first:
213: 7482667652216324306
second: Square
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 256
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: 0
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 1
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: Square
rect:
serializedVersion: 2
x: 0
y: 0
width: 256
height: 256
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
customData:
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 2d009a6b596c7d760800000000000000
internalID: 7482667652216324306
vertices: []
indices:
edges: []
weights: []
outline: []
customData:
physicsShape:
- - {x: -128, y: 128}
- {x: -128, y: -128}
- {x: 128, y: -128}
- {x: 128, y: 128}
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable:
Square: 7482667652216324306
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
+178
View File
@@ -1,6 +1,7 @@
using BrewMonster;
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.World;
using BrewMonster.UI;
using CSNetwork;
@@ -46,6 +47,8 @@ public partial class CECGameRun
static RoleInfo l_SelRoleInfo; // Selected character's role info.
private int m_iDExpEndTime = 0;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void AfterSceneLoad()
@@ -525,4 +528,179 @@ public partial class CECGameRun
}
return szRet;
}
/// <summary>
/// Add a fixed message to chat system with optional formatting parameters
/// 添加固定消息到聊天系统,支持可选的格式化参数
/// </summary>
/// <param name="iMsg">Fixed message ID / 固定消息ID</param>
/// <param name="args">Optional formatting arguments / 可选的格式化参数</param>
public void AddFixedMessage(int iMsg, params object[] args)
{
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
if (pStrTab == null)
{
Debug.LogWarning("[AddFixedMessage] Failed to get fixed message table");
return;
}
string szFixMsg = pStrTab.GetWideString(iMsg);
if (string.IsNullOrEmpty(szFixMsg))
{
Debug.LogWarning($"[AddFixedMessage] Fixed message {iMsg} not found");
return;
}
// Format the message with provided arguments
string szFormattedMsg;
try
{
if (args != null && args.Length > 0)
{
szFormattedMsg = string.Format(szFixMsg, args);
}
else
{
szFormattedMsg = szFixMsg;
}
}
catch (System.FormatException ex)
{
Debug.LogError($"[AddFixedMessage] Format error for message {iMsg}: {ex.Message}");
szFormattedMsg = szFixMsg; // Use unformatted message as fallback
}
// Try to add to in-game UI chat
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan();
if (pGameUI != null)
{
//pGameUI.AddChatMessage(szFormattedMsg, (int)GP_CHAT.GP_CHAT_SYSTEM);
}
else
{
// Fallback to debug output if UI is not available
Debug.Log($"[System] {szFormattedMsg}");
}
}
/// <summary>
/// Add a fixed message to specific chat channel with optional formatting
/// 添加固定消息到指定聊天频道,支持可选的格式化
/// </summary>
/// <param name="iMsg">Fixed message ID / 固定消息ID</param>
/// <param name="cChannel">Chat channel ID / 聊天频道ID</param>
/// <param name="args">Optional formatting arguments / 可选的格式化参数</param>
public void AddFixedChannelMsg(int iMsg, int cChannel, params object[] args)
{
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
if (pStrTab == null)
{
Debug.LogWarning("[AddFixedChannelMsg] Failed to get fixed message table");
return;
}
string szFixMsg = pStrTab.GetWideString(iMsg);
if (string.IsNullOrEmpty(szFixMsg))
{
Debug.LogWarning($"[AddFixedChannelMsg] Fixed message {iMsg} not found");
return;
}
// Format the message with provided arguments
string szFormattedMsg;
try
{
if (args != null && args.Length > 0)
{
szFormattedMsg = string.Format(szFixMsg, args);
}
else
{
szFormattedMsg = szFixMsg;
}
}
catch (System.FormatException ex)
{
Debug.LogError($"[AddFixedChannelMsg] Format error for message {iMsg}: {ex.Message}");
szFormattedMsg = szFixMsg; // Use unformatted message as fallback
}
// Try to add to in-game UI chat with specific channel
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan();
if (pGameUI != null)
{
//pGameUI.AddChatMessage(szFormattedMsg, cChannel);
}
else
{
// Fallback to debug output if UI is not available
Debug.Log($"[Channel {cChannel}] {szFormattedMsg}");
}
}
/// <summary>
/// Add a chat message with full parameters (matching C++ signature)
/// 添加聊天消息(完整参数版本,匹配C++签名)
/// </summary>
/// <param name="pszMsg">Message text / 消息文本</param>
/// <param name="cChannel">Chat channel / 聊天频道</param>
/// <param name="idPlayer">Player ID (default -1) / 玩家ID</param>
/// <param name="szName">Player name (optional) / 玩家名称</param>
/// <param name="byFlag">Message flag (default 0) / 消息标志</param>
/// <param name="cEmotion">Emotion ID (default 0) / 表情ID</param>
/// <param name="pItem">Related item (optional) / 相关物品</param>
/// <param name="pszMsgOrigion">Original message (optional) / 原始消息</param>
public void AddChatMessage(string pszMsg, int cChannel, int idPlayer = -1,
string szName = null, byte byFlag = 0, int cEmotion = 0,
EC_IvtrItem pItem = null, string pszMsgOrigion = null)
{
if (string.IsNullOrEmpty(pszMsg))
return;
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan();
if (pGameUI != null)
{
// Call UI manager's AddChatMessage with full parameters
//pGameUI.AddChatMessage(pszMsg, cChannel, idPlayer, szName, byFlag, cEmotion, pItem, pszMsgOrigion);
}
else
{
// Fallback to debug output if UI is not available
Debug.Log($"[Channel {cChannel}] {pszMsg}");
// Note: In C++ original, pItem is deleted here if UI is not available
// In C#, we don't need explicit deletion due to garbage collection
}
}
/// <summary>
/// Get remaining double experience time in seconds
/// 获取剩余双倍经验时间(秒)
/// </summary>
public int GetRemainDblExpTime()
{
int iRemainTime = m_iDExpEndTime - GetServerAbsTime();
if (iRemainTime < 0) iRemainTime = 0;
return iRemainTime;
}
/// <summary>
/// Get server absolute time
/// 获取服务器绝对时间
/// </summary>
public int GetServerAbsTime()
{
// TODO: Implement server time synchronization
// This should return the synchronized server timestamp
return (int)(System.DateTime.UtcNow.Subtract(new System.DateTime(1970, 1, 1))).TotalSeconds;
}
/// <summary>
/// Set double experience end time
/// 设置双倍经验结束时间
/// </summary>
public void SetDExpEndTime(int endTime)
{
m_iDExpEndTime = endTime;
}
}
+543 -5
View File
@@ -50,6 +50,7 @@ namespace BrewMonster
public bool m_bPrepareFight = false; // true, prepare to fight
private int m_iJumpCount = 0;
private bool m_bJumpInWater = false;
private int m_iMoveEnv;
public A3DVECTOR3 m_vVelocity; // Velocity
@@ -562,6 +563,8 @@ namespace BrewMonster
break;
case int value when value == EC_MsgDef.MSG_HST_SELTARGET:
OnMsgHstSelTarget(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_USEITEM:OnMsgHstUseItem(Msg);
break;
case int value when value == EC_MsgDef.MSG_HST_ATKRESULT: OnMsgHstAttackResult(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_ATTACKED: OnMsgHstAttacked(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_HURTRESULT: OnMsgHstHurtResult(Msg); break;
@@ -675,8 +678,9 @@ namespace BrewMonster
COOLTIME ct = m_aCoolTimes[pCmd.cooldown_index];
ct.iCurTime = pCmd.cooldown_time;
ct.iMaxTime = pCmd.cooldown_time;
Debug.Log("New Max cool time forIvtrMedicine: it be: " + pCmd.cooldown_time);
Math.Min(ct.iCurTime, ct.iMaxTime);
m_aCoolTimes[pCmd.cooldown_index] = ct;
if (pCmd.cooldown_index == (int)CoolTimeIndex.GP_CT_CAST_ELF_SKILL)
{
int i;
@@ -704,7 +708,7 @@ namespace BrewMonster
CECSkill pSkill = GetPositiveSkillByIndex(i);
int fakeRef = 0;
if (pSkill != null && (pSkill.GetCommonCoolDown() & mask) != 0)
pSkill.StartCooling(GetCoolTime(pCmd.cooldown_index, ref fakeRef), GetCoolTime(pCmd.cooldown_index, ref fakeRef));
pSkill.StartCooling(GetCoolTime(pCmd.cooldown_index, out fakeRef), GetCoolTime(pCmd.cooldown_index, out fakeRef));
}
/*const std::map<unsigned int, CECSkill*>&inherentSkillMap = CECComboSkillState::Instance().GetInherentSkillMap();
std::map < unsigned int, CECSkill*>::const_iterator it;
@@ -3412,6 +3416,12 @@ namespace BrewMonster
return m_iJumpCount > 0;
}
public bool IsFalling()
{
return m_iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND
&& m_GndInfo.bOnGround == false;
}
public bool IsPlayingAction(int iAction)
{
if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK) //&& _playerStateMachine.State is PlayerMoveState
@@ -6089,13 +6099,13 @@ namespace BrewMonster
}
// Get cool time
public int GetCoolTime(int iIndex, ref int piMax /* NULL */)
public virtual int GetCoolTime(int iIndex, out int piMax /* NULL */)
{
piMax = 1;
if (iIndex >= 0 && iIndex < (int)CoolTimeIndex.GP_CT_MAX)
{
if (piMax > 0)
piMax = m_aCoolTimes[iIndex].iMaxTime;
return m_aCoolTimes[iIndex].iCurTime;
}
@@ -6978,7 +6988,7 @@ namespace BrewMonster
}
return iItemCnt;
}
bool CanUseEquipment(EC_IvtrEquip pEquip, ref int piReason)
public bool CanUseEquipment(EC_IvtrEquip pEquip, ref int piReason)
{
int iReason = 0;
if(pEquip == null)
@@ -7059,5 +7069,533 @@ namespace BrewMonster
{
return m_pPetCorral;
}
public bool UseItemInPack(int iPack, int iSlot, bool showMsg = true)
{
if(!CanDo(ActionCanDo.CANDO_USEITEM))
return false;
EC_Inventory pPack = GetPack(iPack);
if (pPack == null)
return false;
EC_IvtrItem pItem = pPack.GetItem(iSlot);
if (pItem == null || pItem.IsFrozen())
return false;
if(pItem.Use_Persist() && (IsJumping() || IsFalling()))
return false;
CECGameRun pGameRun = EC_Game.GetGameRun();
//CECGameSession pSession = g_pGame.GetGameSession();
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TRANSMITSCROLL)
{
CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan();
if (pGameUI != null && !IsFighting())
{
// TODO: Implement travel map dialog
}
return true;
}
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM)
{
EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem;
if(pTargetItem == null)
return false;
var essence = pTargetItem.GetDBEssence();
if(!pTargetItem.IsEssenceLoaded())
return false;
if (IsFighting() && essence.use_in_combat == 0)
{
if (showMsg)
if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE);
return false;
}
if (pTargetItem.GetDBEssence().use_in_sanctuary_only != 0 && !IsInSanctuary())
{
if (showMsg)
pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_USE_IN_SANCTUARY_ONLY);
return false;
}
int iCurrMap = pGameRun.GetWorld().GetInstanceID();
if (pTargetItem.GetDBEssence().num_area != 0)
{
bool found = false;
for (int i = 0; i < pTargetItem.GetDBEssence().num_area; i++)
{
if (pTargetItem.GetDBEssence().area_id[i] == iCurrMap)
{
found = true;
break;
}
}
if (!found)
{
if(showMsg)
pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_CURR_MAP);
return false;
}
}
if(!CanDo(ActionCanDo.CANDO_SPELLMAGIC))
return false;
if (InSlidingState())
return false;
if (m_idSelTarget == 0)
return false;
CECSkill pSkill = pTargetItem.GetTargetSkill();
if (pSkill == null)
return false;
if (IsSpellingMagic() && m_pCurSkill != null && m_pCurSkill.IsCharging() &&
m_pCurSkill.GetSkillID() == pSkill.GetSkillID())
{
m_pCurSkill.EndCharging();
UnityGameSession.c2s_SendCmdContinueAction();
return true;
}
int iCon = CheckSkillCastCondition(pSkill);
if (iCon != 0)
{
if (showMsg)
ProcessSkillCondition(iCon);
return false;
}
bool bForceAttack = glb_GetForceAttackFlag(0);
if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_ATTACK ||
pSkill.GetType() == (int)CECSkill.SkillType.TYPE_CURSE)
{
if (m_idSelTarget == m_PlayerInfo.cid)
{
if (showMsg)
pGameRun.AddFixedChannelMsg((int)FixedMsg.FIXMSG_TARGETWRONG, (int)ChatChannel.GP_CHAT_FIGHT);
return false;
}
else if (m_idSelTarget != 0)
{
if (AttackableJudge(m_idSelTarget, bForceAttack) != 1)
return false;
}
}
int idCastTarget = m_idSelTarget;
int iTargetType = pSkill.GetTargetType();
if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS ||
pSkill.GetType() == (int)CECSkill.SkillType.TYPE_NEUTRALBLESS)
{
if(iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget))
idCastTarget = m_PlayerInfo.cid;
if (GPDataTypeHelper.ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid)
{
byte byBLSMask = EC_Utility.glb_BuildBLSMask();
if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_POINT)
{
if (!IsTeamMember(idCastTarget))
{
if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_SELF) != 0)
{
idCastTarget = m_PlayerInfo.cid;
}
else
{
EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget) as EC_ElsePlayer;
if(pPlayer == null)
return false;
if (pPlayer.IsInvader() || pPlayer.IsPariah())
{
if((byBLSMask & (byte)PVPMask.GP_BLSMASK_NORED) != 0)
idCastTarget = m_PlayerInfo.cid;
}
if (!IsFactionMember(pPlayer.GetFactionID()))
{
if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOMAFIA) != 0)
idCastTarget = m_PlayerInfo.cid;
}
if (!IsFactionAllianceMember(pPlayer.GetFactionID()))
{
if((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOALLIANCE) != 0)
idCastTarget = m_PlayerInfo.cid;
}
if (GetForce() != pPlayer.GetForce())
{
if((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOFORCE) != 0)
idCastTarget = m_PlayerInfo.cid;
}
}
}
}
// If host is in dule
if(IsInDuel() && m_idSelTarget == m_pvp.idDuelOpp)
idCastTarget = m_PlayerInfo.cid;
// If host is in battle
if (IsInBattle())
{
EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget);
if (!InSameBattleCamp(pPlayer))
idCastTarget = m_PlayerInfo.cid;
}
}
}
if (iTargetType != 0)
{
int iAliveFlag = 0;
if (iTargetType == 1)
iTargetType = 1;
else if (iTargetType == 2)
iTargetType = 2;
CECObject pObject = EC_ManMessageMono.Instance.GetObject(idCastTarget, iAliveFlag);
if(pObject == null)
return false;
}
if (!IsMeleeing() && !IsSpellingMagic() &&
(iTargetType == 0 || idCastTarget == m_PlayerInfo.cid))
{
if(!pSkill.ReadyToCast())
return false;
if (!pSkill.IsInstant() && pSkill.GetType() != (int)CECSkill.SkillType.TYPE_FLASHMOVE)
{
// TODO: Implement NaturallyStopMoving
//if (!NaturallyStopMoving())
// return false;
}
else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_FLASHMOVE)
{
if(!CanDo(ActionCanDo.CANDO_FLASHMOVE))
return false;
}
m_pPrepSkill = pSkill;
}
else if (IsSpellingMagic() && m_pCurSkill == pSkill && !pSkill.ReadyToCast())
{
return false;
}
}
if (pItem.IsEquipment())
{
if (iPack == Inventory_type.IVTRTYPE_EQUIPPACK)
{
// Take off equipment
int iEmpty = m_pPack.SearchEmpty();
if (iEmpty < 0)
return false;
UnityGameSession.RequestEquipItemAsync((byte)iEmpty, (byte)iSlot, null);
return true;
}
EC_IvtrEquip pEquip = pItem as EC_IvtrEquip;
if(pEquip == null)
return false;
int iReason = 0;
if(!CanUseEquipment(pEquip, ref iReason))
return false;
int iFirstFree = -1, iFirstCan = -1;
for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++)
{
if (pItem.CanEquippedTo(i))
{
if (iFirstCan < 0)
iFirstCan = i;
if (m_pEquipPack.GetItem(i) == null && iFirstFree < 0)
{
iFirstFree = i;
break;
}
}
}
int iDst;
if (iFirstFree >= 0)
iDst = iFirstFree;
else if (iFirstCan >= 0)
iDst = iFirstCan;
else
{
Debug.Assert(false);
return false;
}
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_ARROW ||
pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP)
{
EC_IvtrItem pDstItem = m_pEquipPack.GetItem(iDst);
if (pDstItem == null || pItem.GetTemplateID() != pDstItem.GetTemplateID())
UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null);
else
{
//UnityGameSession.c2s_CmdMoveItemToEquip((byte)iSlot, (byte)iDst);
}
}
else
{
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_GENERALCARD)
{
//TODO: Add general card equip request
}
UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null);
}
return true;
}
if(iPack != Inventory_type.IVTRTYPE_PACK)
return false;
if (!pItem.CheckUseCondition())
{
if (showMsg)
pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_CANNOTUSE);
return false;
}
int piMax = -1;
if (pItem.GetCoolTime(out piMax) > 0)
{
if (showMsg)
pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_INCOOLTIME);
return false;
}
if (pItem.Use_AtkTarget() || pItem.Use_Target())
{
if(pItem.Use_AtkTarget() && CannotAttack())
return false;
if (m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid)
{
if (showMsg)
{
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_NOTARGET), (int)ChatChannel.GP_CHAT_SYSTEM);
}
return false;
}
float fAattackRange = 10000.0f;
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TOSSMAT)
{
EC_IvtrTossMat pTossMat = pItem as EC_IvtrTossMat;
if (pTossMat != null)
fAattackRange = pTossMat.GetDBEssence().attack_range;
}
else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TANKCALLIN)
{
fAattackRange = 5.0f;
}
else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM)
{
EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem;
if (pTargetItem != null && pTargetItem.GetTargetSkill() != null)
{
fAattackRange = pTargetItem.GetTargetSkill().GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus());
}
}
float fDist = 0, fTargetRag = 0;
CECObject pObject = null;
//if (CalcDist(m_idSelTarget, ref fDist, ref pObject))
//{
// return false;
//}
if (GPDataTypeHelper.ISNPCID(m_idSelTarget))
{
CECNPC pNPC = pObject as CECNPC;
if (pNPC != null)
fTargetRag = pNPC.GetTouchRadius();
}
else if (GPDataTypeHelper.ISPLAYERID(m_idSelTarget))
{
EC_ElsePlayer pPlayer = pObject as EC_ElsePlayer;
if(pPlayer != null)
fTargetRag = pPlayer.GetTouchRadius();
}
if (fDist - fTargetRag > fAattackRange * 0.8f)
{
if (showMsg)
{
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_TARGETISFAR), (int)ChatChannel.GP_CHAT_SYSTEM);
}
return false;
}
byte byPVPMask = glb_BuildPVPMask(glb_GetForceAttackFlag(0));
UnityGameSession.c2s_SendCmdUseItemWithTarget((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), byPVPMask);
}
else
{
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DOUBLEEXP)
{
EC_IvtrDoubleExp pDoubleExp = pItem as EC_IvtrDoubleExp;
if (pDoubleExp != null)
{
if (pDoubleExp.GetDBEssence().double_exp_time + pGameRun.GetRemainDblExpTime() > 3600 * 4)
{
if (showMsg)
{
CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan();
}
return false;
}
}
}
if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHARPENER)
{
if (showMsg)
pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_SHARPEN_ON_DRAG);
return false;
}
UnityGameSession.c2s_SendCmdUseItem((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), 1);
}
return true;
}
private void OnMsgHstUseItem(ECMSG Msg)
{
cmd_host_use_item pCmd = GPDataTypeHelper.FromBytes<cmd_host_use_item>((byte[])Msg.dwParam1);
EC_Inventory pPack = GetPack(pCmd.byPackage);
if (pPack == null)
{
Debug.LogError("[OnMsgHstUseItem] Pack not found");
return;
}
EC_IvtrItem pItem = pPack.GetItem(pCmd.bySlot, false);
if (pItem == null || pItem.GetTemplateID() != pCmd.item_id)
{
Debug.LogError($"[OnMsgHstUseItem] Item mismatch at slot {pCmd.bySlot}");
return;
}
pItem.Use();
if (pCmd.use_count > 0)
{
bool removed = pPack.RemoveItem(pCmd.bySlot, pCmd.use_count);
if (removed)
{
if (pPack.GetItem(pCmd.bySlot, false) == null)
{
Debug.Log($"[OnMsgHstUseItem] Item {pCmd.item_id} removed from slot {pCmd.bySlot}");
}
}
else
{
Debug.LogError($"[OnMsgHstUseItem] Failed to remove item {pCmd.item_id} from slot {pCmd.bySlot}");
}
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
if (ui != null)
{
ui.RefreshAll();
ui.UpdateCooldownOverlays();
}
else
{
Debug.LogError("[OnMsgHstUseItem] EC_InventoryUI not found, UI may not update");
}
}
if (m_pWorkMan != null)
{
CECHPWork pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM);
if (pWork is CECHPWorkUse useWork)
{
if(useWork.GetItem() == pCmd.item_id)
{
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM);
}
}
}
}
/// <summary>
/// Calculate distance to an object and optionally retrieve the object reference
/// 计算到对象的距离,并可选地获取对象引用
/// </summary>
/// <param name="idObject">Target object ID / 目标对象ID</param>
/// <param name="pfDist">Output distance / 输出距离</param>
/// <param name="ppObject">Output object reference (optional) / 输出对象引用(可选)</param>
/// <returns>True if calculation succeeded / 计算成功返回true</returns>
//public bool CalcDist(int idObject, ref float pfDist, out CECObject ppObject)
//{
// ppObject = null;
// if (idObject == 0 || idObject == m_PlayerInfo.cid)
// return false;
// CECObject pObject = CECGameRun.Instance.GetWorld()?.GetObject(idObject, 1);
// if (pObject == null)
// return false;
// ppObject = pObject;
// float fDist = 0.0f;
// if (ISNPCID(idObject))
// {
// CECNPC pNPC = (CECNPC)pObject;
// fDist = pNPC.CalcDist(GetPos(), true);
// }
// else if (ISPLAYERID(idObject))
// {
// Debug.Assert(pObject.GetClassID() == CECObject.OCID_ELSEPLAYER);
// EC_ElsePlayer pPlayer = (EC_ElsePlayer)pObject;
// fDist = pPlayer.CalcDist(GetPos(), true);
// }
// else if (ISMATTERID(idObject))
// {
// Debug.Assert(pObject.GetClassID() == CECObject.OCID_MATTER);
// CECMatter pMatter = (CECMatter)pObject;
// fDist = (pMatter.GetPos() - GetPos()).magnitude;
// }
// else
// return false;
// pfDist = fDist;
// return true;
//}
//// Helper method overload without object output
//public bool CalcDist(int idObject, ref float pfDist)
//{
// CECObject pObject;
// return CalcDist(idObject, ref pfDist, out pObject);
//}
//// ID checking helper methods
//private bool ISNPCID(int id) => ((id & 0x80000000) != 0) && ((id & 0x40000000) == 0);
//private bool ISPLAYERID(int id) => id != 0 && (id & 0x80000000) == 0;
//private bool ISMATTERID(int id) => ((id) & 0xC0000000) == 0xC0000000;
}
}