Implement health modification on enemy kill; add HealOnKillModifier and update death behavior
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Data;
|
||||
using Interfaces;
|
||||
@@ -10,20 +11,50 @@ namespace Systems
|
||||
public class CharacterModifierManager : MonoBehaviour
|
||||
{
|
||||
[OdinSerialize] private List<IStatModifier> activeModifiers = new();
|
||||
[OdinSerialize] private List<IOnKillEffect> onKillEffects = new();
|
||||
|
||||
[SerializeField, Self] private Character character;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
EnemyDeathBehavior.OnAnyEnemyKilled += HandleEnemyKilled;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
EnemyDeathBehavior.OnAnyEnemyKilled -= HandleEnemyKilled;
|
||||
}
|
||||
|
||||
public void EquipItem(IStatModifier modifier)
|
||||
{
|
||||
activeModifiers.Add(modifier);
|
||||
modifier.Apply(character.attributes);
|
||||
|
||||
if (modifier is IOnKillEffect onKillEffect)
|
||||
{
|
||||
onKillEffects.Add(onKillEffect);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnequipItem(IStatModifier modifier)
|
||||
{
|
||||
if (activeModifiers.Remove(modifier))
|
||||
if (!activeModifiers.Remove(modifier)) return;
|
||||
|
||||
modifier.Remove(character.attributes);
|
||||
|
||||
if (modifier is IOnKillEffect onKillEffect)
|
||||
{
|
||||
modifier.Remove(character.attributes);
|
||||
onKillEffects.Remove(onKillEffect);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEnemyKilled(GameObject killer, GameObject victim)
|
||||
{
|
||||
if (killer != gameObject) return;
|
||||
|
||||
foreach (var effect in onKillEffects)
|
||||
{
|
||||
effect.OnKill(killer, victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Data;
|
||||
using Inventory;
|
||||
using KBCore.Refs;
|
||||
using Sirenix.Serialization;
|
||||
using UnityEngine;
|
||||
@@ -13,6 +15,9 @@ namespace Systems
|
||||
|
||||
[SerializeField] private IReadOnlyList<Weapon> EquippedWeapons => equippedWeapons.AsReadOnly();
|
||||
[SerializeField, Self] private Character character;
|
||||
|
||||
public event Action<Weapon> WeaponEquipped;
|
||||
public event Action<Weapon> WeaponUnequipped;
|
||||
|
||||
public Weapon EquipWeapon(GameObject weaponPrefab)
|
||||
{
|
||||
@@ -22,6 +27,7 @@ namespace Systems
|
||||
weapon.character = character;
|
||||
equippedWeapons.Add(weapon);
|
||||
weapon.enabled = true;
|
||||
WeaponEquipped?.Invoke(weapon);
|
||||
return weapon;
|
||||
}
|
||||
|
||||
@@ -33,6 +39,7 @@ namespace Systems
|
||||
{
|
||||
if (!equippedWeapons.Remove(weapon)) return;
|
||||
weapon.enabled = false;
|
||||
WeaponUnequipped?.Invoke(weapon);
|
||||
|
||||
if (!destroy) return;
|
||||
Destroy(weapon.gameObject);
|
||||
@@ -43,6 +50,7 @@ namespace Systems
|
||||
foreach (var weapon in equippedWeapons)
|
||||
{
|
||||
weapon.enabled = false;
|
||||
WeaponUnequipped?.Invoke(weapon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +59,7 @@ namespace Systems
|
||||
foreach (var weapon in equippedWeapons)
|
||||
{
|
||||
weapon.enabled = true;
|
||||
WeaponEquipped?.Invoke(weapon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +67,7 @@ namespace Systems
|
||||
{
|
||||
foreach (var weapon in equippedWeapons)
|
||||
{
|
||||
WeaponUnequipped?.Invoke(weapon);
|
||||
Destroy(weapon.gameObject);
|
||||
}
|
||||
equippedWeapons.Clear();
|
||||
|
@@ -9,6 +9,7 @@ namespace Systems
|
||||
{
|
||||
[Self, SerializeField] private Character character;
|
||||
[Self, SerializeField] private InterfaceRef<IDeathBehavior> deathBehavior;
|
||||
[Self, SerializeField] private Health health;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
@@ -30,7 +31,8 @@ namespace Systems
|
||||
|
||||
private void Die()
|
||||
{
|
||||
deathBehavior.Value.Die();
|
||||
var lastAttacker = health.LastAttacker;
|
||||
deathBehavior.Value.Die(lastAttacker);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Interfaces;
|
||||
using Sirenix.Serialization;
|
||||
using UnityEngine;
|
||||
@@ -6,13 +7,18 @@ namespace Systems
|
||||
{
|
||||
public class EnemyDeathBehavior : MonoBehaviour, IDeathBehavior
|
||||
{
|
||||
public static event Action<GameObject, GameObject> OnAnyEnemyKilled;
|
||||
|
||||
[OdinSerialize, SerializeField] private int expReward = 5;
|
||||
[OdinSerialize, SerializeField] private int coinReward = 1;
|
||||
|
||||
public void Die()
|
||||
public void Die(GameObject killer = null)
|
||||
{
|
||||
GameManager.Instance.Player.attributes.ModifyExperience(expReward);
|
||||
GameManager.Instance.AddCoins(coinReward);
|
||||
|
||||
OnAnyEnemyKilled?.Invoke(killer ?? GameManager.Instance.Player.gameObject, gameObject);
|
||||
|
||||
Destroy(gameObject);
|
||||
|
||||
// later let's add particle effects, sound effects, etc.
|
||||
|
30
Assets/Scripts/Systems/EnemyWeaponTargetSetter.cs
Normal file
30
Assets/Scripts/Systems/EnemyWeaponTargetSetter.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Weapons;
|
||||
|
||||
namespace Systems
|
||||
{
|
||||
public class EnemyWeaponTargetSetter : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private List<AutoWeapon> weapons = new();
|
||||
[SerializeField] private Transform target;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
if (weapons.Count == 0)
|
||||
{
|
||||
weapons = new List<AutoWeapon>(GetComponentsInChildren<AutoWeapon>());
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!target || weapons.Count == 0) return;
|
||||
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
weapon.Target = target.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Scripts/Systems/EnemyWeaponTargetSetter.cs.meta
Normal file
3
Assets/Scripts/Systems/EnemyWeaponTargetSetter.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5523bce9a0d94d6fafb3fc09e3bf9cc6
|
||||
timeCreated: 1752316561
|
@@ -7,16 +7,21 @@ namespace Systems
|
||||
{
|
||||
public class Health : MonoBehaviour
|
||||
{
|
||||
private GameObject lastAttacker;
|
||||
|
||||
[Self, SerializeField] private Character character;
|
||||
[SerializeField] private float initialHealth = 100f;
|
||||
|
||||
public GameObject LastAttacker => lastAttacker;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
character.attributes.SetHealth(initialHealth);
|
||||
}
|
||||
|
||||
public void TakeDamage(float damage)
|
||||
public void TakeDamage(float damage, GameObject attacker = null)
|
||||
{
|
||||
lastAttacker = attacker;
|
||||
var effectiveDamage = Math.Max(damage - character.attributes.Armor, 1);
|
||||
character.attributes.ModifyHealth(-effectiveDamage);
|
||||
}
|
||||
|
@@ -12,6 +12,9 @@ namespace Systems
|
||||
[SerializeField, Self] private Inventory.Inventory inventory;
|
||||
[SerializeField, Self] private CharacterModifierManager characterModifierManager;
|
||||
[SerializeField, Self] private CharacterWeaponsManager characterWeaponsManager;
|
||||
|
||||
public event Action<StatModifierItem> ItemEquipped;
|
||||
public event Action<StatModifierItem> ItemUnequipped;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
@@ -42,6 +45,7 @@ namespace Systems
|
||||
inventory.AddItem(item);
|
||||
foreach (var cure in item.cures) characterModifierManager.EquipItem(cure);
|
||||
foreach (var curse in item.curses) characterModifierManager.EquipItem(curse);
|
||||
ItemEquipped?.Invoke(item);
|
||||
}
|
||||
|
||||
public void UnequipItem(StatModifierItem item)
|
||||
@@ -51,6 +55,7 @@ namespace Systems
|
||||
|
||||
foreach (var cure in item.cures) characterModifierManager.UnequipItem(cure);
|
||||
foreach (var curse in item.curses) characterModifierManager.UnequipItem(curse);
|
||||
ItemUnequipped?.Invoke(item);
|
||||
}
|
||||
|
||||
public void EquipWeapon(WeaponItem weaponItem)
|
||||
|
@@ -6,7 +6,7 @@ namespace Systems
|
||||
{
|
||||
public class PlayerDeathBehavior : MonoBehaviour, IDeathBehavior
|
||||
{
|
||||
public void Die()
|
||||
public void Die(GameObject killer = null)
|
||||
{
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
|
||||
}
|
||||
|
71
Assets/Scripts/Systems/PlayerWeaponTargetSetter.cs
Normal file
71
Assets/Scripts/Systems/PlayerWeaponTargetSetter.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using Inventory;
|
||||
using KBCore.Refs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Weapons;
|
||||
|
||||
namespace Systems
|
||||
{
|
||||
public class PlayerWeaponTargetSetter : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Scene] private Camera mainCamera;
|
||||
[SerializeField] private List<AutoWeapon> weapons = new();
|
||||
[Self, SerializeField] private CharacterWeaponsManager weaponsManager;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
weaponsManager.WeaponEquipped += OnWeaponEquipped;
|
||||
weaponsManager.WeaponUnequipped += OnWeaponUnequipped;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
weaponsManager.WeaponEquipped -= OnWeaponEquipped;
|
||||
weaponsManager.WeaponUnequipped -= OnWeaponUnequipped;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
if (!mainCamera) mainCamera = Camera.main;
|
||||
if (weapons == null || weapons.Count == 0)
|
||||
{
|
||||
weapons = new List<AutoWeapon>(GetComponentsInChildren<AutoWeapon>());
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!mainCamera || weapons.Count == 0) return;
|
||||
|
||||
var mouseScreen = Mouse.current.position.ReadValue();
|
||||
var mouseWorld = mainCamera.ScreenToWorldPoint(mouseScreen);
|
||||
mouseWorld.z = 0f;
|
||||
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
weapon.Target = mouseWorld;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWeaponEquipped(Weapon weapon)
|
||||
{
|
||||
if (!weapon || weapon is not AutoWeapon autoWeapon) return;
|
||||
|
||||
if (autoWeapon && !weapons.Contains(autoWeapon))
|
||||
{
|
||||
weapons.Add(autoWeapon);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWeaponUnequipped(Weapon weapon)
|
||||
{
|
||||
if (!weapon || weapon is not AutoWeapon autoWeapon) return;
|
||||
|
||||
if (autoWeapon && weapons.Contains(autoWeapon))
|
||||
{
|
||||
weapons.Remove(autoWeapon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Scripts/Systems/PlayerWeaponTargetSetter.cs.meta
Normal file
3
Assets/Scripts/Systems/PlayerWeaponTargetSetter.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f973da80e1dd49c8a9efdc270992b705
|
||||
timeCreated: 1752316388
|
Reference in New Issue
Block a user