using System.Collections; using System.Collections.Generic; using UnityEngine; using Sirenix.OdinInspector; using QFSW.MOP2; using KairoEngine.Core; using KairoEngine.Inventory; namespace KairoEngine.CharacterSystem { public class DamageController : MonoBehaviour { public CharacterController character; [SerializeField, ShowInInspector] private int hitPoints = 100; [SerializeField, ShowInInspector]private int maxHitPoints = 100; [SerializeField, ShowInInspector] private int armorPoints = 4; //public GameObject hitPrefab; public string hitFxName = "BloodSpillFx"; public int HP { get { return hitPoints; } } public int maxHP { get { return maxHitPoints; } } public int armor { get { return armorPoints; } } private List bulletHits = new List(); void Start() { if(HP <= 0) { character.Die(); DamageEvents.DeathEvent(this, null); } } public void OnCollisionEnter(Collision collision) { Vector3 point = collision.contacts[0].point; if (collision.gameObject.tag == "Bullet") { Bullet bullet = collision.gameObject.GetComponent(); Damage(bullet, point); } DamageEmitter damageEmitter = collision.gameObject.GetComponent(); if(damageEmitter != null) { if(damageEmitter.character != character && damageEmitter.enabled == true) { Damage(damageEmitter, point); } } } public void Damage(Bullet bullet, Vector3 point, DamagePoint damagePoint = null) { float damageMultiplier = 1f; if(damagePoint != null) damageMultiplier = damagePoint.damageMultiplier; // Don't damage the shooter if(bullet.character == character) return; // Each bullet only damages once for (int i = 0; i < bulletHits.Count; i++) { if(bulletHits[i] == bullet) return; } bulletHits.Add(bullet); StartCoroutine(Timer.Start(0.5f, false, () => { bulletHits.Remove(bullet); })); // Get firearm properties to calculate damage ItemBaseFirearm firearmItem = (ItemBaseFirearm)bullet.firearmRef.item; int firearmDamage = firearmItem.CalculateDamage(bullet.firearmRef, bullet.startPos, point); // Distance damage falloff calculation float travelDistance = Vector3.Distance(bullet.startPos, bullet.transform.position); if(travelDistance < firearmItem.minDistance) { firearmDamage = (int)((float)firearmDamage * 1.25f); } else if(travelDistance > firearmItem.halfDistance) { float modifier = ((firearmItem.maxDistance - firearmItem.halfDistance)/100) * (travelDistance - firearmItem.halfDistance); firearmDamage = (int)((float)firearmDamage - (float)firearmDamage * modifier); if(firearmDamage < 0) firearmDamage = 0; } else if(travelDistance > firearmItem.maxDistance) { firearmDamage = 0; } // Critical Hit calculation bool criticalHit = false; float roll = Random.Range(0, 100); if(roll <= firearmItem.criticalChanceModifier) criticalHit = true; // Calculate damage int armorPiercing = bullet.firearmRef.ammoType.armorPiercing; int damage = CalculateDamage(firearmDamage, armorPiercing); if(criticalHit) damage = damage * 2; damage = Mathf.FloorToInt(damage * damageMultiplier); // Remove hitpoints and start events //if(damage == 0) return; hitPoints -= damage; GameObject obj = bullet.character.gameObject; DamageData damageData = new DamageData(this, damagePoint, damage, obj, bullet.character, bullet, null, point, bullet.startPos, hitPoints <= 0); DamageEvents.DamageEvent(damageData); if(character != null) { character.Injury(); if(hitPoints <= 0) { character.Die(); DamageEvents.DeathEvent(this, bullet.character); } } SpawnHitFX(point); } public void Damage(DamageEmitter damageEmitter, Vector3 point, DamagePoint damagePoint = null) { int damage = CalculateDamage(damageEmitter.damage, damageEmitter.armorPiercing); hitPoints -= damage; GameObject obj = damageEmitter.character.gameObject; DamageData damageData = new DamageData(this, damagePoint, damage, obj, damageEmitter.character, null, damageEmitter, point, obj.transform.position, hitPoints <= 0); DamageEvents.DamageEvent(damageData); if(character != null) { character.Injury(); if(hitPoints <= 0) { character.Die(); if(damageEmitter.character != null) DamageEvents.DeathEvent(this, damageEmitter.character); } } SpawnHitFX(point); } private int CalculateDamage(int baseDamage, int armorPiercing) { int defense = armor - armorPiercing; if(defense < 0) defense = 0; int damage = baseDamage - defense; if(damage < 0) damage = 0; return damage; } private void SpawnHitFX(Vector3 position) { //if(hitPrefab == null) return; //var prefab = Instantiate(hitPrefab, position, transform.rotation) as GameObject; MasterObjectPooler.Instance.GetPool(hitFxName).GetObject(position, transform.rotation); } public void Heal(int value) { if(hitPoints + value < maxHitPoints) hitPoints += value; else { value = maxHitPoints - hitPoints; hitPoints = maxHitPoints; } DamageEvents.HealEvent(this, value); } public void SetHP(int value) => hitPoints = value; public void SetMaxHP(int value) => maxHitPoints = value; public void SetArmor(int value) => armorPoints = value; } }