using System.Collections; using Drawing; using Reset.Core; using Sirenix.OdinInspector; using UnityEngine; using Unity.Netcode; namespace Reset.Units{ public class Player : Unit, IKillable, IInteractable{ [HideInInspector] public PlayerControls controls; public float maxHealth{ get; set; } public float currentHealth{ get; set; } public NetworkVariable _isDowned; public bool IsDowned => _isDowned.Value; private float timeDowned; public GameObject pickupTarget; void Awake(){ controls = GetComponent(); maxHealth = 20f; } public void Attach(){ if (IsLocalPlayer || !UnitIsNetworked()) { // PlayerManager.Player = gameObject; PlayerManager.RequestNewController(); GetComponent().AttachCamera(gameObject); } } public override void UnitStart(){ base.UnitStart(); SetPlayerName(); Attach(); ((IKillable)this).IKillableInitialize(); } private void SetPlayerName(){ name = "Player"; if (UnitIsNetworked()){ name += IsLocalPlayer ? ", Local" : ", Network"; } } public override void UnitUpdate(){ GetComponent().DrawHealthDebug(); } public void TakeDamage(DamageSource[] sources){ foreach (DamageSource source in sources) { TakeDamage(source); } } public void TakeDamage(DamageSource source){ ((IKillable)this).currentHealth -= source.damageDealt; if (UnitIsNetworked()) { SetNewHealthRpc(currentHealth); } } // TODO: Move somewhere not stupid so there's not an identical method in Enemy.cs [Rpc(SendTo.Everyone)] public void SetNewHealthRpc(float health){ currentHealth = health; // NOTE: only here for testing. Move out of here into some "post damage" check method if (((IKillable)this).currentHealth <= 0) { // if (UnitIsNetworked()) { Down(); // } else { // Kill(); // } } } public void Down(){ Graph.SendEvent("Downed"); } public void Kill(){ Graph.SendEvent("Killed"); } public void Interact(){ // Check if the other player can be interacted with at all if (pickupTarget&& pickupTarget.GetComponent().CanInteract()) { // Tell the local player to start picking up the ally and switch states Graph.SendEvent("Picking Up Ally"); // Tell the target player to start getting picked up. pickupTarget.GetComponent().StartPickupRpc(); // Wait for the pickup timer to finish StartCoroutine(PickupTimer()); } } [Rpc(SendTo.Owner)] public void StartPickupRpc(){ // When picked up by another player, move into the pick up state // TODO: Turn all these send events into a goddamn task maybe? State stuff should happen in the state machine. Concurrent stuff should happen in code Graph.SendEvent("Pick Up Start"); } IEnumerator PickupTimer(){ // Start a timer and wait for it to complete float elapsed = 0f; while (elapsed < 7f) { elapsed += 1f * Time.deltaTime; yield return null; } Graph.SendEvent("Pick Up Success"); } public bool CanInteract(){ return IsDowned; } public void CancelInteract(){ Graph.SendEvent("Pick Up Failed"); } public void OnObserverDetected(EnvironmentObserver observer){ // Try and get a Player component from the current hit object // The rest of the logic will continue as expected so long as an pickupTarget = observer.hit.collider.gameObject; DrawInteractStatus(); } void DrawInteractStatus(){ using (Draw.WithColor(Color.blue)) { Draw.ingame.Label2D(transform.position + Vector3.up * 2.5f, "Interactable", Color.orchid); } } void LateUpdate(){ // Clear the pickupTarget every frame // NOTE: Will this work online? pickupTarget = null; } } }