Merge pull request 'feature/update-ui' (#308) from feature/update-ui into develop
Reviewed-on: https://git.pthub.vn/Unity/perfect-world-unity/pulls/308
This commit is contained in:
@@ -2,12 +2,13 @@
|
||||
// Creator : Converted from C++ EC_Shop
|
||||
// Date : 2024
|
||||
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts;
|
||||
using CSNetwork.C2SCommand;
|
||||
using System.Text.RegularExpressions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Network;
|
||||
using CSNetwork.C2SCommand;
|
||||
|
||||
public class NPCShopDetailPanel : MonoBehaviour
|
||||
{
|
||||
@@ -47,7 +48,7 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
void UpdateDisplay()
|
||||
public void UpdateDisplay()
|
||||
{
|
||||
if (currentItem.id == 0)
|
||||
{
|
||||
@@ -59,6 +60,9 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
if (itemDescriptionText != null)
|
||||
{
|
||||
string description = GetItemDescription((int)currentItem.id);
|
||||
Debug.Log("[NPCShopDetail] RAW:\n" + description);
|
||||
description = SanitizeDescription(description);
|
||||
Debug.Log("[NPCShopDetail] Sanitized:\n" + description);
|
||||
itemDescriptionText.Set(description);
|
||||
}
|
||||
|
||||
@@ -85,7 +89,57 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
LoadItemIcon(itemIconImage, (int)currentItem.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string SanitizeDescription(string desc)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(desc))
|
||||
return string.Empty;
|
||||
|
||||
// Normalize escaped + real line breaks (including unicode line separators)
|
||||
desc = Regex.Replace(
|
||||
desc,
|
||||
@"\\r\\n|\\n|\\r|\r\n|\r|\u2028|\u2029",
|
||||
"\n",
|
||||
RegexOptions.CultureInvariant);
|
||||
|
||||
desc = Regex.Replace(
|
||||
desc,
|
||||
@"\^[0-9A-Fa-f]{6}",
|
||||
string.Empty,
|
||||
RegexOptions.CultureInvariant);
|
||||
|
||||
string[] lines = desc.Split('\n');
|
||||
var sb = new System.Text.StringBuilder();
|
||||
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
string line = lines[i];
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
line = Regex.Replace(line, @"[\u200B-\u200D\uFEFF]", string.Empty, RegexOptions.CultureInvariant);
|
||||
string plain = Regex.Replace(line, @"<[^>]*>", string.Empty, RegexOptions.CultureInvariant)
|
||||
.Replace(':', ':')
|
||||
.Trim();
|
||||
if (Regex.IsMatch(plain, @"^(?:ID|Price)\s*:", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
|
||||
continue;
|
||||
line = Regex.Replace(
|
||||
line,
|
||||
@"(?i)\b(?:ID|Price)\b\s*[::]\s*\d+\b",
|
||||
string.Empty,
|
||||
RegexOptions.CultureInvariant).Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
if (sb.Length > 0)
|
||||
sb.AppendLine();
|
||||
|
||||
sb.Append(line);
|
||||
}
|
||||
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
void LoadItemIcon(Image iconImage, int itemId)
|
||||
{
|
||||
if (itemId <= 0 || iconImage == null)
|
||||
@@ -161,6 +215,12 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
|
||||
return "No description available.";
|
||||
}
|
||||
|
||||
public void ClearText()
|
||||
{
|
||||
if(itemDescriptionText != null)
|
||||
itemDescriptionText.Set(string.Empty);
|
||||
}
|
||||
|
||||
void OnCloseClicked()
|
||||
{
|
||||
@@ -223,6 +283,7 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public Text legacy;
|
||||
[SerializeField] public TMPro.TextMeshProUGUI tmp;
|
||||
Color myColorDecimal = new Color(1f, 0.816f, 0.365f, 1f);
|
||||
|
||||
public void Set(string value)
|
||||
{
|
||||
@@ -233,6 +294,7 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
if (tmp != null)
|
||||
{
|
||||
tmp.text = EC_Utility.FormatForTextMeshPro(value ?? string.Empty);
|
||||
Debug.Log($"[TextOutlet] Set text: {tmp.text}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,13 +26,16 @@ public class NPCShopUIManager : AUIDialog
|
||||
public GameObject contentRight;
|
||||
public GameObject contentMidSell;
|
||||
public GameObject item_info;
|
||||
public ScrollRect scrollDetailItem;
|
||||
public ScrollRect scrollListItem;
|
||||
|
||||
[Header("Texts")]
|
||||
public TextMeshProUGUI itemDetailNameText;
|
||||
public TextMeshProUGUI itemMoneyText;
|
||||
public TextOutlet itemDescriptionText;
|
||||
public NPCShopDetailPanel itemDescriptionText;
|
||||
public TextMeshProUGUI itemsBuyAmountText;
|
||||
public TextMeshProUGUI itemsBuyTotalMoneyText;
|
||||
public TextMeshProUGUI itemsSellTotalMoneyText;
|
||||
|
||||
[Header("Tabs")]
|
||||
public Transform tabButtonContainer;
|
||||
@@ -82,7 +85,6 @@ public class NPCShopUIManager : AUIDialog
|
||||
|
||||
/// <summary>Current NPC id for this shop session. Send SEVNPC_HELLO with this before buy.</summary>
|
||||
public uint CurrentNPCID => currentNPCID;
|
||||
private NPCShopDetailPanel detailPanelScript;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
@@ -392,45 +394,47 @@ public class NPCShopUIManager : AUIDialog
|
||||
// Initialize buy array with at least one option
|
||||
shopItem.buy = new GShopBuyOption[4]; // GShopItem supports up to 4 buy options
|
||||
|
||||
// Resolve display name/price in a type-agnostic way.
|
||||
// Some element types come back as DATA_TYPE values we don't special-case here (arrows, flyswords, fashion, etc).
|
||||
string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(unchecked((int)good.id));
|
||||
if (string.IsNullOrWhiteSpace(itemName))
|
||||
itemName = $"Item_{good.id}";
|
||||
|
||||
static int ExtractInt(object data, params string[] fieldOrPropNames)
|
||||
// Get item name and price based on type
|
||||
string itemName = "Unknown";
|
||||
int shopPrice = 0;
|
||||
|
||||
switch (itemDataType)
|
||||
{
|
||||
if (data == null || fieldOrPropNames == null || fieldOrPropNames.Length == 0)
|
||||
return 0;
|
||||
|
||||
var t = data.GetType();
|
||||
for (int i = 0; i < fieldOrPropNames.Length; i++)
|
||||
{
|
||||
string name = fieldOrPropNames[i];
|
||||
if (string.IsNullOrEmpty(name))
|
||||
continue;
|
||||
|
||||
var field = t.GetField(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
|
||||
if (field != null && field.FieldType == typeof(int))
|
||||
{
|
||||
try { return (int)field.GetValue(data); } catch { }
|
||||
}
|
||||
|
||||
var prop = t.GetProperty(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
|
||||
if (prop != null && prop.PropertyType == typeof(int) && prop.CanRead)
|
||||
{
|
||||
try { return (int)prop.GetValue(data); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
case DATA_TYPE.DT_WEAPON_ESSENCE:
|
||||
var weaponEssence = (WEAPON_ESSENCE)itemData;
|
||||
itemName = weaponEssence.Name;
|
||||
shopPrice = weaponEssence.shop_price;
|
||||
break;
|
||||
case DATA_TYPE.DT_ARMOR_ESSENCE:
|
||||
var armorEssence = (ARMOR_ESSENCE)itemData;
|
||||
itemName = armorEssence.Name;
|
||||
shopPrice = armorEssence.shop_price;
|
||||
break;
|
||||
case DATA_TYPE.DT_MEDICINE_ESSENCE:
|
||||
var medicineEssence = (MEDICINE_ESSENCE)itemData;
|
||||
itemName = ByteToStringUtils.UshortArrayToUnicodeString(medicineEssence.name);
|
||||
shopPrice = medicineEssence.shop_price;
|
||||
break;
|
||||
case DATA_TYPE.DT_DECORATION_ESSENCE:
|
||||
var decorationEssence = (DECORATION_ESSENCE)itemData;
|
||||
itemName = ByteToStringUtils.UshortArrayToUnicodeString(decorationEssence.name);
|
||||
shopPrice = decorationEssence.shop_price;
|
||||
break;
|
||||
case DATA_TYPE.DT_STONE_ESSENCE:
|
||||
var stoneEssence = (STONE_ESSENCE)itemData;
|
||||
itemName = ByteToStringUtils.UshortArrayToUnicodeString(stoneEssence.name);
|
||||
shopPrice = stoneEssence.shop_price;
|
||||
break;
|
||||
case DATA_TYPE.DT_MATERIAL_ESSENCE:
|
||||
var materialEssence = (MATERIAL_ESSENCE)itemData;
|
||||
itemName = ByteToStringUtils.UshortArrayToUnicodeString(materialEssence.name);
|
||||
shopPrice = materialEssence.shop_price;
|
||||
break;
|
||||
default:
|
||||
itemName = $"Item_{good.id}";
|
||||
break;
|
||||
}
|
||||
|
||||
// Prefer shop_price; fall back to base price if that's all we have.
|
||||
int shopPrice = ExtractInt(itemData, "shop_price");
|
||||
if (shopPrice <= 0)
|
||||
shopPrice = ExtractInt(itemData, "price");
|
||||
|
||||
|
||||
shopItem.name = itemName;
|
||||
|
||||
// Set price from contribution cost or shop price
|
||||
@@ -458,7 +462,42 @@ public class NPCShopUIManager : AUIDialog
|
||||
{
|
||||
if (itemPanelPrefab == null || itemContainer == null)
|
||||
return;
|
||||
|
||||
|
||||
if(scrollListItem != null)
|
||||
{
|
||||
scrollListItem.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
|
||||
if (scrollDetailItem != null)
|
||||
{
|
||||
scrollDetailItem.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
|
||||
if (itemDetailNameText != null)
|
||||
{
|
||||
itemDetailNameText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (itemMoneyText != null)
|
||||
{
|
||||
itemMoneyText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (itemDescriptionText != null)
|
||||
{
|
||||
itemDescriptionText.ClearText();
|
||||
}
|
||||
|
||||
if (itemIconImage != null)
|
||||
{
|
||||
itemIconImage.sprite = khung_item;
|
||||
}
|
||||
|
||||
if (itemsBuyTotalMoneyText != null)
|
||||
{
|
||||
itemsBuyTotalMoneyText.text = string.Empty;
|
||||
}
|
||||
|
||||
GameObject itemPanel = Instantiate(itemPanelPrefab, itemContainer);
|
||||
itemPanel.SetActive(true);
|
||||
|
||||
@@ -494,27 +533,37 @@ public class NPCShopUIManager : AUIDialog
|
||||
return;
|
||||
|
||||
SetupDetailPanel(item, this, shopItemIndex);
|
||||
|
||||
// Ensure detail panel script is available
|
||||
if (detailPanelScript == null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (detailPanelScript != null)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[NPCShopUIManager] NPCShopDetailPanel component not found on npcShopDetailPanel GameObject!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void CloseDialogue()
|
||||
{
|
||||
base.CloseDialogue();
|
||||
if (itemDetailNameText != null)
|
||||
{
|
||||
itemDetailNameText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (itemMoneyText != null)
|
||||
{
|
||||
itemMoneyText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (itemDescriptionText != null)
|
||||
{
|
||||
itemDescriptionText.ClearText();
|
||||
}
|
||||
|
||||
if (itemIconImage != null)
|
||||
{
|
||||
itemIconImage.sprite = khung_item;
|
||||
}
|
||||
|
||||
if(itemsBuyTotalMoneyText != null)
|
||||
{
|
||||
itemsBuyTotalMoneyText.text = string.Empty;
|
||||
}
|
||||
|
||||
EC_Game.GetGameRun().GetUIManager().GetInGameUIMan().EndNPCService();
|
||||
}
|
||||
|
||||
@@ -590,14 +639,18 @@ public class NPCShopUIManager : AUIDialog
|
||||
itemMoneyText.text = BuyUiEmptyValue;
|
||||
}
|
||||
|
||||
if (scrollDetailItem != null)
|
||||
{
|
||||
scrollDetailItem.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
|
||||
buyCount = BuyCountMin;
|
||||
UpdateBuyPriceTexts();
|
||||
|
||||
// Set item description
|
||||
if (itemDescriptionText != null)
|
||||
{
|
||||
string description = GetItemDescription((int)currentItem.id);
|
||||
itemDescriptionText.Set(description);
|
||||
itemDescriptionText.SetupDetailPanel(currentItem, this, shopItemIndex);
|
||||
}
|
||||
|
||||
// if (itemPriceText != null)
|
||||
@@ -708,7 +761,26 @@ public class NPCShopUIManager : AUIDialog
|
||||
|
||||
if (itemsBuyTotalMoneyText != null)
|
||||
{
|
||||
itemsBuyTotalMoneyText.text = total.ToString();
|
||||
uint playerMoney = 0;
|
||||
try
|
||||
{
|
||||
var host = CECGameRun.Instance?.GetHostPlayer();
|
||||
if (host != null)
|
||||
{
|
||||
playerMoney = host.GetMoneyAmount();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
playerMoney = 0;
|
||||
}
|
||||
|
||||
|
||||
string totalText = total.ToString();
|
||||
string playerMoneyStr = playerMoney.ToString();
|
||||
itemsBuyTotalMoneyText.text = total > playerMoney
|
||||
? $"<color=red>{total}</color>/{playerMoney}"
|
||||
: $"{total}/{playerMoney}";
|
||||
}
|
||||
|
||||
if (m_btn_buy != null)
|
||||
@@ -1138,28 +1210,6 @@ public class NPCShopUIManager : AUIDialog
|
||||
m_use_Item.onClick.RemoveListener(OnUseItemClicked);
|
||||
}
|
||||
|
||||
// === Text Outlet Helper ===
|
||||
[System.Serializable]
|
||||
public class TextOutlet
|
||||
{
|
||||
[SerializeField] public Text legacy;
|
||||
[SerializeField] public TMPro.TextMeshProUGUI tmp;
|
||||
|
||||
public void Set(string value)
|
||||
{
|
||||
if (legacy != null)
|
||||
{
|
||||
legacy.text = EC_Utility.FormatForLegacyText(value ?? string.Empty);
|
||||
}
|
||||
if (tmp != null)
|
||||
{
|
||||
string formatTextDeail = EC_Utility.FormatForTextMeshPro(value ?? string.Empty);
|
||||
formatTextDeail.Replace("<color=#FFFFFF>", "<color=#FFD05D>");
|
||||
tmp.text = formatTextDeail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupSellReadySlotListeners()
|
||||
{
|
||||
if (itemReadySell == null)
|
||||
@@ -1237,7 +1287,75 @@ public class NPCShopUIManager : AUIDialog
|
||||
|
||||
private void UpdateSellTotalPriceText()
|
||||
{
|
||||
// Sell total text removed from this manager.
|
||||
return;
|
||||
long totalSellValue = 0;
|
||||
int stageCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var host = CECGameRun.Instance?.GetHostPlayer();
|
||||
var inv = host?.GetInventory(0);
|
||||
|
||||
if (inv == null || sellSlotToSourceSlot == null)
|
||||
{
|
||||
if (itemsSellTotalMoneyText != null)
|
||||
itemsSellTotalMoneyText.text = BuyUiEmptyValue;
|
||||
if (m_btn_sell != null)
|
||||
m_btn_sell.interactable = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var pair in sellSlotToSourceSlot)
|
||||
{
|
||||
int sourceSlot = pair.Value;
|
||||
if (sourceSlot < 0 || sourceSlot >= inv.GetSize())
|
||||
continue;
|
||||
|
||||
var item = inv.GetItem(sourceSlot, false);
|
||||
if (item == null || item.m_iCount <= 0)
|
||||
continue;
|
||||
|
||||
if (!item.IsSellable())
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
item.GetDetailDataFromLocal();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int unitPrice = item.GetScaledPrice();
|
||||
long itemTotal = (long)unitPrice * item.m_iCount;
|
||||
if (itemTotal > 0)
|
||||
{
|
||||
totalSellValue += itemTotal;
|
||||
stageCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (itemsSellTotalMoneyText != null)
|
||||
{
|
||||
if(stageCount == 0 || totalSellValue <= 0)
|
||||
{
|
||||
itemsSellTotalMoneyText.text = BuyUiEmptyValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemsSellTotalMoneyText.text = totalSellValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_btn_sell != null)
|
||||
{
|
||||
m_btn_sell.interactable = stageCount > 0 && totalSellValue > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1840,11 +1840,11 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_fontSize
|
||||
value: 48.2
|
||||
value: 36
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_fontSizeBase
|
||||
value: 48.2
|
||||
value: 36
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_enableAutoSizing
|
||||
@@ -1934,25 +1934,49 @@ PrefabInstance:
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 200
|
||||
value: 171
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 67.9
|
||||
value: 56.91
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 532
|
||||
value: 85.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -37
|
||||
value: -28.455
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 85.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -152.91
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6102967088919909530, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 10.8
|
||||
value: 8
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6830833846243993097, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_Name
|
||||
@@ -1962,6 +1986,22 @@ PrefabInstance:
|
||||
propertyPath: m_IsActive
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 85.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -88.91
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7209086543831860202, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+7324
-2323
File diff suppressed because it is too large
Load Diff
+47
-16080
File diff suppressed because it is too large
Load Diff
@@ -1980,11 +1980,11 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_fontSize
|
||||
value: 48.2
|
||||
value: 36
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_fontSizeBase
|
||||
value: 48.2
|
||||
value: 36
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_enableAutoSizing
|
||||
@@ -2074,25 +2074,49 @@ PrefabInstance:
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 200
|
||||
value: 171
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 67.9
|
||||
value: 55.9082
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 532
|
||||
value: 85.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -37
|
||||
value: -27.9541
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 85.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -151.9082
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6102967088919909530, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 10.8
|
||||
value: 3.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6830833846243993097, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_Name
|
||||
@@ -2102,6 +2126,22 @@ PrefabInstance:
|
||||
propertyPath: m_IsActive
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 85.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -87.9082
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7209086543831860202, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
|
||||
+28
-120
@@ -2771,8 +2771,8 @@ namespace BrewMonster
|
||||
return m_idSelTarget;
|
||||
}
|
||||
|
||||
// Auto select a attackable target / 自动选择一个可攻击的目标
|
||||
// Auto select a attackable target / 自动选择一个可攻击的目标
|
||||
// Auto select a attackable target — cycle by distance (nearest → farthest, then repeat)
|
||||
// 自动选择可攻击目标 — 按距离循环(从近到远,再回到最近)
|
||||
public int AutoSelectTarget()
|
||||
{
|
||||
if (!CanDo(ActionCanDo.CANDO_CHANGESELECT))
|
||||
@@ -2780,145 +2780,53 @@ namespace BrewMonster
|
||||
|
||||
int idCurSel = (m_idSelTarget != 0 && m_idSelTarget != m_PlayerInfo.cid) ? m_idSelTarget : 0;
|
||||
|
||||
// Clean up invalid targets from tab selection array / 清理无效目标
|
||||
if (idCurSel == 0)
|
||||
{
|
||||
// Rebuild selected table / 重建选中表
|
||||
m_aTabSels.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove targets that are too far / 移除距离过远的目标
|
||||
for (int i = m_aTabSels.Count - 1; i >= 0; i--)
|
||||
{
|
||||
CECObject pObject = m_aTabSels[i];
|
||||
if (pObject == null)
|
||||
{
|
||||
m_aTabSels.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
float fDistToHost = 0.0f;
|
||||
if (pObject is EC_ElsePlayer pPlayer)
|
||||
fDistToHost = pPlayer.GetDistToHost();
|
||||
else if (pObject is CECNPC pNPC)
|
||||
fDistToHost = pNPC.GetDistToHost();
|
||||
|
||||
if (fDistToHost > EC_RoleTypes.EC_TABSEL_DIST || !CanSafelySelectWith(fDistToHost))
|
||||
{
|
||||
m_aTabSels.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float fMinDist = 10000.0f;
|
||||
CECObject pCand = null;
|
||||
int idCandidate = 0;
|
||||
|
||||
// Get player candidates / 获取玩家候选列表
|
||||
// idCurSel == 0 so TabSelectCandidates includes current target for index-based cycling
|
||||
List<EC_ElsePlayer> aCandPlayers = new List<EC_ElsePlayer>();
|
||||
EC_ManMessageMono.Instance.EC_ManPlayer.TabSelectCandidates(idCurSel, aCandPlayers);
|
||||
EC_ManMessageMono.Instance.EC_ManPlayer.TabSelectCandidates(0, aCandPlayers);
|
||||
List<CECNPC> aCandNPCs = new List<CECNPC>();
|
||||
EC_ManMessageMono.Instance.CECNPCMan.TabSelectCandidates(0, aCandNPCs);
|
||||
|
||||
var sorted = new List<(float dist, int id, CECObject obj)>();
|
||||
foreach (var pPlayer in aCandPlayers)
|
||||
{
|
||||
if (pPlayer == null)
|
||||
continue;
|
||||
|
||||
// Check whether this player is in selected array / 检查此玩家是否已在选中数组中
|
||||
if (m_aTabSels.Contains(pPlayer))
|
||||
continue; // This player has been in selected array / 此玩家已在选中数组中
|
||||
|
||||
// Record the nearest one as candidate / 记录最近的一个作为候选
|
||||
float fDist = pPlayer.GetDistToHost();
|
||||
if (fDist < fMinDist)
|
||||
{
|
||||
fMinDist = fDist;
|
||||
pCand = pPlayer;
|
||||
idCandidate = pPlayer.GetCharacterID();
|
||||
}
|
||||
sorted.Add((pPlayer.GetDistToHost(), pPlayer.GetCharacterID(), pPlayer));
|
||||
}
|
||||
|
||||
// Get NPC candidates / 获取NPC候选列表
|
||||
List<CECNPC> aCandNPCs = new List<CECNPC>();
|
||||
EC_ManMessageMono.Instance.CECNPCMan.TabSelectCandidates(idCurSel, aCandNPCs);
|
||||
|
||||
foreach (var pNPC in aCandNPCs)
|
||||
{
|
||||
if (pNPC == null)
|
||||
continue;
|
||||
|
||||
// Check whether this npc is in selected array / 检查此NPC是否已在选中数组中
|
||||
if (m_aTabSels.Contains(pNPC))
|
||||
continue; // This npc has been in selected array / 此NPC已在选中数组中
|
||||
|
||||
// Record the nearest one as candidate / 记录最近的一个作为候选
|
||||
float fDist = pNPC.GetDistToHost();
|
||||
if (fDist < fMinDist)
|
||||
{
|
||||
fMinDist = fDist;
|
||||
pCand = pNPC;
|
||||
idCandidate = pNPC.GetNPCID();
|
||||
}
|
||||
sorted.Add((pNPC.GetDistToHost(), pNPC.GetNPCID(), pNPC));
|
||||
}
|
||||
sorted.Sort((a, b) =>
|
||||
{
|
||||
int c = a.dist.CompareTo(b.dist);
|
||||
return c != 0 ? c : a.id.CompareTo(b.id);
|
||||
});
|
||||
|
||||
m_aTabSels.Clear();
|
||||
for (int i = 0; i < sorted.Count; i++)
|
||||
m_aTabSels.Add(sorted[i].obj);
|
||||
|
||||
// Maximum number of candidates in tab selection array / 标签选择数组中的最大候选数
|
||||
// Increased from 9 to 20 to allow more targets / 从9增加到20以允许更多目标
|
||||
const int iMaxCand = 9;
|
||||
int idNewSel = 0;
|
||||
|
||||
if (pCand != null && idCandidate != 0)
|
||||
if (sorted.Count == 0)
|
||||
{
|
||||
// Add candidate to tab selection array / 将候选添加到标签选择数组
|
||||
if (m_aTabSels.Count >= iMaxCand)
|
||||
{
|
||||
m_aTabSels.RemoveAt(m_aTabSels.Count - 1);
|
||||
m_aTabSels.Insert(0, pCand);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_aTabSels.Add(pCand);
|
||||
}
|
||||
|
||||
idNewSel = idCandidate;
|
||||
idNewSel = idCurSel;
|
||||
}
|
||||
else // No proper candidate was found / 未找到合适的候选
|
||||
else
|
||||
{
|
||||
if (m_aTabSels.Count == 0)
|
||||
int idx = -1;
|
||||
for (int i = 0; i < sorted.Count; i++)
|
||||
{
|
||||
idNewSel = idCurSel;
|
||||
}
|
||||
else // Try to select one which has been in selected array / 尝试选择已在选中数组中的一个
|
||||
{
|
||||
int iIndex = -1;
|
||||
for (int i = 0; i < m_aTabSels.Count; i++)
|
||||
if (sorted[i].id == idCurSel)
|
||||
{
|
||||
CECObject pObject = m_aTabSels[i];
|
||||
if (pObject == null)
|
||||
continue;
|
||||
|
||||
int objId = 0;
|
||||
if (pObject is EC_ElsePlayer pElsePlayer)
|
||||
objId = pElsePlayer.GetCharacterID();
|
||||
else if (pObject is CECNPC pNPC)
|
||||
objId = pNPC.GetNPCID();
|
||||
|
||||
if (objId == idCurSel)
|
||||
{
|
||||
iIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iIndex = (iIndex + 1) % m_aTabSels.Count;
|
||||
CECObject pSelectedObj = m_aTabSels[iIndex];
|
||||
if (pSelectedObj != null)
|
||||
{
|
||||
if (pSelectedObj is EC_ElsePlayer pSelPlayer)
|
||||
idNewSel = pSelPlayer.GetCharacterID();
|
||||
else if (pSelectedObj is CECNPC pSelNPC)
|
||||
idNewSel = pSelNPC.GetNPCID();
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int nextIdx = idx < 0 ? 0 : (idx + 1) % sorted.Count;
|
||||
idNewSel = sorted[nextIdx].id;
|
||||
}
|
||||
|
||||
// Select the target if found / 如果找到目标则选择它
|
||||
|
||||
Reference in New Issue
Block a user