using System; using System.Collections.Generic; using System.Linq; using Cielonos.MainGame.Inventory; using Sirenix.OdinInspector; using SLSUtilities.General; using SLSUtilities.WwiseAssistance; using UnityEngine; namespace Cielonos.MainGame.Characters { public class BlockSubmodule : SubmoduleBase { public List blockSources; public bool canBlock; [ShowInInspector] public bool isBlocking => blockSources.Count > 0; [ShowInInspector] public bool isPerfectBlocking => blockSources.Any(source => source.hasPerfectBlock && source.isDuringPerfectBlock); public Timer afterPerfectBlockTimer; public CharacterBase perfectBlockedTarget; public Timer afterNormalBlockTimer; public CharacterBase normalBlockedTarget; public BlockSubmodule(ReactionSubcontroller owner) : base(owner) { blockSources = new List(); canBlock = true; this.afterPerfectBlockTimer = new Timer(1); this.afterPerfectBlockTimer.onComplete.Add(new PrioritizedAction(() => perfectBlockedTarget = null)); this.afterNormalBlockTimer = new Timer(1); this.afterPerfectBlockTimer.onComplete.Add(new PrioritizedAction(() => normalBlockedTarget = null)); } public void ApplyBlock(BlockSource source, bool refreshPerfect = false) { if (canBlock) { BlockSource existingSource = blockSources.Find(x => x.blockName == source.blockName); if (existingSource != null) { if (source.blockTime > existingSource.blockTime) { existingSource.blockTime = source.blockTime; } if (refreshPerfect && existingSource.hasPerfectBlock) { existingSource.isDuringPerfectBlock = true; existingSource.perfectTime = source.perfectTime; } return; } blockSources.AddByPriority(source); } } public void RemoveBlock(string sourceName) { blockSources.RemoveAll(source => source.blockName == sourceName); } public bool TryGetBlockSource(string sourceName, out BlockSource blockSource) { blockSource = blockSources.Find(source => source.blockName == sourceName); return blockSource != null; } public BlockSource GetBlockSource(string sourceName) { return blockSources.Find(source => source.blockName == sourceName); } public BlockSource GetCurrentBlockSource() { return blockSources.Count > 0 ? blockSources[0] : null; } public bool HaveBlockSource(string sourceName) { return blockSources.Any(source => source.blockName == sourceName); } public void Update() { if (isBlocking) { foreach (BlockSource source in blockSources) { source.blockTime -= owner.owner.selfTimeSm.DeltaTime; source.triggerTime -= owner.owner.selfTimeSm.DeltaTime; if (source.hasPerfectBlock) { source.perfectTime -= owner.owner.selfTimeSm.DeltaTime; if (source.perfectTime <= 0) { source.isDuringPerfectBlock = false; } } } blockSources.RemoveAll(source => source.blockTime <= 0); } afterPerfectBlockTimer.Update(owner.owner.selfTimeSm.DeltaTime); afterNormalBlockTimer.Update(owner.owner.selfTimeSm.DeltaTime); } } public class BlockSource : IPrioritized { public int Priority { get; private set; } public CharacterBase sourceCharacter; public ItemBase sourceItem; public string blockName; public bool hasPerfectBlock; public bool isDuringPerfectBlock; public float perfectTime; public float blockTime; public float blockBufferTime = 0.25f; public Breakthrough.Type perfectBlockType; public GameObject perfectBlockEffect; public uint perfectBlockSound; public Action onPerfectBlock; public Breakthrough.Type normalBlockType; public GameObject normalBlockEffect; public uint normalBlockSound; public Action onNormalBlock; public float triggerTime; public BlockSource(CharacterBase sourceCharacter, ItemBase sourceItem, BlockData data) { this.sourceCharacter = sourceCharacter; this.sourceItem = sourceItem; this.blockName = data.blockName; this.Priority = data.blockPriority; this.hasPerfectBlock = data.perfectTime > 0f; this.isDuringPerfectBlock = data.perfectTime > 0f; this.blockTime = data.defaultBlockTime; this.perfectTime = data.perfectTime; if (data.advancedBreakthroughSettings) { this.normalBlockType = data.normalBlockType; this.perfectBlockType = data.perfectBlockType; } else { this.normalBlockType = data.overallBlockType; this.perfectBlockType = data.overallBlockType; } this.perfectBlockEffect = data.perfectBlockEffect; this.perfectBlockSound = data.perfectBlockSound; this.normalBlockEffect = data.normalBlockEffect; this.normalBlockSound = data.normalBlockSound; this.triggerTime = 0.06f; } public void PerfectBlock(AttackAreaBase attackArea, Vector3 blockEffectPosition) { if(triggerTime > 0f) return; triggerTime = 0.04f; if (sourceItem != null) { AudioManager.Post(perfectBlockSound, sourceCharacter.gameObject); sourceItem.feedbackSc.PlayFeedback("PerfectBlock"); } VFXObject.Spawn(perfectBlockEffect, sourceCharacter, blockEffectPosition, Quaternion.identity); onPerfectBlock?.Invoke(attackArea); BlockSubmodule blockSm = sourceCharacter.reactionSc.blockSm; blockSm.perfectBlockedTarget = attackArea.creator; blockSm.afterPerfectBlockTimer.Reset(blockBufferTime + 0.25f); } public void NormalBlock(AttackAreaBase attackArea, Vector3 blockEffectPosition) { if (triggerTime > 0f) return; triggerTime = 0.04f; if (sourceItem != null) { AudioManager.Post(normalBlockSound, sourceCharacter.gameObject); sourceItem.feedbackSc.PlayFeedback("NormalBlock"); } VFXObject.Spawn(normalBlockEffect, sourceCharacter, blockEffectPosition, Quaternion.identity); onNormalBlock?.Invoke(attackArea); BlockSubmodule blockSm = sourceCharacter.reactionSc.blockSm; blockSm.normalBlockedTarget = attackArea.creator; blockSm.afterPerfectBlockTimer.Reset(blockBufferTime + 0.25f); } } }