259 lines
6.9 KiB
C#
259 lines
6.9 KiB
C#
|
using System.Linq;
|
||
|
using RoR2;
|
||
|
using RoR2.Projectile;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace EntityStates.AcidLarva;
|
||
|
|
||
|
public class LarvaLeap : BaseCharacterMain
|
||
|
{
|
||
|
[SerializeField]
|
||
|
public float minimumDuration;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastRadius;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastProcCoefficient;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastDamageCoefficient;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float blastForce;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string leapSoundString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject projectilePrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public Vector3 blastBonusForce;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject blastImpactEffectPrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject blastEffectPrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float airControl;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float aimVelocity;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float upwardVelocity;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float forwardVelocity;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float minimumY;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float minYVelocityForAnim;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float maxYVelocityForAnim;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float knockbackForce;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float maxRadiusToConfirmDetonate;
|
||
|
|
||
|
[SerializeField]
|
||
|
public bool confirmDetonate;
|
||
|
|
||
|
[SerializeField]
|
||
|
public GameObject spinEffectPrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string spinEffectMuzzleString;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string soundLoopStartEvent;
|
||
|
|
||
|
[SerializeField]
|
||
|
public string soundLoopStopEvent;
|
||
|
|
||
|
[SerializeField]
|
||
|
public NetworkSoundEventDef landingSound;
|
||
|
|
||
|
[SerializeField]
|
||
|
public float detonateSelfDamageFraction;
|
||
|
|
||
|
private float previousAirControl;
|
||
|
|
||
|
private GameObject spinEffectInstance;
|
||
|
|
||
|
protected bool isCritAuthority;
|
||
|
|
||
|
protected CrocoDamageTypeController crocoDamageTypeController;
|
||
|
|
||
|
private bool detonateNextFrame;
|
||
|
|
||
|
private static int EmptyStateHash = Animator.StringToHash("Empty");
|
||
|
|
||
|
protected virtual DamageTypeCombo GetBlastDamageType()
|
||
|
{
|
||
|
return DamageType.Generic;
|
||
|
}
|
||
|
|
||
|
public override void OnEnter()
|
||
|
{
|
||
|
base.OnEnter();
|
||
|
previousAirControl = base.characterMotor.airControl;
|
||
|
base.characterMotor.airControl = airControl;
|
||
|
Vector3 direction = GetAimRay().direction;
|
||
|
if (base.isAuthority)
|
||
|
{
|
||
|
base.characterBody.isSprinting = true;
|
||
|
direction.y = Mathf.Max(direction.y, minimumY);
|
||
|
Vector3 vector = direction.normalized * aimVelocity * moveSpeedStat;
|
||
|
Vector3 vector2 = Vector3.up * upwardVelocity;
|
||
|
Vector3 vector3 = new Vector3(direction.x, 0f, direction.z).normalized * forwardVelocity;
|
||
|
base.characterMotor.Motor.ForceUnground();
|
||
|
base.characterMotor.velocity = vector + vector2 + vector3;
|
||
|
isCritAuthority = RollCrit();
|
||
|
}
|
||
|
PlayCrossfade("Gesture, Override", "LarvaLeap", 0.1f);
|
||
|
Util.PlaySound(leapSoundString, base.gameObject);
|
||
|
base.characterDirection.moveVector = direction;
|
||
|
spinEffectInstance = Object.Instantiate(spinEffectPrefab, FindModelChild(spinEffectMuzzleString));
|
||
|
if (base.isAuthority)
|
||
|
{
|
||
|
base.characterMotor.onMovementHit += OnMovementHit;
|
||
|
}
|
||
|
Util.PlaySound(soundLoopStartEvent, base.gameObject);
|
||
|
}
|
||
|
|
||
|
private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo)
|
||
|
{
|
||
|
detonateNextFrame = true;
|
||
|
}
|
||
|
|
||
|
protected override void UpdateAnimationParameters()
|
||
|
{
|
||
|
base.UpdateAnimationParameters();
|
||
|
}
|
||
|
|
||
|
public override void FixedUpdate()
|
||
|
{
|
||
|
base.FixedUpdate();
|
||
|
if (!base.isAuthority || !base.characterMotor)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
base.characterMotor.moveDirection = base.inputBank.moveVector;
|
||
|
base.characterDirection.moveVector = base.characterMotor.velocity;
|
||
|
base.characterMotor.disableAirControlUntilCollision = base.characterMotor.velocity.y < 0f;
|
||
|
if (base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround)))
|
||
|
{
|
||
|
bool flag = true;
|
||
|
if (confirmDetonate)
|
||
|
{
|
||
|
BullseyeSearch bullseyeSearch = new BullseyeSearch();
|
||
|
bullseyeSearch.viewer = base.characterBody;
|
||
|
bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
|
||
|
bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex);
|
||
|
bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
|
||
|
bullseyeSearch.minDistanceFilter = 0f;
|
||
|
bullseyeSearch.maxDistanceFilter = maxRadiusToConfirmDetonate;
|
||
|
bullseyeSearch.searchOrigin = base.inputBank.aimOrigin;
|
||
|
bullseyeSearch.searchDirection = base.inputBank.aimDirection;
|
||
|
bullseyeSearch.maxAngleFilter = 180f;
|
||
|
bullseyeSearch.filterByLoS = false;
|
||
|
bullseyeSearch.RefreshCandidates();
|
||
|
flag = bullseyeSearch.GetResults().FirstOrDefault();
|
||
|
}
|
||
|
if (flag)
|
||
|
{
|
||
|
DoImpactAuthority();
|
||
|
}
|
||
|
outer.SetNextStateToMain();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual void DoImpactAuthority()
|
||
|
{
|
||
|
DetonateAuthority();
|
||
|
if ((bool)landingSound)
|
||
|
{
|
||
|
EffectManager.SimpleSoundEffect(landingSound.index, base.characterBody.footPosition, transmit: true);
|
||
|
}
|
||
|
base.healthComponent.TakeDamage(new DamageInfo
|
||
|
{
|
||
|
damage = base.healthComponent.fullCombinedHealth * detonateSelfDamageFraction,
|
||
|
attacker = base.characterBody.gameObject,
|
||
|
position = base.characterBody.corePosition,
|
||
|
damageType = DamageType.Generic
|
||
|
});
|
||
|
}
|
||
|
|
||
|
protected BlastAttack.Result DetonateAuthority()
|
||
|
{
|
||
|
Vector3 footPosition = base.characterBody.footPosition;
|
||
|
EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
|
||
|
{
|
||
|
origin = footPosition,
|
||
|
scale = blastRadius
|
||
|
}, transmit: true);
|
||
|
return new BlastAttack
|
||
|
{
|
||
|
attacker = base.gameObject,
|
||
|
baseDamage = damageStat * blastDamageCoefficient,
|
||
|
baseForce = blastForce,
|
||
|
bonusForce = blastBonusForce,
|
||
|
crit = isCritAuthority,
|
||
|
damageType = GetBlastDamageType(),
|
||
|
falloffModel = BlastAttack.FalloffModel.None,
|
||
|
procCoefficient = blastProcCoefficient,
|
||
|
radius = blastRadius,
|
||
|
position = footPosition,
|
||
|
attackerFiltering = AttackerFiltering.NeverHitSelf,
|
||
|
impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
|
||
|
teamIndex = base.teamComponent.teamIndex
|
||
|
}.Fire();
|
||
|
}
|
||
|
|
||
|
protected void FireProjectile()
|
||
|
{
|
||
|
Vector3 footPosition = base.characterBody.footPosition;
|
||
|
FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
|
||
|
fireProjectileInfo.projectilePrefab = projectilePrefab;
|
||
|
fireProjectileInfo.crit = isCritAuthority;
|
||
|
fireProjectileInfo.force = 0f;
|
||
|
fireProjectileInfo.damage = damageStat;
|
||
|
fireProjectileInfo.owner = base.gameObject;
|
||
|
fireProjectileInfo.rotation = Quaternion.identity;
|
||
|
fireProjectileInfo.position = footPosition;
|
||
|
FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
|
||
|
ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
|
||
|
}
|
||
|
|
||
|
public override void OnExit()
|
||
|
{
|
||
|
Util.PlaySound(soundLoopStopEvent, base.gameObject);
|
||
|
if (base.isAuthority)
|
||
|
{
|
||
|
base.characterMotor.onMovementHit -= OnMovementHit;
|
||
|
}
|
||
|
base.characterMotor.airControl = previousAirControl;
|
||
|
base.characterBody.isSprinting = false;
|
||
|
if ((bool)spinEffectInstance)
|
||
|
{
|
||
|
EntityState.Destroy(spinEffectInstance);
|
||
|
}
|
||
|
PlayAnimation("Gesture, Override", EmptyStateHash);
|
||
|
base.OnExit();
|
||
|
}
|
||
|
|
||
|
public override InterruptPriority GetMinimumInterruptPriority()
|
||
|
{
|
||
|
return InterruptPriority.PrioritySkill;
|
||
|
}
|
||
|
}
|