Files
2026-06-26 22:41:39 +05:30

901 lines
28 KiB
C#

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<InputToAnimation>().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<Animator>();
mainCamera = Camera.main;
player = GameObject.FindGameObjectWithTag("Player");
enemy = GameObject.FindGameObjectWithTag("Enemy");
animationInterval = 3.0f;
block = false;
dodge = false;
//enemyscript = enemy.GetComponent<EnemyScript>();
helpless = false;
held = false;
health = GetComponent<HealthNew>();
attack = false;
playerAttacks = GetComponent<CharacterAttacks>();
inputBuffer = GetComponent<InputBuffer>();
// Cache TeamMember for control type checking
_teamMember = GetComponent<TeamMember>();
}
private void Update()
{
var pmn = GameObject.FindFirstObjectByType<PlayerManagerNew>();
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<PlayerInput>();
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<Vector2>();
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<CinemachineFreeLook>();
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<Animator>().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<Rigidbody>() == 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<EnemyScript>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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<PlayerInput>().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;
}
}