2021-07-07 13:36:25 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Xml.Serialization;
|
|
|
|
|
using System.Collections.Generic;
|
2021-11-19 22:08:15 +01:00
|
|
|
|
using System.Runtime.InteropServices;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
|
|
|
|
using GTA;
|
|
|
|
|
using GTA.Native;
|
|
|
|
|
using GTA.Math;
|
|
|
|
|
|
|
|
|
|
namespace CoopClient
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
enum ETasks
|
|
|
|
|
{
|
|
|
|
|
CLIMB_LADDER = 47
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 12:00:37 +02:00
|
|
|
|
static class Util
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-07-13 16:30:33 +02:00
|
|
|
|
#region -- POINTER --
|
|
|
|
|
private static int SteeringAngleOffset { get; set; }
|
|
|
|
|
|
|
|
|
|
public static unsafe void NativeMemory()
|
|
|
|
|
{
|
2021-11-25 10:17:58 +01:00
|
|
|
|
IntPtr address;
|
2021-07-13 16:30:33 +02:00
|
|
|
|
|
2021-11-25 10:17:58 +01:00
|
|
|
|
address = Game.FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
|
|
|
|
|
if (address != IntPtr.Zero)
|
2021-07-13 16:30:33 +02:00
|
|
|
|
{
|
|
|
|
|
SteeringAngleOffset = *(int*)(address + 6) + 8;
|
|
|
|
|
}
|
2021-08-02 22:03:07 +02:00
|
|
|
|
|
2021-11-25 10:17:58 +01:00
|
|
|
|
address = Game.FindPattern("\x32\xc0\xf3\x0f\x11\x09", "xxxxxx"); // Weapon / Radio slowdown
|
|
|
|
|
if (address != IntPtr.Zero)
|
2021-08-02 22:03:07 +02:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
|
{
|
2021-11-25 10:17:58 +01:00
|
|
|
|
*(byte*)(address + i).ToPointer() = 0x90;
|
2021-08-02 22:03:07 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-13 16:30:33 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-25 10:17:58 +01:00
|
|
|
|
public static unsafe void CustomSteeringAngle(this Vehicle veh, float value)
|
2021-07-13 16:30:33 +02:00
|
|
|
|
{
|
2021-11-25 10:17:58 +01:00
|
|
|
|
IntPtr address = new IntPtr((long)veh.MemoryAddress);
|
2021-07-13 16:30:33 +02:00
|
|
|
|
if (address == IntPtr.Zero || SteeringAngleOffset == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 08:09:26 +02:00
|
|
|
|
*(float*)(address + SteeringAngleOffset).ToPointer() = value;
|
|
|
|
|
}
|
2021-07-13 16:30:33 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
2021-11-19 08:40:40 +01:00
|
|
|
|
public static Model ModelRequest(this int hash)
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
|
|
|
|
Model model = new Model(hash);
|
|
|
|
|
|
2021-12-12 22:00:06 +01:00
|
|
|
|
if (!model.IsValid)
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
2021-12-12 22:52:57 +01:00
|
|
|
|
//GTA.UI.Notification.Show("~y~Not valid!");
|
2021-12-12 22:00:06 +01:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
2021-12-12 22:00:06 +01:00
|
|
|
|
if (!model.IsLoaded)
|
|
|
|
|
{
|
|
|
|
|
return model.Request(1000) ? model : null;
|
2021-08-18 11:47:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-12 22:00:06 +01:00
|
|
|
|
return model;
|
2021-08-18 11:47:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 12:00:37 +02:00
|
|
|
|
public static bool IsBetween<T>(this T item, T start, T end)
|
|
|
|
|
{
|
|
|
|
|
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-16 22:26:45 +01:00
|
|
|
|
public static bool Compare<T, Y>(this Dictionary<T, Y> item, Dictionary<T, Y> item2)
|
|
|
|
|
{
|
|
|
|
|
if (item == null || item2 == null || item.Count != item2.Count)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (KeyValuePair<T, Y> pair in item)
|
|
|
|
|
{
|
2021-12-17 00:19:34 +01:00
|
|
|
|
if (item2.TryGetValue(pair.Key, out Y value) && Equals(value, pair.Value))
|
2021-12-16 22:26:45 +01:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-17 00:19:34 +01:00
|
|
|
|
// TryGetValue() or Equals failed
|
|
|
|
|
return false;
|
2021-12-16 22:26:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-17 00:19:34 +01:00
|
|
|
|
// No difference between item and item2
|
2021-12-16 22:26:45 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-19 22:08:15 +01:00
|
|
|
|
public static Vector3 LinearVectorLerp(Vector3 start, Vector3 end, ulong currentTime, int duration)
|
2021-07-11 03:05:07 +02:00
|
|
|
|
{
|
|
|
|
|
return new Vector3()
|
|
|
|
|
{
|
|
|
|
|
X = LinearFloatLerp(start.X, end.X, currentTime, duration),
|
|
|
|
|
Y = LinearFloatLerp(start.Y, end.Y, currentTime, duration),
|
|
|
|
|
Z = LinearFloatLerp(start.Z, end.Z, currentTime, duration),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-19 22:08:15 +01:00
|
|
|
|
public static float LinearFloatLerp(float start, float end, ulong currentTime, int duration)
|
2021-07-11 03:05:07 +02:00
|
|
|
|
{
|
|
|
|
|
return (end - start) * currentTime / duration + start;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-24 05:20:32 +01:00
|
|
|
|
public static dynamic Lerp(dynamic from, dynamic to, float fAlpha)
|
|
|
|
|
{
|
|
|
|
|
return (to - from) * fAlpha + from;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-19 08:40:40 +01:00
|
|
|
|
public static int GetResponsiblePedHandle(this Vehicle veh)
|
2021-08-16 13:24:32 +02:00
|
|
|
|
{
|
|
|
|
|
if (veh == null || veh.Handle == 0 || !veh.Exists())
|
|
|
|
|
{
|
2021-08-16 16:38:52 +02:00
|
|
|
|
return 0;
|
2021-08-16 13:24:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-16 16:38:52 +02:00
|
|
|
|
if (!veh.IsSeatFree(VehicleSeat.Driver))
|
2021-08-16 13:24:32 +02:00
|
|
|
|
{
|
2021-08-16 16:38:52 +02:00
|
|
|
|
return veh.GetPedOnSeat(VehicleSeat.Driver).Handle;
|
2021-08-16 13:24:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < veh.PassengerCapacity; i++)
|
|
|
|
|
{
|
2021-08-16 16:38:52 +02:00
|
|
|
|
if (!veh.IsSeatFree((VehicleSeat)i))
|
2021-08-16 13:24:32 +02:00
|
|
|
|
{
|
2021-08-16 16:38:52 +02:00
|
|
|
|
return veh.GetPedOnSeat((VehicleSeat)i).Handle;
|
2021-08-16 13:24:32 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-16 16:38:52 +02:00
|
|
|
|
return 0;
|
2021-08-16 13:24:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-19 08:40:40 +01:00
|
|
|
|
public static byte GetPedSpeed(this Ped ped)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
2021-07-09 03:28:58 +02:00
|
|
|
|
if (ped.IsSprinting)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
2021-07-09 03:28:58 +02:00
|
|
|
|
return 3;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
2021-12-17 01:27:42 +01:00
|
|
|
|
if (ped.IsRunning)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2021-12-17 01:27:42 +01:00
|
|
|
|
if (ped.IsWalking)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
2021-07-09 03:28:58 +02:00
|
|
|
|
return 1;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
2021-07-09 03:28:58 +02:00
|
|
|
|
|
2021-07-07 15:37:54 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-19 08:40:40 +01:00
|
|
|
|
public static Vector3 GetPedAimCoords(this Ped ped, bool isNpc)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
|
|
|
|
bool aimOrShoot = ped.IsAiming || ped.IsShooting && ped.Weapons.Current?.AmmoInClip != 0;
|
|
|
|
|
return aimOrShoot ? (isNpc ? GetLastWeaponImpact(ped) : RaycastEverything(new Vector2(0, 0))) : new Vector3();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-06 00:56:08 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Only works for players NOT NPCs
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Vector3</returns>
|
|
|
|
|
public static Vector3 GetVehicleAimCoords()
|
|
|
|
|
{
|
|
|
|
|
return RaycastEverything(new Vector2(0, 0));
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 22:03:01 +01:00
|
|
|
|
public static ushort? GetVehicleFlags(this Ped ped, Vehicle veh)
|
2021-07-10 23:41:28 +02:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
ushort? flags = 0;
|
2021-07-10 23:41:28 +02:00
|
|
|
|
|
|
|
|
|
if (veh.IsEngineRunning)
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.IsEngineRunning;
|
2021-07-10 23:41:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (veh.AreLightsOn)
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.AreLightsOn;
|
2021-07-10 23:41:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (veh.AreHighBeamsOn)
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.AreHighBeamsOn;
|
2021-07-10 23:41:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 12:00:37 +02:00
|
|
|
|
if (veh.IsSirenActive)
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.IsSirenActive;
|
2021-07-13 12:00:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-14 11:14:34 +02:00
|
|
|
|
if (veh.IsDead)
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.IsDead;
|
2021-08-14 11:14:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 23:18:15 +01:00
|
|
|
|
if (Function.Call<bool>(Hash.IS_HORN_ACTIVE, veh.Handle))
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.IsHornActive;
|
2021-12-13 23:18:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-19 00:53:03 +01:00
|
|
|
|
if (veh.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
|
2021-12-13 23:43:02 +01:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.IsTransformed;
|
2021-12-13 23:43:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-18 09:46:42 +01:00
|
|
|
|
if (veh.HasRoof && (veh.RoofState == VehicleRoofState.Opened || veh.RoofState == VehicleRoofState.Opening))
|
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
flags |= (ushort)VehicleDataFlags.RoofOpened;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (veh.IsTurretSeat((int)ped.SeatIndex))
|
|
|
|
|
{
|
|
|
|
|
flags |= (ushort)VehicleDataFlags.OnTurretSeat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (veh.IsPlane)
|
|
|
|
|
{
|
|
|
|
|
flags |= (ushort)VehicleDataFlags.IsPlane;
|
2021-12-18 09:46:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 23:41:28 +02:00
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-28 19:14:51 +01:00
|
|
|
|
public static ushort? GetPedFlags(this Ped ped, bool isPlayer = false)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
ushort? flags = 0;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
|
|
|
|
|
if (ped.IsAiming)
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsAiming;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 03:28:58 +02:00
|
|
|
|
if ((ped.IsShooting || isPlayer && Game.IsControlPressed(Control.Attack)) && ped.Weapons.Current?.AmmoInClip != 0)
|
2021-07-07 15:37:54 +02:00
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsShooting;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ped.IsReloading)
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsReloading;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ped.IsJumping)
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsJumping;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ped.IsRagdoll)
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsRagdoll;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ped.IsOnFire)
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsOnFire;
|
2021-07-07 15:37:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-27 17:26:16 +01:00
|
|
|
|
if (ped.IsInParachuteFreeFall)
|
|
|
|
|
{
|
2021-12-28 19:14:51 +01:00
|
|
|
|
flags |= (ushort)PedDataFlags.IsInParachuteFreeFall;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, ped.Handle, ETasks.CLIMB_LADDER)) // USING_LADDER
|
|
|
|
|
{
|
|
|
|
|
flags |= (ushort)PedDataFlags.IsOnLadder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ped.IsVaulting && !Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, ped.Handle, ETasks.CLIMB_LADDER))
|
|
|
|
|
{
|
|
|
|
|
flags |= (ushort)PedDataFlags.IsVaulting;
|
2021-12-27 17:26:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 15:37:54 +02:00
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-16 22:05:40 +01:00
|
|
|
|
public static Dictionary<byte, short> GetPedClothes(this Ped ped)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-12-16 22:05:40 +01:00
|
|
|
|
Dictionary<byte, short> result = new Dictionary<byte, short>();
|
|
|
|
|
for (byte i = 0; i < 11; i++)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-12-16 22:05:40 +01:00
|
|
|
|
short mod = Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
|
2021-07-07 13:36:25 +02:00
|
|
|
|
result.Add(i, mod);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 03:31:57 +01:00
|
|
|
|
public static Dictionary<uint, bool> GetWeaponComponents(this Weapon weapon)
|
2021-12-15 01:25:16 +01:00
|
|
|
|
{
|
2021-12-15 03:31:57 +01:00
|
|
|
|
Dictionary<uint, bool> result = null;
|
2021-12-15 01:25:16 +01:00
|
|
|
|
|
|
|
|
|
if (weapon.Components.Count > 0)
|
|
|
|
|
{
|
2021-12-15 03:31:57 +01:00
|
|
|
|
result = new Dictionary<uint, bool>();
|
2021-12-15 01:25:16 +01:00
|
|
|
|
|
|
|
|
|
foreach (var comp in weapon.Components)
|
|
|
|
|
{
|
2021-12-15 03:31:57 +01:00
|
|
|
|
result.Add((uint)comp.ComponentHash, comp.Active);
|
2021-12-15 01:25:16 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-19 08:40:40 +01:00
|
|
|
|
public static Dictionary<int, int> GetVehicleMods(this VehicleModCollection mods)
|
2021-08-14 11:14:34 +02:00
|
|
|
|
{
|
|
|
|
|
Dictionary<int, int> result = new Dictionary<int, int>();
|
2021-11-19 08:40:40 +01:00
|
|
|
|
foreach (VehicleMod mod in mods.ToArray())
|
2021-08-14 11:14:34 +02:00
|
|
|
|
{
|
|
|
|
|
result.Add((int)mod.Type, mod.Index);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 22:03:01 +01:00
|
|
|
|
public static VehicleDamageModel GetVehicleDamageModel(this Vehicle veh)
|
2021-08-14 11:14:34 +02:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
VehicleDamageModel result = new VehicleDamageModel()
|
2021-08-14 11:14:34 +02:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
BrokenDoors = 0,
|
|
|
|
|
BrokenWindows = 0,
|
|
|
|
|
BurstedTires = 0,
|
|
|
|
|
PuncturedTires = 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Broken windows
|
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
|
|
|
|
|
{
|
|
|
|
|
result.BrokenWindows |= (byte)(1 << i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Broken doors
|
|
|
|
|
foreach (VehicleDoor door in veh.Doors)
|
|
|
|
|
{
|
|
|
|
|
if (door.IsBroken)
|
|
|
|
|
{
|
|
|
|
|
result.BrokenDoors |= (byte)(1 << (byte)door.Index);
|
|
|
|
|
}
|
2021-08-14 11:14:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 22:03:01 +01:00
|
|
|
|
// Bursted and Punctured tires
|
|
|
|
|
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
|
2021-08-14 11:14:34 +02:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
if (wheel.IsBursted)
|
|
|
|
|
{
|
|
|
|
|
result.BurstedTires |= (ushort)(1 << (int)wheel.BoneId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wheel.IsPunctured)
|
2021-08-14 11:14:34 +02:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
result.PuncturedTires |= (ushort)(1 << (int)wheel.BoneId);
|
|
|
|
|
}
|
2021-08-14 11:14:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 22:03:01 +01:00
|
|
|
|
public static void SetVehicleDamageModel(this Vehicle veh, VehicleDamageModel model, bool leavedoors = true)
|
2021-11-19 08:40:40 +01:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
for (int i = 0; i < 8; i++)
|
2021-11-19 08:40:40 +01:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
if ((model.BrokenDoors & (byte)(1 << i)) != 0)
|
2021-11-19 08:40:40 +01:00
|
|
|
|
{
|
2021-12-23 22:03:01 +01:00
|
|
|
|
veh.Doors[(VehicleDoorIndex)i].Break(leavedoors);
|
|
|
|
|
}
|
|
|
|
|
else if (veh.Doors[(VehicleDoorIndex)i].IsBroken)
|
|
|
|
|
{
|
|
|
|
|
// The vehicle can only fix a door if the vehicle was completely fixed
|
|
|
|
|
veh.Repair();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((model.BrokenWindows & (byte)(1 << i)) != 0)
|
|
|
|
|
{
|
|
|
|
|
veh.Windows[(VehicleWindowIndex)i].Smash();
|
|
|
|
|
}
|
|
|
|
|
else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
|
|
|
|
|
{
|
|
|
|
|
veh.Windows[(VehicleWindowIndex)i].Repair();
|
2021-11-19 08:40:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 22:03:01 +01:00
|
|
|
|
foreach (VehicleWheel wheel in veh.Wheels)
|
|
|
|
|
{
|
|
|
|
|
if ((model.PuncturedTires & (ushort)(1 << (int)wheel.BoneId)) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (!wheel.IsPunctured)
|
|
|
|
|
{
|
|
|
|
|
wheel.Puncture();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (wheel.IsPunctured)
|
|
|
|
|
{
|
|
|
|
|
wheel.Fix();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((model.BurstedTires & (ushort)(1 << (int)wheel.BoneId)) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (!wheel.IsBursted)
|
|
|
|
|
{
|
|
|
|
|
wheel.Burst();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (wheel.IsBursted)
|
|
|
|
|
{
|
|
|
|
|
wheel.Fix();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-19 08:40:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
public static Settings ReadSettings()
|
|
|
|
|
{
|
|
|
|
|
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
|
|
|
|
|
|
|
|
|
string path = Directory.GetCurrentDirectory() + "\\scripts\\CoopSettings.xml";
|
|
|
|
|
Settings settings = null;
|
|
|
|
|
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
using (FileStream stream = File.OpenRead(path))
|
|
|
|
|
{
|
|
|
|
|
settings = (Settings)ser.Deserialize(stream);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-10 11:31:36 +01:00
|
|
|
|
using (FileStream stream = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
|
|
|
|
ser.Serialize(stream, settings);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
using (FileStream stream = File.OpenWrite(path))
|
|
|
|
|
{
|
|
|
|
|
ser.Serialize(stream, settings = new Settings());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SaveSettings()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
string path = Directory.GetCurrentDirectory() + "\\scripts\\CoopSettings.xml";
|
|
|
|
|
|
|
|
|
|
using (FileStream stream = new FileStream(path, File.Exists(path) ? FileMode.Truncate : FileMode.Create, FileAccess.ReadWrite))
|
|
|
|
|
{
|
|
|
|
|
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
|
|
|
|
ser.Serialize(stream, Main.MainSettings);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 GetLastWeaponImpact(Ped ped)
|
|
|
|
|
{
|
|
|
|
|
OutputArgument coord = new OutputArgument();
|
|
|
|
|
if (!Function.Call<bool>(Hash.GET_PED_LAST_WEAPON_IMPACT_COORD, ped.Handle, coord))
|
|
|
|
|
{
|
|
|
|
|
return new Vector3();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return coord.GetResult<Vector3>();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-06 00:56:08 +01:00
|
|
|
|
public static bool IsTurretSeat(this Vehicle veh, int seat)
|
|
|
|
|
{
|
|
|
|
|
if (!Function.Call<bool>(Hash.DOES_VEHICLE_HAVE_WEAPONS, veh.Handle))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (seat)
|
|
|
|
|
{
|
|
|
|
|
case -1:
|
|
|
|
|
return (VehicleHash)veh.Model.Hash == VehicleHash.Rhino
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Khanjari
|
2021-12-10 17:04:33 +01:00
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.FireTruck
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Riot2
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus2
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
|
|
|
|
|
case 0:
|
|
|
|
|
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc;
|
2021-12-06 00:56:08 +01:00
|
|
|
|
case 1:
|
|
|
|
|
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical2
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical3
|
2021-12-10 17:04:33 +01:00
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.HalfTrack
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
|
2021-12-06 00:56:08 +01:00
|
|
|
|
case 2:
|
|
|
|
|
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|
2021-12-10 17:04:33 +01:00
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
|
2021-12-06 00:56:08 +01:00
|
|
|
|
case 3:
|
2021-12-10 17:04:33 +01:00
|
|
|
|
return (VehicleHash)veh.Model.Hash == VehicleHash.Limo2
|
|
|
|
|
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dinghy5;
|
2021-12-06 00:56:08 +01:00
|
|
|
|
case 7:
|
|
|
|
|
return (VehicleHash)veh.Model.Hash == VehicleHash.Insurgent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
public static double DegToRad(double deg)
|
|
|
|
|
{
|
|
|
|
|
return deg * Math.PI / 180.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 RotationToDirection(Vector3 rotation)
|
|
|
|
|
{
|
|
|
|
|
double z = DegToRad(rotation.Z);
|
|
|
|
|
double x = DegToRad(rotation.X);
|
|
|
|
|
double num = Math.Abs(Math.Cos(x));
|
|
|
|
|
|
|
|
|
|
return new Vector3
|
|
|
|
|
{
|
|
|
|
|
X = (float)(-Math.Sin(z) * num),
|
|
|
|
|
Y = (float)(Math.Cos(z) * num),
|
|
|
|
|
Z = (float)Math.Sin(x)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool WorldToScreenRel(Vector3 worldCoords, out Vector2 screenCoords)
|
|
|
|
|
{
|
|
|
|
|
OutputArgument num1 = new OutputArgument();
|
|
|
|
|
OutputArgument num2 = new OutputArgument();
|
|
|
|
|
|
|
|
|
|
if (!Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, worldCoords.X, worldCoords.Y, worldCoords.Z, num1, num2))
|
|
|
|
|
{
|
|
|
|
|
screenCoords = new Vector2();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
screenCoords = new Vector2((num1.GetResult<float>() - 0.5f) * 2, (num2.GetResult<float>() - 0.5f) * 2);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 ScreenRelToWorld(Vector3 camPos, Vector3 camRot, Vector2 coord)
|
|
|
|
|
{
|
|
|
|
|
Vector3 camForward = RotationToDirection(camRot);
|
|
|
|
|
Vector3 rotUp = camRot + new Vector3(10, 0, 0);
|
|
|
|
|
Vector3 rotDown = camRot + new Vector3(-10, 0, 0);
|
|
|
|
|
Vector3 rotLeft = camRot + new Vector3(0, 0, -10);
|
|
|
|
|
Vector3 rotRight = camRot + new Vector3(0, 0, 10);
|
|
|
|
|
|
|
|
|
|
Vector3 camRight = RotationToDirection(rotRight) - RotationToDirection(rotLeft);
|
|
|
|
|
Vector3 camUp = RotationToDirection(rotUp) - RotationToDirection(rotDown);
|
|
|
|
|
|
|
|
|
|
double rollRad = -DegToRad(camRot.Y);
|
|
|
|
|
|
|
|
|
|
Vector3 camRightRoll = camRight * (float)Math.Cos(rollRad) - camUp * (float)Math.Sin(rollRad);
|
|
|
|
|
Vector3 camUpRoll = camRight * (float)Math.Sin(rollRad) + camUp * (float)Math.Cos(rollRad);
|
|
|
|
|
|
|
|
|
|
Vector3 point3D = camPos + camForward * 10.0f + camRightRoll + camUpRoll;
|
|
|
|
|
if (!WorldToScreenRel(point3D, out Vector2 point2D))
|
|
|
|
|
{
|
|
|
|
|
return camPos + camForward * 10.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector3 point3DZero = camPos + camForward * 10.0f;
|
|
|
|
|
if (!WorldToScreenRel(point3DZero, out Vector2 point2DZero))
|
|
|
|
|
{
|
|
|
|
|
return camPos + camForward * 10.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const double eps = 0.001;
|
|
|
|
|
if (Math.Abs(point2D.X - point2DZero.X) < eps || Math.Abs(point2D.Y - point2DZero.Y) < eps)
|
|
|
|
|
{
|
|
|
|
|
return camPos + camForward * 10.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float scaleX = (coord.X - point2DZero.X) / (point2D.X - point2DZero.X);
|
|
|
|
|
float scaleY = (coord.Y - point2DZero.Y) / (point2D.Y - point2DZero.Y);
|
|
|
|
|
|
|
|
|
|
return camPos + camForward * 10.0f + camRightRoll * scaleX + camUpRoll * scaleY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 RaycastEverything(Vector2 screenCoord)
|
|
|
|
|
{
|
|
|
|
|
Vector3 camPos = GameplayCamera.Position;
|
|
|
|
|
Vector3 camRot = GameplayCamera.Rotation;
|
|
|
|
|
const float raycastToDist = 100.0f;
|
|
|
|
|
const float raycastFromDist = 1f;
|
|
|
|
|
|
|
|
|
|
Vector3 target3D = ScreenRelToWorld(camPos, camRot, screenCoord);
|
|
|
|
|
Vector3 source3D = camPos;
|
|
|
|
|
|
|
|
|
|
Entity ignoreEntity = Game.Player.Character;
|
|
|
|
|
if (Game.Player.Character.IsInVehicle())
|
|
|
|
|
{
|
|
|
|
|
ignoreEntity = Game.Player.Character.CurrentVehicle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector3 dir = target3D - source3D;
|
|
|
|
|
dir.Normalize();
|
|
|
|
|
RaycastResult raycastResults = World.Raycast(source3D + dir * raycastFromDist,
|
|
|
|
|
source3D + dir * raycastToDist,
|
2021-08-18 11:47:59 +02:00
|
|
|
|
IntersectFlags.Everything,
|
2021-07-07 13:36:25 +02:00
|
|
|
|
ignoreEntity);
|
|
|
|
|
|
|
|
|
|
if (raycastResults.DidHit)
|
|
|
|
|
{
|
|
|
|
|
return raycastResults.HitPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return camPos + dir * raycastToDist;
|
|
|
|
|
}
|
2021-11-19 22:08:15 +01:00
|
|
|
|
|
|
|
|
|
[DllImport("kernel32.dll")]
|
|
|
|
|
public static extern ulong GetTickCount64();
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2021-12-24 06:33:00 +01:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static class VectorExtensions
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static Vector3 ToVector(this Quaternion vec)
|
|
|
|
|
{
|
|
|
|
|
return new Vector3()
|
|
|
|
|
{
|
|
|
|
|
X = vec.X,
|
|
|
|
|
Y = vec.Y,
|
|
|
|
|
Z = vec.Z
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static Quaternion ToQuaternion(this Vector3 vec, float vW = 0.0f)
|
|
|
|
|
{
|
|
|
|
|
return new Quaternion()
|
|
|
|
|
{
|
|
|
|
|
X = vec.X,
|
|
|
|
|
Y = vec.Y,
|
|
|
|
|
Z = vec.Z,
|
|
|
|
|
W = vW
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static float Denormalize(this float h)
|
|
|
|
|
{
|
|
|
|
|
return h < 0f ? h + 360f : h;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static float ToRadians(this float val)
|
|
|
|
|
{
|
|
|
|
|
return (float)(Math.PI / 180) * val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Vector3 ToRadians(this Vector3 i)
|
|
|
|
|
{
|
|
|
|
|
return new Vector3()
|
|
|
|
|
{
|
|
|
|
|
X = ToRadians(i.X),
|
|
|
|
|
Y = ToRadians(i.Y),
|
|
|
|
|
Z = ToRadians(i.Z),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Quaternion ToQuaternion(this Vector3 vect)
|
|
|
|
|
{
|
|
|
|
|
vect = new Vector3()
|
|
|
|
|
{
|
|
|
|
|
X = vect.X.Denormalize() * -1,
|
|
|
|
|
Y = vect.Y.Denormalize() - 180f,
|
|
|
|
|
Z = vect.Z.Denormalize() - 180f,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vect = vect.ToRadians();
|
|
|
|
|
|
|
|
|
|
float rollOver2 = vect.Z * 0.5f;
|
|
|
|
|
float sinRollOver2 = (float)Math.Sin((double)rollOver2);
|
|
|
|
|
float cosRollOver2 = (float)Math.Cos((double)rollOver2);
|
|
|
|
|
float pitchOver2 = vect.Y * 0.5f;
|
|
|
|
|
float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
|
|
|
|
|
float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
|
|
|
|
|
float yawOver2 = vect.X * 0.5f; // pitch
|
|
|
|
|
float sinYawOver2 = (float)Math.Sin((double)yawOver2);
|
|
|
|
|
float cosYawOver2 = (float)Math.Cos((double)yawOver2);
|
|
|
|
|
Quaternion result = new Quaternion()
|
|
|
|
|
{
|
|
|
|
|
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
|
|
|
|
|
Y = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2,
|
|
|
|
|
Z = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2,
|
|
|
|
|
W = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2
|
|
|
|
|
};
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static LVector3 ToLVector(this Vector3 vec)
|
|
|
|
|
{
|
|
|
|
|
return new LVector3()
|
|
|
|
|
{
|
|
|
|
|
X = vec.X,
|
|
|
|
|
Y = vec.Y,
|
|
|
|
|
Z = vec.Z
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static LQuaternion ToLQuaternion(this Quaternion vec)
|
|
|
|
|
{
|
|
|
|
|
return new LQuaternion()
|
|
|
|
|
{
|
|
|
|
|
X = vec.X,
|
|
|
|
|
Y = vec.Y,
|
|
|
|
|
Z = vec.Z,
|
|
|
|
|
W = vec.W
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|