437 lines
12 KiB
C#
437 lines
12 KiB
C#
|
using System.Collections.Generic;
|
||
|
using RoR2;
|
||
|
using RoR2.HudOverlay;
|
||
|
using RoR2.UI;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.UI;
|
||
|
|
||
|
namespace EntityStates.Seeker;
|
||
|
|
||
|
public class MeditationUI : BaseSkillState
|
||
|
{
|
||
|
[SerializeField]
|
||
|
[Header("UI")]
|
||
|
public GameObject scopeOverlayPrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float duration = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float timePenalty = 1f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float failureCooldownPenalty = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float animDuration;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float smallHopVelocity;
|
||
|
|
||
|
[SerializeField]
|
||
|
public Sprite primaryIcon;
|
||
|
|
||
|
[SerializeField]
|
||
|
public Sprite secondaryIcon;
|
||
|
|
||
|
[SerializeField]
|
||
|
public Sprite utilityIcon;
|
||
|
|
||
|
[SerializeField]
|
||
|
public Sprite specialIcon;
|
||
|
|
||
|
[SerializeField]
|
||
|
public SeekerController seekerController;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject lotusPrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float wrapUpDuration;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject successEffectPrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject crosshairOverridePrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string startSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string stopSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string timeoutSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string successSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string inputCorrectSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string inputFailSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
[Header("Healing Explosion")]
|
||
|
public float healingExplosionAmount = 10f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float healingOverShield = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastRadius = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float damageCoefficient = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastForce = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public Vector3 blastBonusForce;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastProcCoefficient = 5f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float percentPerGate = 0.75f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float overShieldPercent = 0.25f;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float startingOverShieldPercentage = 0.33f;
|
||
|
|
||
|
private CrosshairUtils.OverrideRequest crosshairOverrideRequest;
|
||
|
|
||
|
private GameObject lotus;
|
||
|
|
||
|
private OverlayController overlayController;
|
||
|
|
||
|
private bool meditationSuccess;
|
||
|
|
||
|
private ICharacterGravityParameterProvider characterGravityParameterProvider;
|
||
|
|
||
|
private ChildLocator overlayInstanceChildLocator;
|
||
|
|
||
|
private ChildLocator lotusChildLocator;
|
||
|
|
||
|
private List<ImageFillController> fillUiList = new List<ImageFillController>();
|
||
|
|
||
|
private CameraTargetParams.AimRequest aimRequest;
|
||
|
|
||
|
private bool spawnedLotus;
|
||
|
|
||
|
private bool failed;
|
||
|
|
||
|
private bool meditationWrapUp;
|
||
|
|
||
|
private bool wrapUpAnimationPlayed;
|
||
|
|
||
|
private float wrapUpTimer;
|
||
|
|
||
|
private float startingYaw;
|
||
|
|
||
|
private EntityStateMachine bodyStateMachine;
|
||
|
|
||
|
private float explosionHealingMod;
|
||
|
|
||
|
private bool upReady = true;
|
||
|
|
||
|
private bool downReady = true;
|
||
|
|
||
|
private bool rightReady = true;
|
||
|
|
||
|
private bool leftReady = true;
|
||
|
|
||
|
private static string[] c = new string[5] { "ArrowInput1", "ArrowInput2", "ArrowInput3", "ArrowInput4", "ArrowInput5" };
|
||
|
|
||
|
public override void OnEnter()
|
||
|
{
|
||
|
base.OnEnter();
|
||
|
EntityStateMachine[] components = base.characterBody.gameObject.GetComponents<EntityStateMachine>();
|
||
|
foreach (EntityStateMachine entityStateMachine in components)
|
||
|
{
|
||
|
if (entityStateMachine.customName == "Body")
|
||
|
{
|
||
|
bodyStateMachine = entityStateMachine;
|
||
|
}
|
||
|
}
|
||
|
bodyStateMachine.SetNextState(new Idle());
|
||
|
explosionHealingMod = base.characterBody.maxHealth;
|
||
|
if (explosionHealingMod < base.characterBody.baseMaxHealth)
|
||
|
{
|
||
|
explosionHealingMod = base.characterBody.baseMaxHealth;
|
||
|
}
|
||
|
base.healthComponent.AddBarrierAuthority(explosionHealingMod * startingOverShieldPercentage);
|
||
|
seekerController = base.characterBody.transform.GetComponent<SeekerController>();
|
||
|
if (base.isAuthority)
|
||
|
{
|
||
|
seekerController.RandomizeMeditationInputs();
|
||
|
}
|
||
|
SmallHop(base.characterMotor, smallHopVelocity);
|
||
|
if ((bool)base.characterMotor)
|
||
|
{
|
||
|
base.characterMotor.walkSpeedPenaltyCoefficient = 0f;
|
||
|
}
|
||
|
if ((bool)base.characterBody)
|
||
|
{
|
||
|
base.characterBody.isSprinting = false;
|
||
|
}
|
||
|
if ((bool)base.characterDirection)
|
||
|
{
|
||
|
base.characterDirection.moveVector = base.characterDirection.forward;
|
||
|
}
|
||
|
if ((bool)base.rigidbodyMotor)
|
||
|
{
|
||
|
base.rigidbodyMotor.moveVector = Vector3.zero;
|
||
|
}
|
||
|
PlayAnimation("FullBody, Override", "MeditationStart", "Meditation.playbackRate", animDuration);
|
||
|
characterGravityParameterProvider = base.gameObject.GetComponent<ICharacterGravityParameterProvider>();
|
||
|
if (characterGravityParameterProvider != null)
|
||
|
{
|
||
|
CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
|
||
|
gravityParameters.channeledAntiGravityGranterCount++;
|
||
|
characterGravityParameterProvider.gravityParameters = gravityParameters;
|
||
|
}
|
||
|
overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
|
||
|
{
|
||
|
prefab = scopeOverlayPrefab,
|
||
|
childLocatorEntry = "CrosshairExtras"
|
||
|
});
|
||
|
overlayController.onInstanceAdded += OnOverlayInstanceAdded;
|
||
|
overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
|
||
|
crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
|
||
|
CameraTargetParams component = base.gameObject.GetComponent<CameraTargetParams>();
|
||
|
if ((bool)component)
|
||
|
{
|
||
|
aimRequest = component.RequestAimType(CameraTargetParams.AimType.ZoomedOut);
|
||
|
}
|
||
|
startingYaw = base.characterDirection.yaw;
|
||
|
Util.PlaySound(startSoundString, base.gameObject);
|
||
|
}
|
||
|
|
||
|
public override void Update()
|
||
|
{
|
||
|
if (seekerController.meditationUIDirty)
|
||
|
{
|
||
|
seekerController.meditationUIDirty = false;
|
||
|
UpdateUIInputSequence();
|
||
|
}
|
||
|
base.characterDirection.yaw = startingYaw;
|
||
|
base.characterDirection.moveVector = base.characterDirection.forward;
|
||
|
base.Update();
|
||
|
if (meditationWrapUp)
|
||
|
{
|
||
|
wrapUpTimer += Time.deltaTime;
|
||
|
if (wrapUpTimer > wrapUpDuration)
|
||
|
{
|
||
|
outer.SetNextStateToMain();
|
||
|
}
|
||
|
if (!wrapUpAnimationPlayed)
|
||
|
{
|
||
|
wrapUpAnimationPlayed = true;
|
||
|
if (meditationSuccess)
|
||
|
{
|
||
|
PlayAnimation("FullBody, Override", "MeditationSuccess", "Meditation.playbackRate", animDuration);
|
||
|
Util.PlaySound(successSoundString, base.gameObject);
|
||
|
lotus.GetComponentInChildren<Animator>().Play("MeditationSuccess");
|
||
|
EffectManager.SpawnEffect(successEffectPrefab, new EffectData
|
||
|
{
|
||
|
origin = base.characterBody.corePosition
|
||
|
}, transmit: true);
|
||
|
if (base.isAuthority)
|
||
|
{
|
||
|
float num = 0f;
|
||
|
float num2 = 0f;
|
||
|
seekerController.IncrementChakraGate();
|
||
|
if (base.characterBody.HasBuff(DLC2Content.Buffs.ChakraBuff))
|
||
|
{
|
||
|
num2 = base.characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff);
|
||
|
num = num2 * percentPerGate;
|
||
|
}
|
||
|
seekerController.CallCmdTriggerHealPulse((healingExplosionAmount * num2 + 0.04f) * explosionHealingMod, base.characterBody.corePosition, blastRadius);
|
||
|
BlastAttack blastAttack = new BlastAttack();
|
||
|
blastAttack.attacker = base.characterBody.gameObject;
|
||
|
blastAttack.baseDamage = (damageCoefficient + num) * base.characterBody.damage;
|
||
|
blastAttack.baseForce = blastForce;
|
||
|
blastAttack.bonusForce = blastBonusForce;
|
||
|
blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
|
||
|
blastAttack.crit = base.characterBody.RollCrit();
|
||
|
blastAttack.damageColorIndex = DamageColorIndex.Item;
|
||
|
blastAttack.inflictor = base.gameObject;
|
||
|
blastAttack.position = base.characterBody.corePosition;
|
||
|
blastAttack.procChainMask = default(ProcChainMask);
|
||
|
blastAttack.procCoefficient = blastProcCoefficient;
|
||
|
blastAttack.radius = blastRadius;
|
||
|
blastAttack.falloffModel = BlastAttack.FalloffModel.None;
|
||
|
blastAttack.teamIndex = base.teamComponent.teamIndex;
|
||
|
blastAttack.Fire();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PlayAnimation("FullBody, Override", "MeditationFail", "Meditation.playbackRate", animDuration);
|
||
|
Util.PlaySound(timeoutSoundString, base.gameObject);
|
||
|
lotus.GetComponentInChildren<Animator>().Play("MeditationFail");
|
||
|
outer.SetNextStateToMain();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int num3 = -1;
|
||
|
if (base.inputBank.rawMoveUp.justPressed)
|
||
|
{
|
||
|
num3 = 0;
|
||
|
}
|
||
|
if (base.inputBank.rawMoveDown.justPressed)
|
||
|
{
|
||
|
num3 = 1;
|
||
|
}
|
||
|
if (base.inputBank.rawMoveRight.justPressed)
|
||
|
{
|
||
|
num3 = 2;
|
||
|
}
|
||
|
if (base.inputBank.rawMoveLeft.justPressed)
|
||
|
{
|
||
|
num3 = 3;
|
||
|
}
|
||
|
if (seekerController.meditationInputStep > 4)
|
||
|
{
|
||
|
meditationSuccess = true;
|
||
|
meditationWrapUp = true;
|
||
|
}
|
||
|
if (num3 == seekerController.GetNextMeditationStep())
|
||
|
{
|
||
|
if (!wrapUpAnimationPlayed && seekerController.meditationInputStep < 5)
|
||
|
{
|
||
|
Util.PlaySound(inputCorrectSoundString, base.gameObject);
|
||
|
seekerController.meditationInputStep++;
|
||
|
}
|
||
|
}
|
||
|
else if (num3 != -1)
|
||
|
{
|
||
|
Util.PlaySound(inputFailSoundString, base.gameObject);
|
||
|
base.fixedAge += timePenalty;
|
||
|
}
|
||
|
if (base.fixedAge > 0.4f)
|
||
|
{
|
||
|
base.characterMotor.velocity = new Vector3(0f, 0f, 0f);
|
||
|
if (base.inputBank.skill4.justPressed)
|
||
|
{
|
||
|
meditationWrapUp = true;
|
||
|
}
|
||
|
Transform modelTransform = GetModelTransform();
|
||
|
if ((bool)modelTransform && !spawnedLotus)
|
||
|
{
|
||
|
spawnedLotus = true;
|
||
|
lotusChildLocator = modelTransform.GetComponent<ChildLocator>();
|
||
|
lotus = Object.Instantiate(lotusPrefab, lotusChildLocator.FindChild("Lotus"), worldPositionStays: false);
|
||
|
}
|
||
|
}
|
||
|
if (base.fixedAge > duration)
|
||
|
{
|
||
|
failed = true;
|
||
|
meditationWrapUp = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UpdateUI();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void SetupInputUIIcons()
|
||
|
{
|
||
|
for (int i = 0; i < 5; i++)
|
||
|
{
|
||
|
switch (seekerController.meditationStepAndSequence[i + 1])
|
||
|
{
|
||
|
case 0:
|
||
|
overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = Quaternion.Euler(0f, 0f, 0f);
|
||
|
break;
|
||
|
case 1:
|
||
|
overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = Quaternion.Euler(0f, 0f, -180f);
|
||
|
break;
|
||
|
case 2:
|
||
|
overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = Quaternion.Euler(0f, 0f, -90f);
|
||
|
break;
|
||
|
case 3:
|
||
|
overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = Quaternion.Euler(0f, 0f, -270f);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
UpdateUIInputSequence();
|
||
|
}
|
||
|
|
||
|
private void UpdateUIInputSequence()
|
||
|
{
|
||
|
if (base.isAuthority)
|
||
|
{
|
||
|
Color32 color = new Color32(byte.MaxValue, 233, 124, byte.MaxValue);
|
||
|
for (int i = 0; i < seekerController.meditationInputStep; i++)
|
||
|
{
|
||
|
overlayInstanceChildLocator.FindChild(c[i]).GetComponent<Image>().color = color;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UpdateUI()
|
||
|
{
|
||
|
foreach (ImageFillController fillUi in fillUiList)
|
||
|
{
|
||
|
fillUi.SetTValue(base.fixedAge / duration);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void OnExit()
|
||
|
{
|
||
|
PlayAnimation("FullBody, Override", "Empty");
|
||
|
Util.PlaySound(stopSoundString, base.gameObject);
|
||
|
if (overlayController != null)
|
||
|
{
|
||
|
HudOverlayManager.RemoveOverlay(overlayController);
|
||
|
overlayController = null;
|
||
|
}
|
||
|
aimRequest?.Dispose();
|
||
|
crosshairOverrideRequest?.Dispose();
|
||
|
if (characterGravityParameterProvider != null)
|
||
|
{
|
||
|
CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
|
||
|
gravityParameters.channeledAntiGravityGranterCount--;
|
||
|
characterGravityParameterProvider.gravityParameters = gravityParameters;
|
||
|
}
|
||
|
if ((bool)base.characterMotor)
|
||
|
{
|
||
|
base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
|
||
|
}
|
||
|
if ((bool)lotus)
|
||
|
{
|
||
|
lotus.GetComponent<DestroyOnTimer>().duration = 0.01f;
|
||
|
}
|
||
|
if (failed)
|
||
|
{
|
||
|
base.skillLocator.special.temporaryCooldownPenalty += failureCooldownPenalty;
|
||
|
}
|
||
|
bodyStateMachine.SetNextStateToMain();
|
||
|
base.OnExit();
|
||
|
}
|
||
|
|
||
|
private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
|
||
|
{
|
||
|
fillUiList.Add(instance.GetComponent<ImageFillController>());
|
||
|
overlayInstanceChildLocator = instance.GetComponent<ChildLocator>();
|
||
|
SetupInputUIIcons();
|
||
|
}
|
||
|
|
||
|
private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
|
||
|
{
|
||
|
fillUiList.Remove(instance.GetComponent<ImageFillController>());
|
||
|
}
|
||
|
|
||
|
public override InterruptPriority GetMinimumInterruptPriority()
|
||
|
{
|
||
|
return InterruptPriority.PrioritySkill;
|
||
|
}
|
||
|
}
|