using UnityEngine;
// Sci-Fi Ship Controller. Copyright (c) 2018-2023 SCSM Pty Ltd. All rights reserved.
namespace SciFiShipController
{
///
/// Simple component that can be added to any non-SSC object to make it targetable (visible on radar).
/// For a more comprehensive solution, see DestructibleObjectModule.
///
[AddComponentMenu("Sci-Fi Ship Controller/Object Components/Targetable")]
[DisallowMultipleComponent]
[HelpURL("http://scsmmedia.com/ssc-documentation")]
public class SSCTargetable : MonoBehaviour
{
#region Public Variables
public bool initialiseOnStart = false;
[Tooltip("How much health the object has initially")]
public float startingHealth = 100f;
[Tooltip("Should the object be destroyed if health falls to 0?")]
public bool destroyOnNoHealth = true;
[Tooltip("When first initialised, should this object be visible to radar?")]
public bool isVisibleToRadarOnStart = true;
[Tooltip("The relative size of the blip on the radar mini-map. Must be between 1 and 5 inclusive.")]
[Range(1, 5)] public byte radarBlipSize = 1;
///
/// The faction or alliance the object belongs to. This can be used to identify if a object is friend or foe. Neutral = 0.
///
[SerializeField] private int factionId = 0;
///
/// Although normally representing a squadron of ships, this can be used on a gameobjects to group it with other things in your scene
///
[SerializeField] private int squadronId = -1;
#endregion
#region Public Properties
///
/// The current health value of this object.
///
public float Health
{
get { return health; }
set
{
// Update the health value
health = value < 0f ? 0f : value;
if (isInitialised && health == 0f && destroyOnNoHealth)
{
Destroy(gameObject);
}
}
}
///
/// [READONLY]
/// Normalised (0.0 – 1.0) value of the health of the object.
///
public float HealthNormalised
{
get
{
float _healthN = startingHealth == 0f ? 0f : health / startingHealth;
if (_healthN > 1f) { return 1f; }
else if (_healthN < 0f) { return 0f; }
else { return _healthN; }
}
}
///
/// [READONLY] Has the module been initialised?
///
public bool IsInitialised { get { return isInitialised; } }
///
/// [READONLY] The number used by the SSCRadar system to identify this object at a point in time.
/// This should not be stored across frames and is updated as required by the system.
///
public int RadarId { get { return radarItemIndex; } }
#endregion
#region Private Variables
private bool isInitialised = false;
private DamageReceiver damageReceiver = null;
private SSCRadar sscRadar = null;
private bool isRadarEnabled = false;
private float health = 0f;
private int radarItemIndex = -1;
#endregion
#region Initialisation Methods
// Start is called before the first frame update
void Start()
{
if (initialiseOnStart) { Initialise(); }
}
#endregion
#region Events
private void OnDestroy()
{
EnableOrDisableRadar(false);
}
#endregion
#region Private Methods
///
/// Add or remove this gameobject from radar.
///
///
private void EnableOrDisableRadar(bool isEnabled)
{
if (isEnabled)
{
if (isInitialised && radarItemIndex == -1)
{
// Create as a RadarItemType.GameObject
if (sscRadar == null) { sscRadar = SSCRadar.GetOrCreateRadar(); }
if (sscRadar != null) { radarItemIndex = sscRadar.EnableRadar(gameObject, transform.position, factionId, squadronId, 0, radarBlipSize); }
isRadarEnabled = radarItemIndex >= 0;
}
}
else
{
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
{
sscRadar.DisableRadar(radarItemIndex);
}
isRadarEnabled = false;
}
}
#endregion
#region Public Virtual and Protected API Methods
///
/// Add health to the object. To incur damage use the ApplyDamage(..).
///
///
public virtual void AddHealth (float healthAmount)
{
if (healthAmount > 0f)
{
if (health < 0f) { health = healthAmount; }
else { health += healthAmount; }
if (health > startingHealth)
{
// Cap health to maximum permitted
health = startingHealth;
}
}
}
///
/// Apply damage to the object.
///
///
public virtual void ApplyDamage (float damageAmount)
{
if (damageAmount > 0f)
{
// Reduce health of object itself
Health -= damageAmount;
}
}
///
/// This routine is called by our damage receiver when a projectile or beam hits our object
///
///
public virtual void ApplyDamage (CallbackOnObjectHitParameters callbackOnObjectHitParameters)
{
if (callbackOnObjectHitParameters.hitInfo.transform != null)
{
ProjectileModule projectile = callbackOnObjectHitParameters.projectilePrefab;
if (projectile != null)
{
ApplyDamage(projectile.damageAmount);
}
// Should have been a beam weapon that fired at the object
else
{
BeamModule beam = callbackOnObjectHitParameters.beamPrefab;
if (beam != null)
{
ApplyDamage(callbackOnObjectHitParameters.damageAmount);
}
else
{
// if we don't need to know what hit the object, simply reduce the health
ApplyDamage(callbackOnObjectHitParameters.damageAmount);
}
}
}
}
///
/// Initialises the SSCTargetable. If you wish to override this in a child (inherited)
/// class you almost always will want to call the base method first.
/// public override void Initialise()
/// {
/// base.Initialise();
/// // Do stuff here
/// }
///
public virtual void Initialise()
{
if (!isInitialised)
{
// Make sure this is NOT a ship or surface turret
ShipControlModule shipControlModule = GetComponent();
SurfaceTurretModule surfaceTurretModule = GetComponent();
DestructibleObjectModule destructibleObjectModule = GetComponent();
if (shipControlModule != null)
{
#if UNITY_EDITOR
Debug.LogWarning("ERROR: SSCTargetable.Initialise() - this component is not compatible with ships. Instead, use Identification on the Combat tab of " + name);
#endif
}
else if (surfaceTurretModule != null)
{
#if UNITY_EDITOR
Debug.LogWarning("ERROR: SSCTargetable.Initialise() - this component is not compatible with surface turrrets. Instead, use Is Visible to Radar on the Surface Turret Module of " + name);
#endif
}
else if (destructibleObjectModule != null)
{
#if UNITY_EDITOR
Debug.LogWarning("ERROR: SSCTargetable.Initialise() - this component is not compatible with DestructibleObjectModule. Instead, use Visible to Radar on the DestructibleObjectModule of " + name);
#endif
}
else
{
damageReceiver = GetComponent();
sscRadar = SSCRadar.GetOrCreateRadar();
if (damageReceiver == null) { damageReceiver = gameObject.AddComponent(); }
if (damageReceiver == null)
{
#if UNITY_EDITOR
Debug.LogWarning("ERROR: SSCTargetable.Initialise() - could not find or add DamageReceiver component to " + name);
#endif
}
else
{
health = startingHealth;
// Get notified when we take damage
damageReceiver.callbackOnHit = ApplyDamage;
EnableOrDisableRadar(isVisibleToRadarOnStart);
isInitialised = true;
}
}
}
}
#endregion
#region Public API Methods
///
/// Disable radar for this object. If you want to change the visibility to other radar consumers,
/// consider calling SetRadarVisibility(..) rather than disabling the radar and (later)
/// calling EnableRadar() again. This will be automatically called by when the object is destroyed.
///
public void DisableRadar()
{
EnableOrDisableRadar(false);
}
// Enable radar for this object. It will be visible on radar to others in the scene.
public void EnableRadar()
{
EnableOrDisableRadar(true);
}
///
/// Reset the health of the object back to initial values
///
public void ResetHealth()
{
// Reset health value for the object
health = startingHealth;
}
///
/// If radar is enabled for this object, set its visibility to radar.
///
///
public void SetRadarVisibility(bool isVisible)
{
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
{
sscRadar.SetVisibility(radarItemIndex, isVisible);
}
}
///
/// Set the Squadron Id for the object. If radar is enabled, this will also update the radar.
///
///
public void SetSquadronId(int newSquadronId)
{
if (squadronId != newSquadronId)
{
squadronId = newSquadronId;
// Do we need to update the radar item?
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
{
sscRadar.SetSquardronId(radarItemIndex, squadronId);
}
}
}
///
/// Set the Faction Id for the object. If radar is enabled, this will also update the radar.
///
///
public void SetFactionId(int newFactionId)
{
if (factionId != newFactionId)
{
factionId = newFactionId;
// Do we need to update the radar item?
if (isInitialised && isRadarEnabled && radarItemIndex >= 0)
{
sscRadar.SetFactionId(radarItemIndex, factionId);
}
}
}
#endregion
}
}