2021-12-27 17:26:16 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
|
|
|
|
using GTA;
|
|
|
|
|
using GTA.Native;
|
|
|
|
|
using GTA.Math;
|
|
|
|
|
|
2021-12-27 10:15:52 +01:00
|
|
|
|
namespace CoopClient.Entities.Player
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2021-12-27 10:15:52 +01:00
|
|
|
|
public partial class EntitiesPlayer
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2022-03-20 09:21:41 +01:00
|
|
|
|
#region -- VARIABLES --
|
2021-12-15 03:31:57 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The latest character rotation (may not have been applied yet)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Vector3 Rotation { get; internal set; }
|
|
|
|
|
internal byte Speed { get; set; }
|
2022-04-10 14:34:55 +02:00
|
|
|
|
private bool _lastIsJumping = false;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
internal bool IsJumping { get; set; }
|
2021-12-28 19:14:51 +01:00
|
|
|
|
internal bool IsOnLadder { get; set; }
|
|
|
|
|
internal bool IsVaulting { get; set; }
|
2021-12-27 17:26:16 +01:00
|
|
|
|
internal bool IsInParachuteFreeFall { get; set; }
|
2022-01-01 04:16:24 +01:00
|
|
|
|
internal bool IsParachuteOpen { get; set; }
|
|
|
|
|
internal Prop ParachuteProp { get; set; } = null;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
internal bool IsRagdoll { get; set; }
|
|
|
|
|
internal bool IsOnFire { get; set; }
|
|
|
|
|
internal bool IsAiming { get; set; }
|
|
|
|
|
internal bool IsShooting { get; set; }
|
|
|
|
|
internal bool IsReloading { get; set; }
|
|
|
|
|
internal uint CurrentWeaponHash { get; set; }
|
2022-04-10 14:34:55 +02:00
|
|
|
|
private Dictionary<uint, bool> _lastWeaponComponents = null;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
2022-04-10 14:34:55 +02:00
|
|
|
|
private int _lastWeaponObj = 0;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
#endregion
|
|
|
|
|
|
2022-04-10 14:34:55 +02:00
|
|
|
|
private bool _isPlayingAnimation = false;
|
|
|
|
|
private string[] _currentAnimation = new string[2] { "", "" };
|
|
|
|
|
private float _animationStopTime = 0;
|
2021-12-27 11:05:01 +01:00
|
|
|
|
|
2021-12-15 03:31:57 +01:00
|
|
|
|
private void DisplayOnFoot()
|
|
|
|
|
{
|
|
|
|
|
if (Character.IsInVehicle())
|
|
|
|
|
{
|
2022-04-14 02:08:13 +02:00
|
|
|
|
if (MainVehicle == null)
|
|
|
|
|
{
|
|
|
|
|
Character.Task.LeaveVehicle();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MainVehicle.Doors[(VehicleDoorIndex)VehicleSeatIndex + 1]?.Open(true, true);
|
|
|
|
|
Character.Task.LeaveVehicle(MainVehicle, false);
|
|
|
|
|
|
|
|
|
|
MainVehicle = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Character.PositionNoOffset = Position;
|
|
|
|
|
return;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-28 17:50:04 +01:00
|
|
|
|
if (IsInParachuteFreeFall)
|
|
|
|
|
{
|
2022-01-01 19:24:57 +01:00
|
|
|
|
Character.PositionNoOffset = Vector3.Lerp(Character.Position, Position + Velocity, 0.5f);
|
|
|
|
|
Character.Quaternion = Rotation.ToQuaternion();
|
|
|
|
|
|
|
|
|
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, "skydive@base", "free_idle", 3))
|
2021-12-28 17:50:04 +01:00
|
|
|
|
{
|
2022-01-01 19:24:57 +01:00
|
|
|
|
Function.Call(Hash.TASK_PLAY_ANIM, Character.Handle, LoadAnim("skydive@base"), "free_idle", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
2021-12-28 17:50:04 +01:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-01 04:16:24 +01:00
|
|
|
|
if (IsParachuteOpen)
|
|
|
|
|
{
|
|
|
|
|
if (ParachuteProp == null)
|
|
|
|
|
{
|
2022-01-01 19:24:57 +01:00
|
|
|
|
Model model = 1740193300.ModelRequest();
|
|
|
|
|
if (model != null)
|
|
|
|
|
{
|
|
|
|
|
ParachuteProp = World.CreateProp(model, Character.Position, Character.Rotation, false, false);
|
|
|
|
|
model.MarkAsNoLongerNeeded();
|
|
|
|
|
ParachuteProp.IsPositionFrozen = true;
|
|
|
|
|
ParachuteProp.IsCollisionEnabled = false;
|
|
|
|
|
|
|
|
|
|
ParachuteProp.AttachTo(Character.Bones[Bone.SkelSpine2], new Vector3(3.6f, 0f, 0f), new Vector3(0f, 90f, 0f));
|
|
|
|
|
}
|
2022-01-01 04:16:24 +01:00
|
|
|
|
Character.Task.ClearAllImmediately();
|
|
|
|
|
Character.Task.ClearSecondary();
|
|
|
|
|
}
|
2022-01-01 19:24:57 +01:00
|
|
|
|
|
|
|
|
|
Character.PositionNoOffset = Vector3.Lerp(Character.Position, Position + Velocity, 0.5f);
|
|
|
|
|
Character.Quaternion = Rotation.ToQuaternion();
|
2022-01-01 04:16:24 +01:00
|
|
|
|
|
|
|
|
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, "skydive@parachute@first_person", "chute_idle_right", 3))
|
|
|
|
|
{
|
|
|
|
|
Function.Call(Hash.TASK_PLAY_ANIM, Character, LoadAnim("skydive@parachute@first_person"), "chute_idle_right", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ParachuteProp != null)
|
|
|
|
|
{
|
|
|
|
|
if (ParachuteProp.Exists())
|
|
|
|
|
{
|
|
|
|
|
ParachuteProp.Delete();
|
|
|
|
|
}
|
|
|
|
|
ParachuteProp = null;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-28 19:14:51 +01:00
|
|
|
|
if (IsOnLadder)
|
|
|
|
|
{
|
2022-04-22 10:03:59 +02:00
|
|
|
|
if (Velocity.Z < 0)
|
2021-12-28 19:14:51 +01:00
|
|
|
|
{
|
2022-04-22 10:03:59 +02:00
|
|
|
|
string anim = Velocity.Z < -2f ? "slide_climb_down" : "climb_down";
|
|
|
|
|
if (_currentAnimation[1] != anim)
|
2022-04-22 09:13:09 +02:00
|
|
|
|
{
|
|
|
|
|
Character.Task.ClearAllImmediately();
|
2022-04-22 10:03:59 +02:00
|
|
|
|
_currentAnimation[1] = anim;
|
2022-04-22 09:13:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 10:03:59 +02:00
|
|
|
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, "laddersbase", anim, 3))
|
2022-04-22 09:13:09 +02:00
|
|
|
|
{
|
2022-04-22 10:03:59 +02:00
|
|
|
|
Character.Task.PlayAnimation("laddersbase", anim, 8f, -1, AnimationFlags.Loop);
|
2022-04-22 09:13:09 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-22 10:03:59 +02:00
|
|
|
|
else
|
2022-04-22 09:13:09 +02:00
|
|
|
|
{
|
2022-04-22 10:03:59 +02:00
|
|
|
|
if (Math.Abs(Velocity.Z) < 0.5)
|
2022-04-22 09:13:09 +02:00
|
|
|
|
{
|
2022-04-22 10:03:59 +02:00
|
|
|
|
if (_currentAnimation[1] != "base_left_hand_up")
|
|
|
|
|
{
|
|
|
|
|
Character.Task.ClearAllImmediately();
|
|
|
|
|
_currentAnimation[1] = "base_left_hand_up";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, "laddersbase", "base_left_hand_up", 3))
|
|
|
|
|
{
|
|
|
|
|
Character.Task.PlayAnimation("laddersbase", "base_left_hand_up", 8f, -1, AnimationFlags.Loop);
|
|
|
|
|
}
|
2022-04-22 09:13:09 +02:00
|
|
|
|
}
|
2022-04-22 10:03:59 +02:00
|
|
|
|
else
|
2022-04-22 09:13:09 +02:00
|
|
|
|
{
|
2022-04-22 10:03:59 +02:00
|
|
|
|
if (_currentAnimation[1] != "climb_up")
|
|
|
|
|
{
|
|
|
|
|
Character.Task.ClearAllImmediately();
|
|
|
|
|
_currentAnimation[1] = "climb_up";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, "laddersbase", "climb_up", 3))
|
|
|
|
|
{
|
|
|
|
|
Character.Task.PlayAnimation("laddersbase", "climb_up", 8f, -1, AnimationFlags.Loop);
|
|
|
|
|
}
|
2022-04-22 09:13:09 +02:00
|
|
|
|
}
|
2021-12-28 19:14:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateOnFootPosition(true, true, false);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-04-14 02:08:13 +02:00
|
|
|
|
if (!IsOnLadder && Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, Character.Handle, ETasks.CLIMB_LADDER))
|
2021-12-28 19:14:51 +01:00
|
|
|
|
{
|
|
|
|
|
Character.Task.ClearAllImmediately();
|
2022-04-22 10:03:59 +02:00
|
|
|
|
_currentAnimation[1] = "";
|
2021-12-28 19:14:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsVaulting)
|
|
|
|
|
{
|
|
|
|
|
if (!Character.IsVaulting)
|
|
|
|
|
{
|
|
|
|
|
Character.Task.Climb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateOnFootPosition(true, true, false);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-04-14 02:08:13 +02:00
|
|
|
|
if (!IsVaulting && Character.IsVaulting)
|
2021-12-28 19:14:51 +01:00
|
|
|
|
{
|
|
|
|
|
Character.Task.ClearAllImmediately();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 03:31:57 +01:00
|
|
|
|
if (IsOnFire && !Character.IsOnFire)
|
|
|
|
|
{
|
|
|
|
|
Character.IsInvincible = false;
|
|
|
|
|
|
|
|
|
|
Function.Call(Hash.START_ENTITY_FIRE, Character.Handle);
|
|
|
|
|
}
|
|
|
|
|
else if (!IsOnFire && Character.IsOnFire)
|
|
|
|
|
{
|
|
|
|
|
Function.Call(Hash.STOP_ENTITY_FIRE, Character.Handle);
|
|
|
|
|
|
|
|
|
|
Character.IsInvincible = true;
|
|
|
|
|
|
|
|
|
|
if (Character.IsDead)
|
|
|
|
|
{
|
|
|
|
|
Character.Resurrect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-28 19:14:51 +01:00
|
|
|
|
if (IsJumping)
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2022-04-10 14:34:55 +02:00
|
|
|
|
if (!_lastIsJumping)
|
2021-12-28 19:14:51 +01:00
|
|
|
|
{
|
2022-04-10 14:34:55 +02:00
|
|
|
|
_lastIsJumping = true;
|
2021-12-28 19:14:51 +01:00
|
|
|
|
Character.Task.Jump();
|
|
|
|
|
}
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
2022-01-01 19:24:57 +01:00
|
|
|
|
UpdateOnFootPosition();
|
2021-12-28 19:14:51 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-04-10 14:34:55 +02:00
|
|
|
|
_lastIsJumping = false;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
2021-12-24 06:33:00 +01:00
|
|
|
|
if (IsRagdoll)
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2021-12-24 06:33:00 +01:00
|
|
|
|
if (!Character.IsRagdoll)
|
|
|
|
|
{
|
2021-12-27 11:05:01 +01:00
|
|
|
|
Character.CanRagdoll = true;
|
|
|
|
|
Function.Call(Hash.SET_PED_TO_RAGDOLL, Character.Handle, 50000, 60000, 0, 1, 1, 1);
|
2021-12-24 06:33:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-27 10:15:52 +01:00
|
|
|
|
UpdateOnFootPosition(false, false, true);
|
|
|
|
|
|
2021-12-24 06:33:00 +01:00
|
|
|
|
return;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
2022-04-22 13:57:39 +02:00
|
|
|
|
else
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2022-04-22 13:57:39 +02:00
|
|
|
|
if (Character.IsRagdoll)
|
|
|
|
|
{
|
|
|
|
|
Character.CanRagdoll = false;
|
|
|
|
|
Character.Task.ClearAllImmediately();
|
2021-12-24 06:33:00 +01:00
|
|
|
|
|
2022-04-22 13:57:39 +02:00
|
|
|
|
_isPlayingAnimation = true;
|
|
|
|
|
_currentAnimation = new string[2] { "anim@sports@ballgame@handball@", "ball_get_up" };
|
|
|
|
|
_animationStopTime = 0.7f;
|
2021-12-27 11:05:01 +01:00
|
|
|
|
|
2022-04-22 13:57:39 +02:00
|
|
|
|
Function.Call(Hash.TASK_PLAY_ANIM, Character.Handle, LoadAnim("anim@sports@ballgame@handball@"), "ball_get_up", 12f, 12f, -1, 0, -10f, 1, 1, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (_currentAnimation[1] == "ball_get_up")
|
|
|
|
|
{
|
|
|
|
|
UpdateOnFootPosition(true, true, false);
|
|
|
|
|
float currentTime = Function.Call<float>(Hash.GET_ENTITY_ANIM_CURRENT_TIME, Character.Handle, "anim@sports@ballgame@handball@", _currentAnimation[1]);
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
2022-04-22 13:57:39 +02:00
|
|
|
|
if (currentTime < _animationStopTime)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Character.Task.ClearAnimation(_currentAnimation[0], _currentAnimation[1]);
|
|
|
|
|
Character.Task.ClearAll();
|
|
|
|
|
_isPlayingAnimation = false;
|
|
|
|
|
_currentAnimation = new string[2] { "", "" };
|
|
|
|
|
_animationStopTime = 0;
|
|
|
|
|
}
|
2021-12-27 11:05:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 13:57:39 +02:00
|
|
|
|
CheckCurrentWeapon();
|
|
|
|
|
|
2021-12-15 03:31:57 +01:00
|
|
|
|
if (IsReloading)
|
|
|
|
|
{
|
2022-04-22 13:57:39 +02:00
|
|
|
|
if (!_isPlayingAnimation)
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2022-04-22 13:57:39 +02:00
|
|
|
|
string[] reloadingAnim = GetReloadingAnimation();
|
|
|
|
|
if (reloadingAnim != null)
|
|
|
|
|
{
|
|
|
|
|
_isPlayingAnimation = true;
|
|
|
|
|
_currentAnimation = reloadingAnim;
|
|
|
|
|
Character.Task.PlayAnimation(_currentAnimation[0], _currentAnimation[1], 8f, -1, AnimationFlags.AllowRotation | AnimationFlags.UpperBodyOnly);
|
|
|
|
|
}
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-22 13:57:39 +02:00
|
|
|
|
else if (_currentAnimation[1] == "reload_aim")
|
|
|
|
|
{
|
|
|
|
|
Character.Task.ClearAnimation(_currentAnimation[0], _currentAnimation[1]);
|
|
|
|
|
_isPlayingAnimation = false;
|
|
|
|
|
_currentAnimation = new string[2] { "", "" };
|
|
|
|
|
}
|
2021-12-28 17:50:04 +01:00
|
|
|
|
|
|
|
|
|
if (IsShooting)
|
|
|
|
|
{
|
|
|
|
|
DisplayShooting();
|
|
|
|
|
}
|
|
|
|
|
else if (IsAiming)
|
|
|
|
|
{
|
|
|
|
|
DisplayAiming();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WalkTo();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region WEAPON
|
|
|
|
|
private void CheckCurrentWeapon()
|
|
|
|
|
{
|
2022-04-10 14:34:55 +02:00
|
|
|
|
if (Character.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents))
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
|
|
|
|
Character.Weapons.RemoveAll();
|
|
|
|
|
|
|
|
|
|
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
|
|
|
|
{
|
|
|
|
|
if (WeaponComponents == null || WeaponComponents.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Character.Weapons.Give((WeaponHash)CurrentWeaponHash, -1, true, true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-04-10 14:34:55 +02:00
|
|
|
|
_lastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
|
|
|
|
foreach (KeyValuePair<uint, bool> comp in WeaponComponents)
|
|
|
|
|
{
|
|
|
|
|
if (comp.Value)
|
|
|
|
|
{
|
2022-04-10 14:34:55 +02:00
|
|
|
|
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _lastWeaponObj, comp.Key);
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-10 14:34:55 +02:00
|
|
|
|
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _lastWeaponObj, Character.Handle);
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-10 14:34:55 +02:00
|
|
|
|
_lastWeaponComponents = WeaponComponents;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
2021-12-28 17:50:04 +01:00
|
|
|
|
}
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
2022-04-22 13:57:39 +02:00
|
|
|
|
private string[] GetReloadingAnimation()
|
|
|
|
|
{
|
|
|
|
|
switch (Character.Weapons.Current.Hash)
|
|
|
|
|
{
|
|
|
|
|
case WeaponHash.Revolver:
|
|
|
|
|
case WeaponHash.RevolverMk2:
|
|
|
|
|
case WeaponHash.DoubleActionRevolver:
|
|
|
|
|
case WeaponHash.NavyRevolver:
|
|
|
|
|
return new string[2] { "anim@weapons@pistol@revolver_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.APPistol:
|
|
|
|
|
return new string[2] { "weapons@pistol@ap_pistol_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.Pistol50:
|
|
|
|
|
return new string[2] { "weapons@pistol@pistol_50_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.Pistol:
|
|
|
|
|
case WeaponHash.PistolMk2:
|
|
|
|
|
case WeaponHash.PericoPistol:
|
|
|
|
|
case WeaponHash.SNSPistol:
|
|
|
|
|
case WeaponHash.SNSPistolMk2:
|
|
|
|
|
case WeaponHash.HeavyPistol:
|
|
|
|
|
case WeaponHash.VintagePistol:
|
|
|
|
|
case WeaponHash.CeramicPistol:
|
|
|
|
|
case WeaponHash.MachinePistol:
|
|
|
|
|
return new string[2] { "weapons@pistol@pistol_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.AssaultRifle:
|
|
|
|
|
case WeaponHash.AssaultrifleMk2:
|
|
|
|
|
return new string[2] { "weapons@rifle@aussault_rifle_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.SniperRifle:
|
|
|
|
|
return new string[2] { "weapons@rifle@sniper_rifle_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.HeavySniper:
|
|
|
|
|
case WeaponHash.HeavySniperMk2:
|
|
|
|
|
return new string[2] { "weapons@rifle@sniper_heavy_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.PumpShotgun:
|
|
|
|
|
case WeaponHash.PumpShotgunMk2:
|
|
|
|
|
return new string[2] { "weapons@rifle@pump_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.Railgun:
|
|
|
|
|
return new string[2] { "weapons@rifle@rail_gun_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.SawnOffShotgun:
|
|
|
|
|
return new string[2] { "weapons@rifle@sawnoff_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.AssaultShotgun:
|
|
|
|
|
return new string[2] { "weapons@rifle@shotgun_assault_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.BullpupShotgun:
|
|
|
|
|
return new string[2] { "weapons@rifle@shotgun_bullpup_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.AdvancedRifle:
|
|
|
|
|
return new string[2] { "weapons@submg@advanced_rifle_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.CarbineRifle:
|
|
|
|
|
case WeaponHash.CarbineRifleMk2:
|
|
|
|
|
case WeaponHash.CompactRifle:
|
|
|
|
|
return new string[2] { "weapons@rifle@lo@carbine_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.Gusenberg:
|
|
|
|
|
return new string[2] { "anim@weapons@machinegun@gusenberg_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.Musket:
|
|
|
|
|
return new string[2] { "anim@weapons@musket@musket_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.FlareGun:
|
|
|
|
|
return new string[2] { "anim@weapons@pistol@flare_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.SpecialCarbine:
|
|
|
|
|
case WeaponHash.SpecialCarbineMk2:
|
|
|
|
|
return new string[2] { "anim@weapons@rifle@lo@spcarbine_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.CombatPDW:
|
|
|
|
|
return new string[2] { "anim@weapons@rifle@lo@pdw_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.BullpupRifle:
|
|
|
|
|
case WeaponHash.BullpupRifleMk2:
|
|
|
|
|
return new string[2] { "anim@weapons@rifle@lo@bullpup_rifle_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.AssaultSMG:
|
|
|
|
|
return new string[2] { "weapons@submg@assault_smg_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.MicroSMG:
|
|
|
|
|
case WeaponHash.MiniSMG:
|
|
|
|
|
return new string[2] { "weapons@submg@micro_smg_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.SMG:
|
|
|
|
|
case WeaponHash.SMGMk2:
|
|
|
|
|
return new string[2] { "weapons@rifle@smg_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.GrenadeLauncher:
|
|
|
|
|
case WeaponHash.GrenadeLauncherSmoke:
|
|
|
|
|
case WeaponHash.CompactGrenadeLauncher:
|
|
|
|
|
return new string[2] { "weapons@heavy@lo@grenade_launcher_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.RPG:
|
|
|
|
|
return new string[2] { "weapons@heavy@lo@rpg_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.CombatMG:
|
|
|
|
|
case WeaponHash.CombatMGMk2:
|
|
|
|
|
return new string[2] { "weapons@machinegun@lo@combat_mg_str", "reload_aim" };
|
|
|
|
|
case WeaponHash.MG:
|
|
|
|
|
return new string[2] { "weapons@machinegun@lo@mg_str", "reload_aim" };
|
|
|
|
|
default:
|
|
|
|
|
GTA.UI.Notification.Show($"~r~Reloading failed! Weapon ~g~[{CurrentWeaponHash}]~r~ no found!");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-28 17:50:04 +01:00
|
|
|
|
private void DisplayShooting()
|
|
|
|
|
{
|
|
|
|
|
if (!Character.IsInRange(Position, 0.5f))
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2021-12-28 17:50:04 +01:00
|
|
|
|
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
|
|
|
|
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, true, 2.0f, 0.5f, false, 0, false,
|
|
|
|
|
unchecked((uint)FiringPattern.FullAuto));
|
|
|
|
|
UpdateOnFootPosition();
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
2021-12-28 17:50:04 +01:00
|
|
|
|
else
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2021-12-28 17:50:04 +01:00
|
|
|
|
Function.Call(Hash.TASK_SHOOT_AT_COORD, Character.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z, 1500, unchecked((uint)FiringPattern.FullAuto));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DisplayAiming()
|
|
|
|
|
{
|
|
|
|
|
if (!Character.IsInRange(Position, 0.5f))
|
|
|
|
|
{
|
|
|
|
|
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
|
|
|
|
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, false, 0x3F000000, 0x40800000, false, 512, false, 0);
|
|
|
|
|
UpdateOnFootPosition();
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-28 17:50:04 +01:00
|
|
|
|
Character.Task.AimAt(AimCoords, 100);
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-28 17:50:04 +01:00
|
|
|
|
#endregion
|
2021-12-15 03:31:57 +01:00
|
|
|
|
|
|
|
|
|
private bool LastMoving;
|
|
|
|
|
private void WalkTo()
|
|
|
|
|
{
|
2021-12-24 03:16:16 +01:00
|
|
|
|
Vector3 predictPosition = Position + (Position - Character.Position) + Velocity;
|
|
|
|
|
float range = predictPosition.DistanceToSquared(Character.Position);
|
|
|
|
|
|
|
|
|
|
switch (Speed)
|
2021-12-15 03:31:57 +01:00
|
|
|
|
{
|
2021-12-24 03:16:16 +01:00
|
|
|
|
case 1:
|
|
|
|
|
if (!Character.IsWalking || range > 0.25f)
|
|
|
|
|
{
|
|
|
|
|
float nrange = range * 2;
|
|
|
|
|
if (nrange > 1.0f)
|
|
|
|
|
{
|
|
|
|
|
nrange = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Character.Task.GoStraightTo(predictPosition);
|
|
|
|
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, nrange);
|
|
|
|
|
}
|
|
|
|
|
LastMoving = true;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (!Character.IsRunning || range > 0.50f)
|
|
|
|
|
{
|
|
|
|
|
Character.Task.RunTo(predictPosition, true);
|
|
|
|
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
LastMoving = true;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
if (!Character.IsSprinting || range > 0.75f)
|
|
|
|
|
{
|
|
|
|
|
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, Character.Handle, predictPosition.X, predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
|
|
|
|
Function.Call(Hash.SET_RUN_SPRINT_MULTIPLIER_FOR_PLAYER, Character.Handle, 1.49f);
|
|
|
|
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
LastMoving = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (LastMoving)
|
|
|
|
|
{
|
|
|
|
|
Character.Task.StandStill(2000);
|
|
|
|
|
LastMoving = false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
2021-12-27 10:15:52 +01:00
|
|
|
|
UpdateOnFootPosition();
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-01 17:24:55 +01:00
|
|
|
|
private bool StuckDetection = false;
|
2021-12-27 10:15:52 +01:00
|
|
|
|
private ulong LastStuckTime;
|
|
|
|
|
private void UpdateOnFootPosition(bool updatePosition = true, bool updateRotation = true, bool updateVelocity = true)
|
|
|
|
|
{
|
2022-01-01 17:24:55 +01:00
|
|
|
|
ulong time = Util.GetTickCount64();
|
|
|
|
|
|
|
|
|
|
if (StuckDetection)
|
2021-12-27 10:15:52 +01:00
|
|
|
|
{
|
2022-01-01 17:24:55 +01:00
|
|
|
|
if (time - LastStuckTime >= 500)
|
2021-12-27 10:15:52 +01:00
|
|
|
|
{
|
2022-01-01 17:24:55 +01:00
|
|
|
|
StuckDetection = false;
|
2021-12-27 10:15:52 +01:00
|
|
|
|
|
2022-01-01 17:24:55 +01:00
|
|
|
|
if (Character.Position.DistanceTo(Position) > 5f)
|
|
|
|
|
{
|
|
|
|
|
Character.PositionNoOffset = Position;
|
|
|
|
|
Character.Rotation = Rotation;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (time - LastStuckTime >= 500)
|
|
|
|
|
{
|
|
|
|
|
if (Character.Position.DistanceTo(Position) > 5f)
|
2021-12-27 10:15:52 +01:00
|
|
|
|
{
|
2022-01-01 17:24:55 +01:00
|
|
|
|
StuckDetection = true;
|
|
|
|
|
LastStuckTime = time;
|
2021-12-27 10:15:52 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updatePosition)
|
|
|
|
|
{
|
2022-04-12 01:55:33 +02:00
|
|
|
|
float lerpValue = (int)((Latency * 1000 / 2) + (Main.MainNetworking.Latency * 1000 / 2)) * 2 / 50000f;
|
2021-12-27 10:15:52 +01:00
|
|
|
|
|
|
|
|
|
Vector2 biDimensionalPos = Vector2.Lerp(new Vector2(Character.Position.X, Character.Position.Y), new Vector2(Position.X + (Velocity.X / 5), Position.Y + (Velocity.Y / 5)), lerpValue);
|
|
|
|
|
float zPos = Util.Lerp(Character.Position.Z, Position.Z, 0.1f);
|
|
|
|
|
Character.PositionNoOffset = new Vector3(biDimensionalPos.X, biDimensionalPos.Y, zPos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updateRotation)
|
|
|
|
|
{
|
|
|
|
|
// You can find the ToQuaternion() for Rotation inside the VectorExtensions
|
|
|
|
|
Character.Quaternion = Quaternion.Lerp(Character.Quaternion, Rotation.ToQuaternion(), 0.10f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updateVelocity)
|
|
|
|
|
{
|
|
|
|
|
Character.Velocity = Velocity;
|
|
|
|
|
}
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
2021-12-27 11:05:01 +01:00
|
|
|
|
|
|
|
|
|
private string LoadAnim(string anim)
|
|
|
|
|
{
|
|
|
|
|
ulong startTime = Util.GetTickCount64();
|
|
|
|
|
|
|
|
|
|
while (!Function.Call<bool>(Hash.HAS_ANIM_DICT_LOADED, anim))
|
|
|
|
|
{
|
|
|
|
|
Script.Yield();
|
|
|
|
|
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
|
|
|
|
|
if (Util.GetTickCount64() - startTime >= 1000)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return anim;
|
|
|
|
|
}
|
2021-12-15 03:31:57 +01:00
|
|
|
|
}
|
|
|
|
|
}
|