void LocalStopTargeting()
 {
     // TODO: Reactivate idle-floaty-square image in the crosshair
     lockingImageCtrl.StopTargeting();
     targetedCharacter = null;
     lockedOnTarget    = false;
 }
 void StopTargeting(TargetableCharacter targetChar)
 {
     LocalStopTargeting();
     if (targetChar == null)
     {
         Debug.LogError("Target character has no TargetableCharacter component (how did we START targeting this guy?)");
         return;
     }
     targetChar.BroadcastBecameUntargeted(UserId());
 }
 // Start is called before the first frame update
 void Start()
 {
     fireOnButtonUp    = lockedOnTarget = paused = charging = false;
     targetedCharacter = null;
     projectileCtrl    = GameObject.Find("_GLOBAL_VIEWS").GetComponentInChildren <ProjectileController>();
     if (projectileCtrl == null)
     {
         Debug.LogError("Got null ProjectileController");
     }
 }
    void SwitchToTargetIfCloserToCenter(TargetableCharacter candidate)
    {
        float targetSightAngle = TargetSightAngle(candidate.centerTransform.position);
        bool  canBeTargeted    = CanBeTargeted(candidate, targetSightAngle);

        // If several enemy players are in scope, choose the player closest to the center of the scope.
        if (canBeTargeted && targetSightAngle < currentSharpestTargetAngle)
        {
            targetedCharacter          = candidate;
            currentSharpestTargetAngle = targetSightAngle;
        }
    }
 void StartTargeting(TargetableCharacter targetChar)
 {
     // TODO: Stop idle-floaty-square image in the crosshair when targetting
     // Inform remote player he's being targeted
     if (targetChar == null)
     {
         Debug.LogError("Target character has no TargetableCharacter component!");
         return;
     }
     targetChar.BroadcastBecameTargeted(UserId());
     lockingImageCtrl.StartTargeting(targetChar.centerTransform, () =>
     {
         targetChar.BroadcastBecameLockedOn(UserId());
         lockedOnTarget = true;
     });
 }
    bool CanBeTargeted(TargetableCharacter target, float targetSightAngle)
    {
        // Raycast from camera position should be safe, so long as the camera is within the bounds of the player collider.
        // TODO: This may not always be the best idea as the camera can move for effect. Either remember to keep camera in, or find another way
        RaycastHit hit;

        if (!Physics.Raycast(cam.transform.position, target.centerTransform.position - cam.transform.position, out hit))
        {
            Debug.LogError("How is the raycast missing everything when we shot it at a targetable character center position?");
            return(false);
        }
        if (hit.collider.gameObject == gameObject)
        {
            Debug.LogError("Raycast hit self collider. That's not good");
            return(false);
        }
        // Return true if the raycast hit the target (otherwise, it means there's something in the way)
        return(hit.collider.gameObject == target.gameObject && targetSightAngle <= MaxAngleToBeTargeted());
    }
    void UpdateLockFire()
    {
        // Initial lock-on check
        if (Tools.NearlyEqual(weaponCooldownCounter, 0, 0.01f) && buttonDown)
        {
            if (targetedCharacter != null)
            {
                Debug.LogWarning("Got fire-button-down but lock-target is already set, did we miss a fire-button-up event?");
                targetedCharacter = null;
                lockedOnTarget    = false;
            }
            // I'm not a performance expert but it may be best to just iterate over all players and see who's in scope.
            // Any targetable object will have an angle less than 1+maxAngle anyway, so this is like setting it to infinity:
            currentSharpestTargetAngle = 1 + MaxAngleToBeTargeted();
            foreach (Player player in PhotonNetwork.PlayerList)
            {
                if (NetworkCharacter.IsLocalPlayer(player) || !NetworkCharacter.IsPlayerAlive(player))
                {
                    continue;
                }
                TargetableCharacter playerTarget = NetworkCharacter.GetPlayerGameObject(player).GetComponent <TargetableCharacter>();
                SwitchToTargetIfCloserToCenter(playerTarget);
            }
            // If a dummy character is spawned it won't be in the player list but it should be targeted anyway
            if (UserDefinedConstants.spawnDummyPlayer && NetworkManager.DummyPlayer != null)
            {
                TargetableCharacter playerTarget = NetworkManager.DummyPlayer.GetComponent <TargetableCharacter>();
                SwitchToTargetIfCloserToCenter(playerTarget);
            }

            // Lock on to found character, if found
            if (targetedCharacter != null)
            {
                StartTargeting(targetedCharacter);
            }

            // In any case, player will now fire on button release
            fireOnButtonUp = true;
        }

        // Stop targeting if:
        // 1. We are currently targeting and not locked on yet
        // 2. Either the player can no longer be targeted, or we're not pressing the fire button anymore
        if (targetedCharacter != null && !lockedOnTarget && (!CanBeTargeted(targetedCharacter) || !buttonPressed))
        {
            StopTargeting(targetedCharacter);
        }

        // When targeting completes it's handled in the Action passed to StartTargeting

        // If user pressed the button after weapon cooldown and we got button up, now fire
        if (fireOnButtonUp && buttonUp)
        {
            fireOnButtonUp        = false;
            weaponCooldownCounter = UserDefinedConstants.weaponCooldown;
            if (lockedOnTarget)
            {
                FireSeekingProjectile();
            }
            else
            {
                // If we didn't lock on, then we're no longer targeting anyone
                if (targetedCharacter != null)
                {
                    StopTargeting(targetedCharacter);
                }
                FireProjectileMaxImpulse();
            }
            // Either way, locally, we're no longer targeting anyone (don't keep the indicator for the target of a fired projectile)
            LocalStopTargeting();
        }
    }
 bool CanBeTargeted(TargetableCharacter target)
 {
     return(CanBeTargeted(target, TargetSightAngle(target.centerTransform.position)));
 }