using UnityEngine; using UnityEngine.Networking; namespace RoR2; [RequireComponent(typeof(VehicleSeat))] [RequireComponent(typeof(Rigidbody))] public class FireballVehicle : MonoBehaviour, ICameraStateProvider { [Header("Vehicle Parameters")] public float duration = 3f; public float initialSpeed = 120f; public float targetSpeed = 40f; public float acceleration = 20f; public float cameraLerpTime = 1f; [Header("Blast Parameters")] public bool detonateOnCollision; public GameObject explosionEffectPrefab; public float blastDamageCoefficient; public float blastRadius; public float blastForce; public BlastAttack.FalloffModel blastFalloffModel; public DamageTypeCombo blastDamageType; public Vector3 blastBonusForce; public float blastProcCoefficient; public string explosionSoundString; [Header("Overlap Parameters")] public float overlapDamageCoefficient; public float overlapProcCoefficient; public float overlapForce; public float overlapFireFrequency; public float overlapResetFrequency; public float overlapVehicleDurationBonusPerHit; public GameObject overlapHitEffectPrefab; private float age; private bool hasDetonatedServer; private VehicleSeat vehicleSeat; private Rigidbody rigidbody; private OverlapAttack overlapAttack; private float overlapFireAge; private float overlapResetAge; private void Awake() { vehicleSeat = GetComponent(); vehicleSeat.onPassengerEnter += OnPassengerEnter; vehicleSeat.onPassengerExit += OnPassengerExit; rigidbody = GetComponent(); } private void OnPassengerExit(GameObject passenger) { if (NetworkServer.active) { DetonateServer(); } foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList) { if (readOnlyInstances.target == passenger) { readOnlyInstances.SetOverrideCam(this, 0f); readOnlyInstances.SetOverrideCam(null, cameraLerpTime); } } } private void OnPassengerEnter(GameObject passenger) { if ((bool)vehicleSeat.currentPassengerInputBank) { Vector3 aimDirection = vehicleSeat.currentPassengerInputBank.aimDirection; rigidbody.rotation = Quaternion.LookRotation(aimDirection); rigidbody.velocity = aimDirection * initialSpeed; CharacterBody currentPassengerBody = vehicleSeat.currentPassengerBody; overlapAttack = new OverlapAttack { attacker = currentPassengerBody.gameObject, damage = overlapDamageCoefficient * currentPassengerBody.damage, pushAwayForce = overlapForce, isCrit = currentPassengerBody.RollCrit(), damageColorIndex = DamageColorIndex.Item, inflictor = base.gameObject, procChainMask = default(ProcChainMask), procCoefficient = overlapProcCoefficient, teamIndex = currentPassengerBody.teamComponent.teamIndex, hitBoxGroup = base.gameObject.GetComponent(), hitEffectPrefab = overlapHitEffectPrefab }; } } private void DetonateServer() { if (!hasDetonatedServer) { hasDetonatedServer = true; CharacterBody currentPassengerBody = vehicleSeat.currentPassengerBody; if ((bool)currentPassengerBody) { EffectData effectData = new EffectData { origin = base.transform.position, scale = blastRadius }; EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true); BlastAttack blastAttack = new BlastAttack(); blastAttack.attacker = currentPassengerBody.gameObject; blastAttack.baseDamage = blastDamageCoefficient * currentPassengerBody.damage; blastAttack.baseForce = blastForce; blastAttack.bonusForce = blastBonusForce; blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf; blastAttack.crit = currentPassengerBody.RollCrit(); blastAttack.damageColorIndex = DamageColorIndex.Item; blastAttack.damageType = blastDamageType; blastAttack.falloffModel = blastFalloffModel; blastAttack.inflictor = base.gameObject; blastAttack.position = base.transform.position; blastAttack.procChainMask = default(ProcChainMask); blastAttack.procCoefficient = blastProcCoefficient; blastAttack.radius = blastRadius; blastAttack.teamIndex = currentPassengerBody.teamComponent.teamIndex; blastAttack.Fire(); } Util.PlaySound(explosionSoundString, base.gameObject); Object.Destroy(base.gameObject); } } private void FixedUpdate() { if (!vehicleSeat || !vehicleSeat.currentPassengerInputBank) { return; } age += Time.fixedDeltaTime; overlapFireAge += Time.fixedDeltaTime; overlapResetAge += Time.fixedDeltaTime; if (NetworkServer.active) { if (overlapFireAge > 1f / overlapFireFrequency) { if (overlapAttack.Fire()) { age = Mathf.Max(0f, age - overlapVehicleDurationBonusPerHit); } overlapFireAge = 0f; } if (overlapResetAge >= 1f / overlapResetFrequency) { overlapAttack.ResetIgnoredHealthComponents(); overlapResetAge = 0f; } } Ray aimRay = vehicleSeat.currentPassengerInputBank.GetAimRay(); aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var _); Vector3 velocity = rigidbody.velocity; Vector3 target = aimRay.direction * targetSpeed; Vector3 vector = Vector3.MoveTowards(velocity, target, acceleration * Time.fixedDeltaTime); rigidbody.MoveRotation(Quaternion.LookRotation(aimRay.direction)); rigidbody.AddForce(vector - velocity, ForceMode.VelocityChange); if (NetworkServer.active && duration <= age) { DetonateServer(); } } private void OnCollisionEnter(Collision collision) { if (detonateOnCollision && NetworkServer.active) { DetonateServer(); } } public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState) { } public bool IsUserLookAllowed(CameraRigController cameraRigController) { return true; } public bool IsUserControlAllowed(CameraRigController cameraRigController) { return true; } public bool IsHudAllowed(CameraRigController cameraRigController) { return true; } }