using Cinemachine.Utility; using UnityEngine; //using static UnityEditor.PlayerSettings; using UnityEngine.InputSystem; #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.EnhancedTouch; using System.Collections; using UnityEngine.Events; using Unity.VisualScripting; using UnityEngine.EventSystems; using UnityEngine.InputSystem.UI; using Cinemachine; using static UnityEngine.AudioSettings; using System; // NOTE: Unified Input System // Animation triggers are now handled exclusively by InputToAnimation. // Legacy OnXxx() input handlers in this class are intentionally no-ops to avoid duplicate triggers. // If you need to fire an animation from code, prefer: // GetComponent().TriggerAnimation(AnimationNames.Jab); // or route via CharacterAttacks for gameplay logic. [AddComponentMenu("")] // Don't display in add component menu public class PlayerScript : MonoBehaviour { //Player ID private int playerID; [Header("Sub Behaviours")] public PlayerVisualsBehaviour playerVisualsBehaviour; //jump system variables static bool jump; public GroundCheck groundCheck; public FallCheck fallCheck; static float jumpForce = 20; public GameObject player; public GameObject enemy; public float distance; private AnimatorClipInfo[] m_CurrentClipInfo; private float m_CurrentClipLength; private string m_ClipName; public float nextAnimationTime; public float animationInterval; static Animator anim; public Vector2 input; private Camera mainCamera; //public EnemyScript enemyscript; private HealthNew health; public bool block; public CharacterAttacks playerAttacks; private AnimatorClipInfo[] playerclipinfo; // Reference to the currently held item. private PickableItem[] pickedItem; // Reference to the slot for holding picked item. [SerializeField] private Transform pickingHands; public float pickingdistance; private PickableItem item; public bool helpless = false; static bool held; [Header("Input Settings")] public PlayerInput playerInput; private bool isInputActive = false; public bool attack; public bool dodge; public Transform headTransform; public InputBuffer inputBuffer; // TeamMember reference for control type checking private TeamMember _teamMember; // Add fields for vicious and special attacks private bool canPerformViciousAttack = true; private bool canPerformSpecialAttack = true; private float viciousAttackCooldown = 5.0f; private float specialAttackCooldown = 10.0f; private float lastViciousAttackTime = -5.0f; private float lastSpecialAttackTime = -10.0f; // Use this for initialization void Start() { anim = GetComponent(); mainCamera = Camera.main; player = GameObject.FindGameObjectWithTag("Player"); enemy = GameObject.FindGameObjectWithTag("Enemy"); animationInterval = 3.0f; block = false; dodge = false; //enemyscript = enemy.GetComponent(); helpless = false; held = false; health = GetComponent(); attack = false; playerAttacks = GetComponent(); inputBuffer = GetComponent(); // Cache TeamMember for control type checking _teamMember = GetComponent(); } private void Update() { var pmn = GameObject.FindFirstObjectByType(); if (pmn != null && pmn.pause) return; // Update cooldowns for vicious and special attacks canPerformViciousAttack = (Time.time - lastViciousAttackTime >= viciousAttackCooldown); canPerformSpecialAttack = (Time.time - lastSpecialAttackTime >= specialAttackCooldown); // Decay the input value gradually when no input is received, decayrate = 1.0f //input = Vector2.Lerp(input, Vector2.zero, Time.deltaTime * 1.0f); // Check if we should use mobile controls // Include editor platforms so we can test mobile controls in the editor bool isMobile = (UnityEngine.Application.platform == RuntimePlatform.Android || UnityEngine.Application.platform == RuntimePlatform.IPhonePlayer); // Also enable mobile input path in editor for testing bool isEditor = (UnityEngine.Application.platform == RuntimePlatform.LinuxEditor || UnityEngine.Application.platform == RuntimePlatform.WindowsEditor || UnityEngine.Application.platform == RuntimePlatform.OSXEditor); // Use mobile input path in editor OR on actual mobile devices if (isMobile || isEditor) { // Movement now comes from the Input System Move action (fed by MobileOnScreenStick) // No direct joystick lookup. if (!dodge && !block) { OnMoveMobile(); } else if (dodge && !block) { // Use current input vector to determine dodge direction var dir = input; string joystickDir = GetDirection(dir); playerAttacks.DodgeMobile(joystickDir, dir); } else if (block && !dodge) { var dir = input; string joystickDir = GetDirection(dir); playerAttacks.BlockMobile(joystickDir); } } } public void OnMove(InputAction.CallbackContext context) { // CRITICAL: Only process input if this character is HumanControlled if (_teamMember != null && _teamMember.CurrentControlType != TeamMember.ControlType.HumanControlled) { return; } // NOTE: We always update the input vector here. The actual movement gating // (attack enabled, not blocking, not dodging) is handled in CharacterMovement.FixedUpdate. // We only gate the input reading by device assignment to prevent input cross-contamination. // Ensure input is from this player's assigned device(s). Allow synthetic devices (on-screen controls) // created by Unity's Input System so mobile UI can drive the player. var pi = GetComponent(); if (pi != null && pi.devices.Count > 0) { var device = context.control?.device; if (device != null) { bool isAssignedDevice = false; for (int i = 0; i < pi.devices.Count; i++) { if (pi.devices[i] == device) { isAssignedDevice = true; break; } } if (!isAssignedDevice && !device.synthetic) return; } } // Read movement input - ALWAYS update this so CharacterMovement has latest input Vector2 rawInput = context.ReadValue(); input = rawInput; // Set the input as active when there is input isInputActive = input.magnitude > 0.0f; /*//follow moving player GameObject camera = GameObject.Find("CinemachineCamera"); var vcam = camera.GetComponent(); if (vcam != null) { Transform headTransform = transform; if (gameObject.name == "Cheetah") { //Transform firstTarget = targets[0].transform; headTransform = gameObject.transform.GetChild(9).GetChild(6).GetChild(1); } else if (gameObject.name == "Rabbit") { headTransform = gameObject.transform.GetChild(7).GetChild(6).GetChild(1); } if (headTransform != null) { //vcam.LookAt = vcam.Follow = GameObject.Find("DEF-spine.001").transform; vcam.LookAt = vcam.Follow = headTransform; //vcam.LookAt = vcam.Follow = GameObject.Find("BUILD-WALL").transform; vcam.m_Lens.FieldOfView = 43; } }*/ } public void OnJab(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnHaymaker(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnSpinningBackfist(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnElbowSmash(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnChargePunch(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnAirPunch(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnDropKick(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnLowKick(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnPunch(InputAction.CallbackContext context) { // Legacy aggregate handler disabled. Animations are handled by InputToAnimation. return; } public void OnJump(InputAction.CallbackContext context) { if (context.started) { Jump(); } } public void OnKick(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } public void OnMoveMobile() { // Block camera updates only during blocking or dodging (NOT based on 'attack' permission flag) if (block == true || dodge == true) return; // Input is already filled by OnMove from the Input System (MobileOnScreenStick) // So we just use the current 'input' vector here. // Set the input as active when there is input isInputActive = input.magnitude > 0.0f; // Camera targeting is handled by CameraManager / SetupSingleCamera. // Do NOT override Follow/LookAt here every frame — it fights CinemachineBrain. } public void OnPunchMobileNew(float verticalValue, float horizontalValue, string punchDirection) { // Legacy mobile trigger disabled. Animations are handled by InputToAnimation. return; } public void OnKickMobileNew(float verticalValue, float horizontalValue, string kickDirection) { // Legacy mobile trigger disabled. Animations are handled by InputToAnimation. return; } public void OnLook(InputAction.CallbackContext context) { if (context.started) { Look(); } } public void OnSprint(InputAction.CallbackContext context) { //print("is sprinting controls " + context.control); // held = !held; if (context.performed) { anim.SetBool("isSprinting", true); } else if (context.canceled) { anim.SetBool("isSprinting", false); } } public void OnStrike(InputAction.CallbackContext context) { // Legacy direct trigger disabled. Animations are handled by InputToAnimation. return; } //This is called from Player Input, when a button has been pushed, that correspons with the 'TogglePause' action public void OnTogglePause(InputAction.CallbackContext value) { if (value.started) { //GameManager.Instance.TogglePauseState(this); } } public void SetPlayerInputActive(bool activation, PlayerInput selectedPlayerInput) { // UnityEngine.DevLog.Log("Activating pi at " + Time.time); if (playerInput == null) playerInput = selectedPlayerInput; playerInput.enabled = activation; } public int GetPlayerID() { return playerID; } public PlayerInput GetPlayerInput() { return playerInput; } public virtual void UpdatePlayerDirection() { //print("update player direction"); Vector3 relativePos = Vector3.zero; if (gameObject.CompareTag("Player")) relativePos = enemy.transform.position - player.transform.position; else if (gameObject.CompareTag("Enemy")) relativePos = player.transform.position - enemy.transform.position; // the second argument, upwards, defaults to Vector3.up if (relativePos.y < 0.1 && jump == false) { Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up); transform.rotation = rotation; } } void Strike() { m_CurrentClipInfo = enemy.GetComponent().GetCurrentAnimatorClipInfo(0); m_ClipName = m_CurrentClipInfo[0].clip.name; player.transform.LookAt(enemy.transform.position); anim.Play("Baseball Strike"); GameObject wood = GameObject.FindGameObjectWithTag("wood"); //reposition and rotate the wood to fit properly in the hands if (wood.GetComponent() == null) { Vector3 position = new Vector3(-0.01f, 1.06f, -2.38f); Vector3 rotationangles = new Vector3(110.06f, 0, 8.9f); wood.transform.localPosition = position; wood.transform.localEulerAngles = rotationangles; } } void Jump() { if (player.transform.position.y < 10.5) { anim.SetBool("jumpkick", false); jump = true; jumpForce = 40; anim.Play("14-Jump-Up"); player.transform.Translate(new Vector3(0, jumpForce, 0) * Time.deltaTime); } } void Kick(string kickAttack) { UpdatePlayerDirection(); inputBuffer.AddInputToBuffer(kickAttack); string input = inputBuffer.GetLatestInput(); if (input != null) playerAttacks.KickAttacks(input); } void KickMobile(float verticalValue, float horizontalValue, string kickDirection) { UpdatePlayerDirection(); if (Time.time > nextAnimationTime) { // Map mobile inputs to our 2 kick animations string animation = AnimationNames.LowKick; // Default fallback switch (kickDirection) { case "up": case "upright": case "upleft": case "right": case "left": animation = AnimationNames.DropKick; break; case "down": case "downright": case "downleft": animation = AnimationNames.LowKick; break; } playerAttacks.KickAttacksDirectly(animation); } } void Look() { } void Punch(string punchAttack) { UpdatePlayerDirection(); inputBuffer.AddInputToBuffer(punchAttack); string input = inputBuffer.GetLatestInput(); if (input != null) playerAttacks.PunchAttacks(input); } void PunchMobile(float verticalValue, float horizontalValue, string punchDirection) { UpdatePlayerDirection(); if (Time.time > nextAnimationTime) { // Map mobile inputs to our 6 punch animations string animation = AnimationNames.Jab; // Default fallback switch (punchDirection) { case "up": animation = AnimationNames.Jab; break; case "down": animation = AnimationNames.Haymaker; break; case "left": case "right": animation = AnimationNames.SpinningBackfist; break; case "upleft": case "upright": animation = AnimationNames.ElbowSmash; break; case "downleft": animation = AnimationNames.ChargedPunch; break; case "downright": animation = AnimationNames.AirPunch; break; } playerAttacks.PunchAttacksDirectly(animation); } } public static string GetDirection(Vector2 vector) { float x = vector.x; float y = vector.y; if (y > 0.5f && Math.Abs(x) <= 0.5f) { return "up"; } if (y < -0.5f && Math.Abs(x) <= 0.5f) { return "down"; } if (x < -0.5f && Math.Abs(y) <= 0.5f) { return "left"; } if (x > 0.5f && Math.Abs(y) <= 0.5f) { return "right"; } if (x <= -0.5f && y > 0.5f) { return "upleft"; } if (x >= 0.5f && y > 0.5f) { return "upright"; } if (x <= -0.5f && y < -0.5f) { return "downleft"; } if (x >= 0.5f && y < -0.5f) { return "downright"; } return "undefined"; // If it doesn't match any of the directions } public void StartDodge() { if (!dodge) // Check if dodge is not already active { dodge = true; StartCoroutine(DodgeCoroutine()); } } public void StartBlock() { if (!block) { block = true; //GameObject.FindGameObjectWithTag("Enemy").GetComponent().attack = true; //attack = false; StartCoroutine(BlockCoroutine()); } } private IEnumerator DodgeCoroutine() { // Duration of dodge yield return new WaitForSeconds(1.5f); // End dodge //do not add another statement here the function breaks for some reason dodge = false; } private IEnumerator BlockCoroutine() { // Duration of dodge yield return new WaitForSeconds(1.5f); // End dodge //do not add another statement here the function breaks for some reason //attack = true; block = false; } // VICIOUS ATTACKS // Example mapped to key combinations or button presses public void OnChokeslam(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformViciousAttack) return; if (context.control.device == GetComponent().devices[0]) { lastViciousAttackTime = Time.time; ViciousAttack("Chokeslam"); } } public void OnSuplex(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformViciousAttack) return; if (context.control.device == GetComponent().devices[0]) { lastViciousAttackTime = Time.time; ViciousAttack("Suplex"); } } public void OnGiantSwing(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformViciousAttack) return; if (context.control.device == GetComponent().devices[0]) { lastViciousAttackTime = Time.time; ViciousAttack("GiantSwing"); } } public void OnDiamondCrusher(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformViciousAttack) return; if (context.control.device == GetComponent().devices[0]) { lastViciousAttackTime = Time.time; ViciousAttack("DiamondCrusher"); } } // SPECIAL FINISHER ATTACKS public void OnRKO(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformSpecialAttack) return; if (context.control.device == GetComponent().devices[0]) { lastSpecialAttackTime = Time.time; SpecialAttack("RKO"); } } public void OnSpear(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformSpecialAttack) return; if (context.control.device == GetComponent().devices[0]) { lastSpecialAttackTime = Time.time; SpecialAttack("Spear"); } } public void OnRockBottom(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformSpecialAttack) return; if (context.control.device == GetComponent().devices[0]) { lastSpecialAttackTime = Time.time; SpecialAttack("RockBottom"); } } // Helper methods to route to CharacterAttacks void ViciousAttack(string viciousAttack) { UpdatePlayerDirection(); inputBuffer.AddInputToBuffer(viciousAttack); string input = inputBuffer.GetLatestInput(); if (input != null) playerAttacks.ViciousAttacks(input); } void SpecialAttack(string specialAttack) { UpdatePlayerDirection(); inputBuffer.AddInputToBuffer(specialAttack); string input = inputBuffer.GetLatestInput(); if (input != null) playerAttacks.SpecialAttacks(input); } // Mobile support for vicious and special attacks public void OnViciousAttackMobile(float verticalValue, float horizontalValue, string direction) { if (attack == false || !canPerformViciousAttack) return; UpdatePlayerDirection(); lastViciousAttackTime = Time.time; if (Time.time > nextAnimationTime) { playerAttacks.ViciousAttacksMobile(verticalValue, horizontalValue, direction); } } public void OnSpecialAttackMobile(float verticalValue, float horizontalValue, string direction) { if (attack == false || !canPerformSpecialAttack) return; UpdatePlayerDirection(); lastSpecialAttackTime = Time.time; if (Time.time > nextAnimationTime) { playerAttacks.SpecialAttacksMobile(verticalValue, horizontalValue, direction); } } // Additional methods for vicious attacks that were referenced in SelectionOptions public void OnSumoSlap(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformViciousAttack) return; if (context.control.device == GetComponent().devices[0]) { lastViciousAttackTime = Time.time; ViciousAttack("SumoSlap"); } } public void OnJavelinTackle(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformViciousAttack) return; if (context.control.device == GetComponent().devices[0]) { lastViciousAttackTime = Time.time; ViciousAttack("JavelinTackle"); } } // Additional methods for special finishers that were referenced in SelectionOptions public void OnF5(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformSpecialAttack) return; if (context.control.device == GetComponent().devices[0]) { lastSpecialAttackTime = Time.time; SpecialAttack("F5"); } } public void OnSwantomBomb(InputAction.CallbackContext context) { if (!context.performed || attack == false || !canPerformSpecialAttack) return; if (context.control.device == GetComponent().devices[0]) { lastSpecialAttackTime = Time.time; SpecialAttack("SwantomBomb"); } } // STUB METHODS FOR COMMENTED OUT ANIMATIONS // The following methods are stubs for animations that are not currently active, // but are still referenced in other scripts like SelectionOptions.cs and HealthNew.cs public void OnRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnLeftHook(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnRightHook(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnLeftElbow(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnRightElbow(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnRightBody(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnPowerPunchLeft(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnSupermanPunch(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnLegKickRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnBodyKickRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnKneeRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnBackSideKick(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnFrontKickRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnLegPowerKickRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnJumpBack(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnJumpLeft(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnJumpRight(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnBlockStepBack(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnBlockBodyLeft(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } public void OnBlockLeg(InputAction.CallbackContext context) { // Stub method - not active in current configuration return; } }