装备系统完结,修复并加入很多

This commit is contained in:
FloatGaming
2026-04-03 19:15:02 +08:00
parent 538085b64f
commit d9376833b6
378 changed files with 62464 additions and 16756 deletions
+302 -8
View File
@@ -41,6 +41,7 @@ public class storeSystem : MonoBehaviour
[Header("sprites")]
public Sprite coinSprite;
public Sprite materialSprite;
public Sprite cannotBuySprite;
[Header("selecting item purchase")]
@@ -54,6 +55,10 @@ public class storeSystem : MonoBehaviour
public Button purchaseButton;
public Text p_detailedDescriptionText;
[Header("selectable equipment reward")]
public GameObject ctasPrefab;
public Transform ctasParent;
private const int MinPurchaseAmount = 1;
private const int MaxPurchaseAmount = 999999;
private static readonly Color InsufficientCostColor = new Color(0.45f, 0.08f, 0.08f, 1f);
@@ -67,6 +72,7 @@ public class storeSystem : MonoBehaviour
private int currentPurchaseAmount = MinPurchaseAmount;
private bool suppressAmountInputCallback;
private Color defaultSumCostColor = Color.white;
private GameObject activeCtasInstance;
private string LegacySaveFilePath
{
@@ -102,6 +108,7 @@ public class storeSystem : MonoBehaviour
private void OnDestroy()
{
CloseActiveCtas();
UnregisterHeaderControlCallbacks();
UnregisterToggleCallbacks();
UnregisterPurchasePanelCallbacks();
@@ -274,6 +281,7 @@ public class storeSystem : MonoBehaviour
private void OnCloseButtonClicked()
{
CloseActiveCtas();
gameObject.SetActive(false);
}
@@ -624,7 +632,7 @@ public class storeSystem : MonoBehaviour
&& itemSO.canbepurchased
&& !IsAssociatedContentUnlocked(itemSO)
&& !IsSoldOut(itemSO)
&& HasCoinRequirement(itemSO);
&& HasSupportedRequirement(itemSO);
}
private void SpawnItem(storeItemSO itemSO)
@@ -732,7 +740,7 @@ public class storeSystem : MonoBehaviour
: itemSO.itemDetailedDescription;
}
if (resetAmount)
if (resetAmount || IsSelectableEquipmentRewardItem(itemSO))
{
SetPurchaseAmount(MinPurchaseAmount, false);
}
@@ -742,6 +750,7 @@ public class storeSystem : MonoBehaviour
RefreshPurchaseSummary();
}
UpdatePurchaseAmountControlsState(itemSO);
RefreshPurchaseButtonState();
}
@@ -773,6 +782,7 @@ public class storeSystem : MonoBehaviour
currentPurchaseAmount = MinPurchaseAmount;
UpdatePurchaseAmountInput();
UpdatePurchaseAmountControlsState(null);
RefreshPurchaseButtonState();
}
@@ -839,6 +849,26 @@ public class storeSystem : MonoBehaviour
}
}
private void UpdatePurchaseAmountControlsState(storeItemSO itemSO)
{
bool forceSinglePurchase = IsSelectableEquipmentRewardItem(itemSO);
if (p_iAmount_plus != null)
{
p_iAmount_plus.interactable = !forceSinglePurchase;
}
if (p_iAmount_minus != null)
{
p_iAmount_minus.interactable = !forceSinglePurchase;
}
if (p_iAmount_input != null)
{
p_iAmount_input.interactable = !forceSinglePurchase;
}
}
private void SetPurchaseAmount(int amount, bool showWarnings)
{
int clampedAmount = amount;
@@ -927,10 +957,15 @@ public class storeSystem : MonoBehaviour
return coinSprite;
}
if (currencyType == storeItemSO.CurrencyType.material)
{
return materialSprite;
}
return null;
}
private bool HasCoinRequirement(storeItemSO itemSO)
private bool HasSupportedRequirement(storeItemSO itemSO)
{
if (itemSO == null || itemSO.costRequirements == null || itemSO.costRequirements.Count == 0)
{
@@ -1009,6 +1044,12 @@ public class storeSystem : MonoBehaviour
return;
}
if (IsSelectableEquipmentRewardItem(currentSelectedItem))
{
HandleSelectableEquipmentPurchaseClicked(currentSelectedItem);
return;
}
string failureMessage;
int grantedCount;
if (!StoreExpBottlePurchaseService.TryPurchase(playerData, currentSelectedItem, currentPurchaseAmount, out failureMessage, out grantedCount))
@@ -1026,6 +1067,125 @@ public class storeSystem : MonoBehaviour
RefreshCurrentView();
}
private void HandleSelectableEquipmentPurchaseClicked(storeItemSO itemSO)
{
if (itemSO == null)
{
return;
}
if (currentPurchaseAmount != 1)
{
SetPurchaseAmount(1, false);
gNotice.warning.display("该物品仅支持单份购买");
return;
}
if (!TryGetSelectableEquipmentRequirement(itemSO, out smeltStageRewardSO rewardSource, out smeltStageRewardSO.SmeltStageRewardRequirement requirement))
{
gNotice.warning.display("当前未配置发放逻辑");
return;
}
bool requireTypeSelection = RequiresTypeSelection(requirement);
bool requireSkillSelection = RequiresSkillSelection(requirement);
if (!requireTypeSelection && !requireSkillSelection)
{
TryCompleteSelectableEquipmentPurchase(itemSO, rewardSource, requirement, null, 0);
return;
}
if (ctasPrefab == null || ctasParent == null || rewardSource == null || rewardSource.rewardRandomConfig == null)
{
gNotice.warning.display("选择器未配置");
return;
}
CloseActiveCtas();
GameObject instance = Instantiate(ctasPrefab, ctasParent);
activeCtasInstance = instance;
global::ctasPrefab selector = instance.GetComponent<global::ctasPrefab>();
if (selector == null)
{
Destroy(instance);
activeCtasInstance = null;
gNotice.warning.display("选择器未配置");
return;
}
equipmentSO selectionTemplate = rewardSource.rewardTemplate != null
? Instantiate(rewardSource.rewardTemplate)
: ScriptableObject.CreateInstance<equipmentSO>();
selectionTemplate.hideFlags = HideFlags.DontSave;
selectionTemplate.sa_skillID = 0;
selectionTemplate.ia_skillID = 0;
selectionTemplate.skillType = requirement.chosenSkillType;
selector.Initialize(
selectionTemplate,
rewardSource.rewardRandomConfig,
requireTypeSelection,
requireSkillSelection,
(selectedType, selectedSkillGroupId) =>
{
activeCtasInstance = null;
TryCompleteSelectableEquipmentPurchase(itemSO, rewardSource, requirement, selectedType, selectedSkillGroupId);
},
() => { activeCtasInstance = null; });
}
private void TryCompleteSelectableEquipmentPurchase(
storeItemSO itemSO,
smeltStageRewardSO rewardSource,
smeltStageRewardSO.SmeltStageRewardRequirement requirement,
equipmentSO.EquipmentSkillType? selectedType,
int selectedSkillGroupId)
{
if (itemSO == null || rewardSource == null || requirement == null || itemSO.costRequirements == null || itemSO.costRequirements.Count == 0)
{
gNotice.warning.display("商品数据丢失");
return;
}
var primaryCost = itemSO.costRequirements[0];
int totalCost = Mathf.Max(0, primaryCost.amount);
string insufficientMessage = primaryCost.currencyType == storeItemSO.CurrencyType.material ? "记忆碎片不足" : "货币不足";
if (!HasEnoughCurrency(primaryCost.currencyType, totalCost))
{
gNotice.warning.display(insufficientMessage);
RefreshPurchaseSummary();
return;
}
if (!TrySpendCurrency(primaryCost.currencyType, totalCost))
{
gNotice.warning.display(insufficientMessage);
RefreshPurchaseSummary();
return;
}
equipmentSO generated = equipmentGenerator.GenerateFromSmeltReward(
rewardSource,
requirement,
selectedType,
selectedSkillGroupId);
if (generated == null)
{
RefundCurrency(primaryCost.currencyType, totalCost);
gNotice.warning.display("装备发放失败");
RefreshPurchaseSummary();
return;
}
RegisterPurchasedCount(itemSO.itemID, 1);
RefreshAllEquipBags();
}
private string GetAmountAndQuotaText(storeItemSO itemSO)
{
string prefix = itemSO.itemSinglePurchaseQty == 1 ? string.Empty : $"{itemSO.itemSinglePurchaseQty}个装/";
@@ -1064,7 +1224,7 @@ public class storeSystem : MonoBehaviour
private string GetPriceAmountText(storeItemSO itemSO)
{
if (itemSO == null || !itemSO.canbepurchased || IsAssociatedContentUnlocked(itemSO) || !HasCoinRequirement(itemSO))
if (itemSO == null || !itemSO.canbepurchased || IsAssociatedContentUnlocked(itemSO) || !HasSupportedRequirement(itemSO))
{
return "不可购买";
}
@@ -1074,22 +1234,156 @@ public class storeSystem : MonoBehaviour
private bool ShouldShowPriceIcon(storeItemSO itemSO)
{
return itemSO != null && itemSO.canbepurchased && !IsAssociatedContentUnlocked(itemSO) && HasCoinRequirement(itemSO);
return itemSO != null && itemSO.canbepurchased && !IsAssociatedContentUnlocked(itemSO) && HasSupportedRequirement(itemSO);
}
private bool CanPurchaseCurrentSelection(storeItemSO itemSO)
{
return IsCurrentlyPurchasable(itemSO);
return IsCurrentlyPurchasable(itemSO)
&& (!IsSelectableEquipmentRewardItem(itemSO) || currentPurchaseAmount == 1);
}
private bool CanAffordCurrentSelection(long totalCost)
{
if (totalCost <= 0)
if (currentSelectedItem == null || totalCost <= 0)
{
return true;
}
return PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(totalCost);
var cost = currentSelectedItem.costRequirements != null && currentSelectedItem.costRequirements.Count > 0
? currentSelectedItem.costRequirements[0]
: null;
if (cost == null)
{
return false;
}
switch (cost.currencyType)
{
case storeItemSO.CurrencyType.coins:
return PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(totalCost);
case storeItemSO.CurrencyType.material:
return PlayerEconomyLedger.EnsureInstance().HasEnoughMaterial(totalCost);
default:
return false;
}
}
private bool IsSelectableEquipmentRewardItem(storeItemSO itemSO)
{
return itemSO != null
&& itemSO.associatedSelectableEquipmentRewardSource != null
&& itemSO.associatedSelectableEquipmentRewardIndex >= 0;
}
private bool TryGetSelectableEquipmentRequirement(
storeItemSO itemSO,
out smeltStageRewardSO rewardSource,
out smeltStageRewardSO.SmeltStageRewardRequirement requirement)
{
rewardSource = null;
requirement = null;
if (!IsSelectableEquipmentRewardItem(itemSO))
{
return false;
}
rewardSource = itemSO.associatedSelectableEquipmentRewardSource;
if (rewardSource.rewardRequirements == null
|| itemSO.associatedSelectableEquipmentRewardIndex >= rewardSource.rewardRequirements.Length)
{
rewardSource = null;
return false;
}
requirement = rewardSource.rewardRequirements[itemSO.associatedSelectableEquipmentRewardIndex];
return requirement != null;
}
private bool RequiresTypeSelection(smeltStageRewardSO.SmeltStageRewardRequirement requirement)
{
if (requirement == null)
{
return false;
}
if (requirement.equipmentType == smeltStageRewardSO.equipType.selfChosenType)
{
return true;
}
return !string.IsNullOrEmpty(requirement.equipRewardName)
&& requirement.equipRewardName.Contains("自选");
}
private bool RequiresSkillSelection(smeltStageRewardSO.SmeltStageRewardRequirement requirement)
{
return requirement != null
&& requirement.skillRequirement == smeltStageRewardSO.skillOwned.selfChosen;
}
private bool HasEnoughCurrency(storeItemSO.CurrencyType currencyType, int amount)
{
switch (currencyType)
{
case storeItemSO.CurrencyType.coins:
return PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(amount);
case storeItemSO.CurrencyType.material:
return PlayerEconomyLedger.EnsureInstance().HasEnoughMaterial(amount);
default:
return false;
}
}
private bool TrySpendCurrency(storeItemSO.CurrencyType currencyType, int amount)
{
switch (currencyType)
{
case storeItemSO.CurrencyType.coins:
return PlayerEconomyLedger.EnsureInstance().TrySpendCoins(amount);
case storeItemSO.CurrencyType.material:
return PlayerEconomyLedger.EnsureInstance().TrySpendMaterial(amount);
default:
return false;
}
}
private void RefundCurrency(storeItemSO.CurrencyType currencyType, int amount)
{
switch (currencyType)
{
case storeItemSO.CurrencyType.coins:
PlayerEconomyLedger.EnsureInstance().AddCoins(amount);
break;
case storeItemSO.CurrencyType.material:
PlayerEconomyLedger.EnsureInstance().AddMaterial(amount);
break;
}
}
private void CloseActiveCtas()
{
if (activeCtasInstance != null)
{
Destroy(activeCtasInstance);
activeCtasInstance = null;
}
}
private static void RefreshAllEquipBags()
{
equipBag[] bags = Resources.FindObjectsOfTypeAll<equipBag>();
for (int i = 0; i < bags.Length; i++)
{
equipBag bag = bags[i];
if (bag == null)
{
continue;
}
bag.Rebuild();
}
}
private void SetupAvailabilityState(storeItemPrefab itemView, storeItemSO itemSO)