r2mods/ilspy_dump/ror2_csproj/RoR2.Projectile/ProjectileExplosion.cs

262 lines
8.1 KiB
C#

using System;
using HG;
using UnityEngine;
using UnityEngine.Networking;
namespace RoR2.Projectile;
[RequireComponent(typeof(ProjectileController))]
public class ProjectileExplosion : MonoBehaviour
{
protected ProjectileController projectileController;
protected ProjectileDamage projectileDamage;
protected bool alive = true;
[Header("Main Properties")]
public BlastAttack.FalloffModel falloffModel = BlastAttack.FalloffModel.Linear;
public float blastRadius;
[Tooltip("The percentage of the damage, proc coefficient, and force of the initial projectile. Ranges from 0-1")]
public float blastDamageCoefficient;
public float blastProcCoefficient = 1f;
public AttackerFiltering blastAttackerFiltering;
public Vector3 bonusBlastForce;
public bool canRejectForce = true;
public HealthComponent projectileHealthComponent;
public GameObject explosionEffect;
[Obsolete("This sound will not play over the network. Provide the sound via the prefab referenced by explosionEffect instead.", false)]
[ShowFieldObsolete]
[Tooltip("This sound will not play over the network. Provide the sound via the prefab referenced by explosionEffect instead.")]
public string explosionSoundString;
[Header("Child Properties")]
[Tooltip("Does this projectile release children on death?")]
public bool fireChildren;
public GameObject childrenProjectilePrefab;
public int childrenCount;
[Tooltip("What percentage of our damage does the children get?")]
public float childrenDamageCoefficient;
[ShowFieldObsolete]
[Tooltip("How to randomize the orientation of children")]
public Vector3 minAngleOffset;
[ShowFieldObsolete]
public Vector3 maxAngleOffset;
public float minRollDegrees;
public float rangeRollDegrees;
public float minPitchDegrees;
public float rangePitchDegrees;
[Tooltip("useLocalSpaceForChildren is unused by ProjectileImpactExplosion")]
public bool useLocalSpaceForChildren;
[Tooltip("If true, applies a DoT given the following properties")]
[Header("DoT Properties")]
public bool applyDot;
public DotController.DotIndex dotIndex = DotController.DotIndex.None;
[Tooltip("Duration in seconds of the DoT. Unused if calculateTotalDamage is true.")]
public float dotDuration;
[Tooltip("Multiplier on the per-tick damage")]
public float dotDamageMultiplier = 1f;
[Tooltip("If true, we cap the numer of DoT stacks for this attacker.")]
public bool applyMaxStacksFromAttacker;
[Tooltip("The maximum number of stacks that we can apply for this attacker")]
public uint maxStacksFromAttacker = uint.MaxValue;
[Tooltip("If true, we disregard the duration and instead specify the total damage.")]
public bool calculateTotalDamage;
[Tooltip("totalDamage = totalDamageMultiplier * attacker's damage")]
public float totalDamageMultiplier;
protected virtual void Awake()
{
projectileController = GetComponent<ProjectileController>();
projectileDamage = GetComponent<ProjectileDamage>();
}
public void Detonate()
{
if (NetworkServer.active)
{
DetonateServer();
}
UnityEngine.Object.Destroy(base.gameObject);
}
protected void DetonateServer()
{
if ((bool)explosionEffect)
{
EffectManager.SpawnEffect(explosionEffect, new EffectData
{
origin = base.transform.position,
scale = blastRadius
}, transmit: true);
}
if ((bool)projectileDamage)
{
BlastAttack blastAttack = new BlastAttack();
blastAttack.position = base.transform.position;
blastAttack.baseDamage = projectileDamage.damage * blastDamageCoefficient;
blastAttack.baseForce = projectileDamage.force * blastDamageCoefficient;
blastAttack.radius = blastRadius;
blastAttack.attacker = (projectileController.owner ? projectileController.owner.gameObject : null);
blastAttack.inflictor = base.gameObject;
blastAttack.teamIndex = projectileController.teamFilter.teamIndex;
blastAttack.crit = projectileDamage.crit;
blastAttack.procChainMask = projectileController.procChainMask;
blastAttack.procCoefficient = projectileController.procCoefficient * blastProcCoefficient;
blastAttack.bonusForce = bonusBlastForce;
blastAttack.falloffModel = falloffModel;
blastAttack.damageColorIndex = projectileDamage.damageColorIndex;
blastAttack.damageType = projectileDamage.damageType;
blastAttack.attackerFiltering = blastAttackerFiltering;
blastAttack.canRejectForce = canRejectForce;
BlastAttack.Result result = blastAttack.Fire();
OnBlastAttackResult(blastAttack, result);
}
if (explosionSoundString.Length > 0)
{
Util.PlaySound(explosionSoundString, base.gameObject);
}
if (fireChildren)
{
for (int i = 0; i < childrenCount; i++)
{
FireChild();
}
}
}
protected Quaternion GetRandomChildRollPitch()
{
Quaternion quaternion = Quaternion.AngleAxis(minRollDegrees + UnityEngine.Random.Range(0f, rangeRollDegrees), Vector3.forward);
Quaternion quaternion2 = Quaternion.AngleAxis(minPitchDegrees + UnityEngine.Random.Range(0f, rangePitchDegrees), Vector3.left);
return quaternion * quaternion2;
}
protected virtual Quaternion GetRandomDirectionForChild()
{
Quaternion randomChildRollPitch = GetRandomChildRollPitch();
if (useLocalSpaceForChildren)
{
return base.transform.rotation * randomChildRollPitch;
}
return randomChildRollPitch;
}
protected void FireChild()
{
Quaternion randomDirectionForChild = GetRandomDirectionForChild();
GameObject obj = UnityEngine.Object.Instantiate(childrenProjectilePrefab, base.transform.position, randomDirectionForChild);
ProjectileController component = obj.GetComponent<ProjectileController>();
if ((bool)component)
{
component.procChainMask = projectileController.procChainMask;
component.procCoefficient = projectileController.procCoefficient;
component.Networkowner = projectileController.owner;
}
obj.GetComponent<TeamFilter>().teamIndex = GetComponent<TeamFilter>().teamIndex;
ProjectileDamage component2 = obj.GetComponent<ProjectileDamage>();
if ((bool)component2)
{
component2.damage = projectileDamage.damage * childrenDamageCoefficient;
component2.crit = projectileDamage.crit;
component2.force = projectileDamage.force;
component2.damageColorIndex = projectileDamage.damageColorIndex;
}
NetworkServer.Spawn(obj);
}
public void SetExplosionRadius(float newRadius)
{
blastRadius = newRadius;
}
public void SetAlive(bool newAlive)
{
alive = newAlive;
}
public bool GetAlive()
{
if (!NetworkServer.active)
{
return false;
}
return alive;
}
protected virtual void OnValidate()
{
if (!Application.IsPlaying(this) && !string.IsNullOrEmpty(explosionSoundString))
{
Debug.LogWarningFormat(base.gameObject, "{0} ProjectileImpactExplosion component supplies a value in the explosionSoundString field. This will not play correctly over the network. Please move the sound to the explosion effect.", Util.GetGameObjectHierarchyName(base.gameObject));
}
}
protected virtual void OnBlastAttackResult(BlastAttack blastAttack, BlastAttack.Result result)
{
if (!applyDot)
{
return;
}
CharacterBody characterBody = blastAttack.attacker?.GetComponent<CharacterBody>();
BlastAttack.HitPoint[] hitPoints = result.hitPoints;
for (int i = 0; i < hitPoints.Length; i++)
{
BlastAttack.HitPoint hitPoint = hitPoints[i];
if ((bool)hitPoint.hurtBox && (bool)hitPoint.hurtBox.healthComponent)
{
InflictDotInfo inflictDotInfo = default(InflictDotInfo);
inflictDotInfo.victimObject = hitPoint.hurtBox.healthComponent.gameObject;
inflictDotInfo.attackerObject = blastAttack.attacker;
inflictDotInfo.dotIndex = dotIndex;
inflictDotInfo.damageMultiplier = dotDamageMultiplier;
InflictDotInfo dotInfo = inflictDotInfo;
if (calculateTotalDamage && (bool)characterBody)
{
dotInfo.totalDamage = characterBody.damage * totalDamageMultiplier;
}
else
{
dotInfo.duration = dotDuration;
}
if (applyMaxStacksFromAttacker)
{
dotInfo.maxStacksFromAttacker = maxStacksFromAttacker;
}
if ((bool)characterBody && (bool)characterBody.inventory)
{
StrengthenBurnUtils.CheckDotForUpgrade(characterBody.inventory, ref dotInfo);
}
DotController.InflictDot(ref dotInfo);
}
}
}
}