using System.Collections.Generic; using System.Linq; using Cielonos.MainGame.Characters; using Cielonos.MainGame.UI; using Sirenix.OdinInspector; using SLSUtilities.General; using UnityEngine; namespace Cielonos.MainGame.Inventory { public class FunctionSubmodule : SubmoduleBase { [ReadOnly] public Dictionary functionUnits; public RuntimeFunctionUnit mainFunction => functionUnits.Count > 0 ? functionUnits.Values.First() : null; public RuntimeFunctionUnit this[string functionName] => functionUnits.ContainsKey(functionName) ? functionUnits[functionName] : null; public FunctionSubmodule(ItemBase owner, FunctionData data) : base(owner) { functionUnits = new Dictionary(); foreach (var unit in data.functionUnitList) { functionUnits[unit.unitName] = new RuntimeFunctionUnit(this, unit); } } public void Update(float deltaTime) { foreach (var unit in functionUnits.Values) { unit.Update(deltaTime); } } } public class RuntimeFunctionUnit : SubmoduleBase { private CharacterBase character => owner.owner.player; public FunctionData.FunctionUnit data; public float currentCooldown; public float maxCooldown; public RuntimeFunctionUnit(FunctionSubmodule owner, FunctionData.FunctionUnit data) : base(owner) { this.data = data; maxCooldown = data.cooldown; currentCooldown = 0f; } public void Update(float deltaTime) { currentCooldown -= deltaTime; currentCooldown = Mathf.Max(currentCooldown, 0f); } public bool IsAvailable() { bool cooldownAvailable = currentCooldown <= 0f; bool energyAvailable = character.attributeSm[CharacterAttribute.Energy] >= GetEffectiveEnergyCost(); bool available = cooldownAvailable && energyAvailable; if (!available) { if(character is Player && owner.owner is MainWeaponBase) { if (data.shownInUI || data.isMain) { PlayerCanvas.MainWeaponUIArea.functionIconDict[data.unitName].SetFrameOutline(0.25f, Color.red); } } } return available; } public RuntimeFunctionUnit Execute() { ResetCooldown(); ConsumeEnergy(); if(character is Player && owner.owner is MainWeaponBase) { if (data.shownInUI || data.isMain) { PlayerCanvas.MainWeaponUIArea.functionIconDict[data.unitName].SetFrameOutline(0.25f); } } return this; } private const float MaxCooldownReduction = 0.9f; private const float MaxEnergyCostReduction = 0.9f; /// 计算应用 EnergyCostReduction 后的实际能量消耗。 private float GetEffectiveEnergyCost() { float energyCostReduction = Mathf.Clamp(character.attributeSm[CharacterAttribute.EnergyCostReduction], 0f, MaxEnergyCostReduction); return data.energyCost * (1f - energyCostReduction); } private void ResetCooldown() { float cooldownReduction = Mathf.Clamp(character.attributeSm[CharacterAttribute.CooldownReduction], 0f, MaxCooldownReduction); currentCooldown = maxCooldown * (1f - cooldownReduction); } private void ConsumeEnergy() { float cost = GetEffectiveEnergyCost(); character.attributeSm[CharacterAttribute.Energy] -= cost; // onEnergyChanged 已由 AttributeSubmodule 值变更回调自动触发 } } }