using System.Collections; using System.Collections.Generic; using UnityEngine; using RPGCreationKit.Player; namespace RPGCreationKit { public class SpellProjectile : MonoBehaviour { [HideInInspector] public Entity shooterEntity; bool shotByPlayer = false; public bool shot = false; bool hasCreatedItem = false; bool projectileHit = false; public Spell thisSpell; // Used when this spell projectile collides with something/someone public GameObject explosionEffect; [SerializeField] Rigidbody rb; [SerializeField] Collider physicalCollider; float damageAmount = 0f; Vector3 direction; /// /// General init function, it is overriden by Shoot() but needed for spells like Restoration as they never get Shoot called /// /// /// public void Init(Entity _shooterEntity, bool _shotByPlayer = false) { shooterEntity = _shooterEntity; shotByPlayer = _shotByPlayer; } /// /// Used by Spell Types: Projectile to shoot and travel in a direction /// /// /// /// public void Shoot(Entity _shooterEntity, Vector3 _direction, bool _shotByPlayer = false) { shooterEntity = _shooterEntity; shotByPlayer = _shotByPlayer; direction = _direction; if (rb == null) { rb = gameObject.AddComponent(); GetComponent().enabled = true; rb.isKinematic = true; } // Ignore collision with the shooter if(shotByPlayer) Physics.IgnoreCollision(physicalCollider, RckPlayer.instance.charController, true); else if(shooterEntity.GetComponent() != null) Physics.IgnoreCollision(physicalCollider, shooterEntity.GetComponent(), true); gameObject.SetLayer(RCKLayers.Default, true); rb.isKinematic = false; gameObject.transform.SetParent(null); shot = true; } private void Update() { if(shot && !projectileHit) { // Move the projectile rb.position += direction * thisSpell.speed * Time.deltaTime; } } private void OnCollisionEnter(Collision collision) { if (projectileHit || !shot) return; IHittable hittable = collision.gameObject.GetComponent(); IDamageable damageable = collision.gameObject.GetComponentInParent(); Entity entityHit = null; if(damageable != null) entityHit = damageable.GetEntity(); if (entityHit != null && entityHit == shooterEntity) { // AI hit itself, return return; } if (collision.transform.CompareTag("RPG Creation Kit/EntityShield")) { StickProjectile(collision); return; } if (hittable != null) { // Check for body // Check for BodyParts, with a single swing we can hit multiple bodyparts but we don't want to be able to hit the same enemy more than once. if (collision.transform.CompareTag("RPG Creation Kit/BodyPart")) { BodyPart bodyPart = collision.gameObject.GetComponent(); // Check if player shot himself if (shooterEntity == RckPlayer.GetPlayerEntity() && shotByPlayer && damageable == RckPlayer.instance.GetIDamageable()) return; // Check for damageable, body part should always be damageable if (damageable != null) { damageAmount = thisSpell.magnitude; LocationalDamage locDamage = bodyPart.GetComponentInParent(); if (locDamage != null) damageAmount = locDamage.CalculateLocationalDamage(bodyPart, damageAmount); DamageContext context = new DamageContext(damageAmount, shooterEntity, null, null, false, thisSpell); damageable.Damage(context); /* if (damageable.Bleeds()) damageable.InstantiateBlood(transform.position); */ EntityAttributes attributes = bodyPart.GetComponentInParent(); if (attributes != null && thisSpell.onTargetEffects.Length > 0) attributes.ExecuteEffects(thisSpell.onTargetEffects); } hittable.Hit(RckPlayer.instance.mainCamera.transform.forward, RCKSettings.MELEE_ONBODY_RIGIDBODY_FORCE); hittable.GenerateDecal(); StickProjectile(collision); } else // simple hit against an hittable { // Check for damageable if (damageable != null) { // Check if player shot himself if (shooterEntity == RckPlayer.GetPlayerEntity() && shotByPlayer && damageable == RckPlayer.instance.GetIDamageable()) return; damageAmount = thisSpell.magnitude; DamageContext context = new DamageContext(damageAmount, shooterEntity, null, null, false, thisSpell); damageable.Damage(context); /* if (damageable.Bleeds()) damageable.InstantiateBlood(transform.position); */ StickProjectile(collision); } else { StickProjectile(collision); } } hittable.Hit(transform.forward, RCKSettings.ARROW_ONBODY_RIGIDBODY_FORCE); hittable.GenerateDecal(); } if (hittable == null && damageable == null && !collision.gameObject.CompareTag("Player")) // If it hit a random object StickProjectile(collision); } public void StickProjectile(Collision coll) { projectileHit = true; // Stop the projectile gameObject.transform.SetParent(coll.transform); rb.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative; rb.isKinematic = true; physicalCollider.enabled = false; //transform.rotation = Quaternion.FromToRotation(Vector3.up, coll.contacts[0].point); // Push it trough objects Explode(); } public void Explode() { if (explosionEffect != null) { // Deatach from this object explosionEffect.transform.parent = transform.parent; explosionEffect.SetActive(true); // Destroy the projectile Destroy(gameObject); } } public void ExecuteOnCasterEffects() { EntityAttributes attr = null; if (shotByPlayer) attr = EntityAttributes.PlayerAttributes; else if(shooterEntity != null) attr = shooterEntity.GetComponent(); if (attr != null) { attr.ExecuteEffects(thisSpell.onCasterEffects); } } public void CastToTouch() { shot = true; } } }