using BehaviorDesigner.Runtime; using MoleMole.Config; using UnityEngine; namespace MoleMole { public class AbilityMirrorMixin : BaseAbilityMixin { private class MirrorData { public uint mirrorRuntimeID; public int mirrorSkillCount; public float mirrorLifetime; public bool destroyAheadActionTriggered; public void Reset() { mirrorRuntimeID = 0u; mirrorSkillCount = 0; mirrorLifetime = 0f; destroyAheadActionTriggered = false; } } private enum State { Idle = 0, SpawningMirrors = 1, MirrorActive = 2 } private MirrorMixin config; private int _mirrorAmount; private float _mirrorLifespan; private EntityTimer _delayTimer; private MirrorData[] _mirrorDatas; private int _curMirrorIx; private State _state; public AbilityMirrorMixin(ActorAbility instancedAbility, ActorModifier instancedModifier, ConfigAbilityMixin config) : base(instancedAbility, instancedModifier, config) { this.config = (MirrorMixin)config; _mirrorLifespan = instancedAbility.Evaluate(this.config.MirrorLastingTime); _mirrorAmount = instancedAbility.Evaluate(this.config.MirrorAmount); _delayTimer = new EntityTimer(this.config.DelayTime); _mirrorDatas = new MirrorData[_mirrorAmount]; for (int i = 0; i < _mirrorAmount; i++) { _mirrorDatas[i] = new MirrorData(); } _state = State.Idle; } public override void OnAdded() { _delayTimer.SetActive(false); _state = State.Idle; for (int i = 0; i < _mirrorDatas.Length; i++) { _mirrorDatas[i].Reset(); } Singleton.Instance.RegisterEventListener(actor.runtimeID); _curMirrorIx = 0; } public override void OnRemoved() { for (int i = 0; i < _mirrorDatas.Length; i++) { if (_mirrorDatas[i].mirrorRuntimeID != 0) { KillSingleMirror(i); } } Singleton.Instance.RemoveEventListener(actor.runtimeID); } public override bool ListenEvent(BaseEvent evt) { if (evt is EvtKilled) { return ListenKilled((EvtKilled)evt); } return false; } private bool ListenKilled(EvtKilled evt) { for (int i = 0; i < _mirrorDatas.Length; i++) { MirrorData mirrorData = _mirrorDatas[i]; if (mirrorData.mirrorRuntimeID == evt.targetID) { KillSingleMirror(i); return true; } } return false; } public override void OnAbilityTriggered(EvtAbilityStart evt) { if (_state == State.SpawningMirrors || _state == State.MirrorActive) { for (int i = 0; i < _mirrorDatas.Length; i++) { if (_mirrorDatas[i].mirrorRuntimeID != 0) { KillSingleMirror(i); } } } _state = State.SpawningMirrors; _curMirrorIx = 0; _delayTimer.SetActive(true); _mirrorLifespan = instancedAbility.Evaluate(config.MirrorLastingTime); if (config.ApplyAttackerWitchTimeRatio && evt.TriggerEvent != null) { EvtEvadeSuccess evtEvadeSuccess = evt.TriggerEvent as EvtEvadeSuccess; if (evtEvadeSuccess != null) { MonsterActor monsterActor = Singleton.Instance.GetActor(evtEvadeSuccess.attackerID); if (monsterActor != null) { ConfigMonsterAnimEvent configMonsterAnimEvent = SharedAnimEventData.ResolveAnimEvent(monsterActor.config, evtEvadeSuccess.skillID); if (configMonsterAnimEvent != null) { _mirrorLifespan *= configMonsterAnimEvent.AttackProperty.WitchTimeRatio; } } } } for (int j = 0; j < config.SelfModifiers.Length; j++) { actor.abilityPlugin.ApplyModifier(instancedAbility, config.SelfModifiers[j]); } } private void SpawnSingleMirror(int ix) { if (actor is AvatarActor) { uint mirrorRuntimeID = Singleton.Instance.CreateAvatarMirror((BaseMonoAvatar)entity, entity.XZPosition, entity.transform.forward, config.MirrorAIName, instancedAbility.Evaluate(config.HPRatioOfParent)); _mirrorDatas[ix].mirrorRuntimeID = mirrorRuntimeID; } else if (actor is MonsterActor) { uint mirrorRuntimeID2 = Singleton.Instance.CreateMonsterMirror((BaseMonoMonster)entity, entity.XZPosition, entity.transform.forward, config.MirrorAIName, instancedAbility.Evaluate(config.HPRatioOfParent)); _mirrorDatas[ix].mirrorRuntimeID = mirrorRuntimeID2; } BaseAbilityActor baseAbilityActor = Singleton.Instance.GetActor(_mirrorDatas[ix].mirrorRuntimeID); if (config.MirrorAbilities != null) { string[] mirrorAbilities = config.MirrorAbilities; foreach (string abilityName in mirrorAbilities) { if (string.IsNullOrEmpty(config.MirrorAbilitiesOverrideName)) { baseAbilityActor.abilityPlugin.AddAbility(AbilityData.GetAbilityConfig(abilityName)); } else { baseAbilityActor.abilityPlugin.AddAbility(AbilityData.GetAbilityConfig(abilityName, config.MirrorAbilitiesOverrideName)); } } } BehaviorTree component = baseAbilityActor.entity.GetComponent(); if (component != null) { component.SetVariableValue("MirrorCreationIndex", ix); } actor.abilityPlugin.HandleActionTargetDispatch(config.MirrorCreateActions, instancedAbility, instancedModifier, baseAbilityActor, null); } private void KillSingleMirror(int ix) { BaseAbilityActor baseAbilityActor = Singleton.Instance.GetActor(_mirrorDatas[ix].mirrorRuntimeID); if (!_mirrorDatas[ix].destroyAheadActionTriggered) { actor.abilityPlugin.HandleActionTargetDispatch(config.MirrorAheadDestroyActions, instancedAbility, instancedModifier, baseAbilityActor, null); } actor.abilityPlugin.HandleActionTargetDispatch(config.MirrorDestroyActions, instancedAbility, instancedModifier, baseAbilityActor, null); baseAbilityActor.isAlive = false; baseAbilityActor.entity.SetDied(KillEffect.KillImmediately); _mirrorDatas[ix].Reset(); } public override void Core() { if (_state == State.SpawningMirrors) { _delayTimer.Core(1f); if (_delayTimer.isTimeUp) { SpawnSingleMirror(_curMirrorIx); _curMirrorIx++; if (_curMirrorIx >= _mirrorAmount) { _state = State.MirrorActive; } else { _delayTimer.timespan = config.PerMirrorDelayTime; _delayTimer.Reset(true); } } } if (_state != State.SpawningMirrors && _state != State.MirrorActive) { return; } int num = 0; for (int i = 0; i < _mirrorAmount; i++) { if (_mirrorDatas[i].mirrorRuntimeID != 0) { num++; _mirrorDatas[i].mirrorLifetime += Time.deltaTime * entity.TimeScale; if (_mirrorDatas[i].mirrorLifetime > _mirrorLifespan) { KillSingleMirror(i); } else if (_mirrorDatas[i].mirrorLifetime > _mirrorLifespan - config.AheadTime && !_mirrorDatas[i].destroyAheadActionTriggered) { BaseAbilityActor other = Singleton.Instance.GetActor(_mirrorDatas[i].mirrorRuntimeID); actor.abilityPlugin.HandleActionTargetDispatch(config.MirrorAheadDestroyActions, instancedAbility, instancedModifier, other, null); _mirrorDatas[i].destroyAheadActionTriggered = true; } } } if (_state == State.MirrorActive && num == 0) { for (int j = 0; j < config.SelfModifiers.Length; j++) { actor.abilityPlugin.TryRemoveModifier(instancedAbility, config.SelfModifiers[j]); } _state = State.Idle; } } } }