projectEli/Assets/NeoFPS/Core/Damage/ShieldPickup.cs
2022-11-06 20:28:33 -05:00

183 lines
6.4 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using NeoSaveGames.Serialization;
using NeoSaveGames;
namespace NeoFPS
{
[HelpURL("https://docs.neofps.com/manual/healthref-mb-shieldpickup.html")]
[RequireComponent(typeof(AudioSource))]
public class ShieldPickup : MonoBehaviour, IPickup, INeoSerializableComponent
{
[SerializeField, Tooltip("The number of shield steps to recharge.")]
private int m_StepCount = 1;
[SerializeField, Tooltip("An event called when the pickup heals a character.")]
private UnityEvent m_OnShieldsRecharged = null;
[SerializeField, Tooltip("If the character needs less recharging than the pickup amount, should the pickup still be destroyed or should the remainder be available to use again?")]
private bool m_SingleUse = true;
[SerializeField, Tooltip("What to do to the pickup object once its item has been used (fully, or single use).")]
private ConsumeResult m_ConsumeResult = ConsumeResult.Destroy;
[SerializeField, Tooltip("How long to wait before respawning if the consume result is set to \"Respawn\".")]
private float m_RespawnDuration = 20f;
[SerializeField, Tooltip("The display mesh of the pickup. This should not be the same game object as this, so that if this is disabled the pickup will still respawn if required.")]
private GameObject m_DisplayMesh = null;
private static readonly NeoSerializationKey k_RespawnKey = new NeoSerializationKey("respawn");
private static readonly NeoSerializationKey k_EnabledKey = new NeoSerializationKey("pickupEnabled");
private static readonly NeoSerializationKey k_RemainingKey = new NeoSerializationKey("remaining");
public enum ConsumeResult
{
Destroy,
Disable,
Respawn
}
private int m_Remaining = 0;
private AudioSource m_AudioSource = null;
private Collider m_Collider = null;
private IEnumerator m_DelayedSpawnCoroutine = null;
private float m_RespawnTimer = 0f;
private void OnValidate()
{
if (m_StepCount < 1)
m_StepCount = 1;
// Get the display mesh object
if (m_DisplayMesh == null)
{
var mesh = GetComponentInChildren<MeshRenderer>(true);
if (mesh != null && mesh.gameObject != gameObject)
m_DisplayMesh = mesh.gameObject;
}
}
void Awake()
{
m_Collider = GetComponent<Collider>();
m_AudioSource = GetComponent<AudioSource>();
EnablePickup(true);
}
public void Trigger(ICharacter character)
{
// Do nothing if character has no health manager
var shieldMgr = character.GetComponent<IShieldManager>();
if (shieldMgr == null)
return;
// Apply the shield
int consumed = shieldMgr.FillShieldSteps(m_Remaining);
// React based on amount consumed
if (consumed != 0)
{
// Fire event
m_OnShieldsRecharged.Invoke();
if (m_SingleUse)
{
DestroyPickup();
}
else
{
if (consumed < m_Remaining)
m_Remaining -= consumed;
else
DestroyPickup();
}
}
}
void DestroyPickup ()
{
if (m_DelayedSpawnCoroutine != null)
StopCoroutine(m_DelayedSpawnCoroutine);
// NB: The item will have been moved into the inventory heirarchy
switch (m_ConsumeResult)
{
case ConsumeResult.Destroy:
if (m_AudioSource.clip != null)
AudioSource.PlayClipAtPoint(m_AudioSource.clip, transform.position);
Destroy(gameObject);
break;
case ConsumeResult.Disable:
m_AudioSource.Play();
EnablePickup(false);
break;
case ConsumeResult.Respawn:
m_AudioSource.Play();
EnablePickup(false);
m_RespawnTimer = m_RespawnDuration;
m_DelayedSpawnCoroutine = DelayedSpawn();
StartCoroutine(m_DelayedSpawnCoroutine);
break;
}
}
public virtual void EnablePickup(bool value)
{
// Enable the mesh
if (m_DisplayMesh != null)
m_DisplayMesh.SetActive(value);
// Enable the collider
m_Collider.enabled = value;
// Reset the recharge amount to full
m_Remaining = m_StepCount;
}
IEnumerator DelayedSpawn()
{
while (m_RespawnTimer > 0f)
{
yield return null;
m_RespawnTimer -= Time.deltaTime;
}
EnablePickup(true);
m_DelayedSpawnCoroutine = null;
}
public void WriteProperties(INeoSerializer writer, NeoSerializedGameObject nsgo, SaveMode saveMode)
{
if (m_DelayedSpawnCoroutine != null)
writer.WriteValue(k_RespawnKey, m_RespawnTimer);
if (!m_Collider.enabled)
writer.WriteValue(k_EnabledKey, false);
if (m_Remaining != m_StepCount)
writer.WriteValue(k_RemainingKey, m_Remaining);
}
public void ReadProperties(INeoDeserializer reader, NeoSerializedGameObject nsgo)
{
// Enable the pickup
bool pickupEnabled = true;
reader.TryReadValue(k_EnabledKey, out pickupEnabled, true);
EnablePickup(pickupEnabled);
// Respawn timer (start the coroutine if the property is found)
float respawn = 0f;
if (reader.TryReadValue(k_RespawnKey, out respawn, 0f))
{
m_RespawnTimer = respawn;
m_DelayedSpawnCoroutine = DelayedSpawn();
StartCoroutine(m_DelayedSpawnCoroutine);
}
// Remaining heal
reader.TryReadValue(k_RemainingKey, out m_Remaining, m_Remaining);
}
}
}