using System.Collections.Generic; using ChocDino.UIFX; using Cielonos.MainGame.Buffs.Character; using Cielonos.MainGame.Characters; using Cielonos.MainGame.Effects.Feedback; using Cielonos.MainGame.UI; using SLSUtilities.Feedback; using SLSUtilities.General; using SLSUtilities.FunctionalAnimation; using SLSUtilities.WwiseAssistance; using UnityEngine; namespace Cielonos.MainGame.Inventory.Collections { public partial class Polychrome : MainWeaponBase { private PassionSystem _passionSystem; private bool _canAirLightAttack; private bool _canAirHeavyAttack; protected override void Update() { if (player.inventorySc.equipmentSm.currentMainWeapon == this) { functionSm?.Update(player.selfTimeSm.DeltaTime); } } public override void OnEquipped() { base.OnEquipped(); _currentKatanaParticle = string.Empty; player.eventSm.onFirstJump.TryAdd(nameof(Polychrome), new PrioritizedAction(() => { _canAirLightAttack = true; _canAirHeavyAttack = true; comboSm["AirLight"].Reset(); })); _passionSystem = CombatManager.GetCombatSystem(); _passionSystem.OnLevelChanged += OnPassionLevelChanged; RegisterFunctionsToAnimSc(StayBlocking); viewObjects["Katana"].SetFadeAnim(0.2f); viewObjects["Saya"].SetFadeAnim(0.2f); UpdateViewObjectVisuals(); } public override void OnUnequipped() { base.OnUnequipped(); _passionSystem.OnLevelChanged -= OnPassionLevelChanged; player.eventSm.onFirstJump.Remove(nameof(Polychrome)); } private void OnPassionLevelChanged(int oldLevel, int newLevel) { UpdateViewObjectVisuals(); } public override void OnSwitchIn() { if (_passionSystem.LevelIndex >= 3) { List availableEnemies = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 4); List disruptable = CombatManager.EnemySm.GetDisruptableEnemies(availableEnemies); Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies).ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy(); if (target != null) { if (PlayTargetedAnimation("DisruptionAttackB", target)) { FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup") .Clip("Time"); float duration = fullBodyFuncAnimSm.collection["DisruptionAttackB"] .Interval(IntervalType.Startup).Duration * 2; timeScaleModifierClip.duration = duration; player.feedbackSc.PlayFeedback("DisruptionStartup"); comboSm.main.Reset(); _passionSystem.DecreasePassion(100, false); } } SetBlock(equipBlockData, false); player.selfTimeSm.AddLocalTimer(0.4f, () => RemoveBlock(equipBlockData)); } else { PlayTargetedAnimation("EquipBlock"); SetBlock(equipBlockData); player.selfTimeSm.AddLocalTimer(0.4f, () => { RemoveBlock(equipBlockData); fullBodyFuncAnimSm.Stop("EquipBlock"); }); } } public override void OnPrimaryPress() { if (player.statusSm.HasStatus(StatusType.Stun)) { return; } if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName)) { return; } if (player.landMovementSc.isJumping) { if (!_canAirLightAttack || !functionSm["LightAttack"].IsAvailable()) { return; } if (PlayTargetedAnimation("AirAttack" + comboSm["AirLight"].GetNextNodeName("L"))) { comboSm["AirLight"].NextCombo("L"); functionSm["LightAttack"].Execute(); if (comboSm["AirLight"].GetCurrentNodeName() == "L1") { _canAirLightAttack = false; } } return; } CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5); if (player.landMovementSc.isSprinting && functionSm["LightAttack"].IsAvailable()) { comboSm.main.Reset(); if (PlayTargetedAnimation("RunAttack", target)) { comboSm.main.NextCombo("L"); } functionSm["LightAttack"].Execute(); return; } if (functionSm["LightAttack"].IsAvailable()) { string nextNodeName = comboSm.main.GetNextNodeName("L"); bool keepAdsorption = nextNodeName is "L4" or "L5"; if (PlayTargetedAnimation("Attack" + comboSm.main.GetNextNodeName("L"), target, 1f, keepAdsorption)) { float totalTime = 0f; CombatManager.EnemySm.activeEnemiesList.ForEach(enemy => { (enemy as Enemy).behaviorSc.DispatchContextEvent("PlayerLightAttack", totalTime); }); comboSm.main.NextCombo("L"); functionSm["LightAttack"].Execute(); } } } private bool TryPlayParryAttack(Enemy parryTarget, List availableEnemies) { if (parryTarget != null && !availableEnemies.Contains(parryTarget)) { float distance = Vector3.Distance(player.transform.position.Flatten(), parryTarget.transform.position.Flatten()); return PlayTargetedAnimation(distance > 2f ? "DodgeParryAttack" : "BlockParryAttack", parryTarget); } return PlayTargetedAnimation("BlockParryAttack"); } public override void OnSecondaryPress() { if (player.statusSm.HasStatus(StatusType.Stun)) { return; } List availableEnemies = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 4); BlockSubmodule blockSm = player.reactionSc.blockSm; if (!blockSm.afterPerfectBlockTimer.isCompleted) { Enemy blockedTarget = blockSm.perfectBlockedTarget as Enemy; if (TryPlayParryAttack(blockedTarget, availableEnemies)) { blockSm.afterPerfectBlockTimer.Complete(); RemoveBlock(); } } DodgeSubmodule dodgeSm = player.reactionSc.dodgeSm; if (!dodgeSm.afterPerfectDodgeTimer.isCompleted) { Enemy dodgedTarget = dodgeSm.perfectDodgedTarget as Enemy; if (TryPlayParryAttack(dodgedTarget, availableEnemies)) { dodgeSm.afterPerfectDodgeTimer.Complete(); } } if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName)) { return; } if (player.landMovementSc.isJumping) { if (!_canAirHeavyAttack || !functionSm["HeavyAttack"].IsAvailable()) { return; } if (PlayTargetedAnimation("AirAttackRStart")) { player.landMovementSc.ExtraJump(10f); comboSm.main.Reset(); functionSm["HeavyAttack"].Execute(); _canAirLightAttack = false; _canAirHeavyAttack = false; } return; } if (player.inputSc.IsHoldingSpecialA) { if (functionSm["DisruptionAttack"].IsAvailable()) { bool isEnhanced = _passionSystem.LevelIndex >= 3; string suffix = isEnhanced ? "B" : "A"; List disruptable = CombatManager.EnemySm.GetDisruptableEnemies(availableEnemies); Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies).ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy(); if (PlayTargetedAnimation("DisruptionAttack" + suffix, target)) { if (disruptable.Count > 0) { FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup") .Clip("Time"); float duration = fullBodyFuncAnimSm.collection["DisruptionAttack" + suffix] .Interval(IntervalType.Startup).Duration * 2; timeScaleModifierClip.duration = duration; player.feedbackSc.PlayFeedback("DisruptionStartup"); } if (isEnhanced) { _passionSystem.DecreasePassion(100f, false); } comboSm.main.Reset(); functionSm["DisruptionAttack"].Execute(); } } return; } if (functionSm["HeavyAttack"].IsAvailable()) { Enemy target = CombatManager.EnemySm.GetBestEnemy(availableEnemies); string nextNodeName = comboSm.main.GetNextNodeName("R"); bool keepAdsorption = nextNodeName is "RC"; if (PlayTargetedAnimation("Attack" + nextNodeName, target, 1f, keepAdsorption)) { float totalTime = fullBodyFuncAnimSm.GetIntervalScaledDuration(IntervalType.Startup) - 0.2f; CombatManager.EnemySm.activeEnemiesList.ForEach(enemy => { (enemy as Enemy)!.behaviorSc.DispatchContextEvent("PlayerHeavyAttack", totalTime); }); comboSm.main.NextCombo("R"); functionSm["HeavyAttack"].Execute(); } } } public override void OnSpecialCPress() { comboSm.main.Reset(); SetBlock(); if (!player.statusSm.HasStatus(StatusType.Stun)) { CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5); if (fullBodyFuncAnimSm.Stop(DisruptionType.ForcedAction)) { PlayTargetedAnimation("Block", target, 2f, false, true, upperBodyFuncAnimSm, 1f, 0.1f, true); } } } public override void OnSpecialCRelease() { if (upperBodyFuncAnimSm.currentRuntimeFuncAnim is { animationName: "Block" }) { upperBodyFuncAnimSm.Stop(DisruptionType.ForcedAction); } player.selfTimeSm.AddLocalTimer(0.04f, () => RemoveBlock()); } public override void OnSpecialBPress() { PlayTargetedAnimation("UltimateAttack"); } } public partial class Polychrome { private string _currentKatanaParticle; private void UpdateViewObjectVisuals() { if (_passionSystem == null) return; int level = _passionSystem.LevelIndex; // 开关粒子特效 if (level < 3) // C, B,A级 { if (_currentKatanaParticle != string.Empty) { GetParticle().Stop(); _currentKatanaParticle = string.Empty; } } else if (level <= 4) // S,SS级 (2) { if (_currentKatanaParticle != "ParticleStage0") { if (_currentKatanaParticle != string.Empty) { GetParticle().Stop(); } _currentKatanaParticle = "ParticleStage0"; GetParticle().Play(); } } else // SSS级及以上 { if (_currentKatanaParticle != "ParticleStage1") { if (_currentKatanaParticle != string.Empty) { GetParticle().Stop(); } _currentKatanaParticle = "ParticleStage1"; GetParticle().Play(); } } return; ParticleSystem GetParticle() { return viewObjects["Katana"].functionalParts.TryGetValue(_currentKatanaParticle, out GameObject particleObj) ? particleObj.GetComponent() : null; } } } public partial class Polychrome { public override Dictionary GetDescriptionArgs() { var args = new Dictionary(); if (attackData == null) return args; // TODO: 将下列 AttackUnit key 替换为 AttackData ScriptableObject 中的实际 key 名 TryPopulateAttack(args, "light", "ProbingAttack"); // TryPopulateAttack(args, "heavy", "HeavySlash"); // TryPopulateAttack(args, "disruption_a", "DisruptionA"); // TryPopulateAttack(args, "disruption_b", "DisruptionB"); // TryPopulateAttack(args, "disruption_c", "DisruptionC"); return args; } private void TryPopulateAttack(Dictionary args, string prefix, string unitKey) { if (attackData.attackUnits.TryGetValue(unitKey, out AttackUnit unit)) { DisplayTextResolver.PopulateAttackArgs(args, prefix, unit, player); } } } // ================================================================= // 以下为已废弃的 ExtraUIContainer 相关代码 / Deprecated ExtraUIContainer Codes // ================================================================= /* public partial class Polychrome { private PolychromeExtraUIContainer ExtraUIContainer => extraUIContainer as PolychromeExtraUIContainer; // OnEquipped: // extraUIContainer = Instantiate(extraUIContainerPrefab, PlayerCanvas.MainWeaponUIArea.transform).GetComponent(); // extraUIContainer.mainWeapon = this; // OnUnequipped: // Destroy(extraUIContainer.gameObject); // UpdateVisuals: // if (ExtraUIContainer != null) // { // ExtraUIContainer.SetStars(level); // } } */ }