Skip to content

Instantly share code, notes, and snippets.

@ikt32
Last active March 13, 2017 14:29
Show Gist options
  • Save ikt32/d83a8ea80577df4092cc0ddd78c4ad0a to your computer and use it in GitHub Desktop.
Save ikt32/d83a8ea80577df4092cc0ddd78c4ad0a to your computer and use it in GitHub Desktop.
Very first attempt at gear locking in GTA V
using System;
using GTA;
using GTA.Native;
public class Gears : Script {
Random random = new Random();
public Gears() {
Tick += OnTick;
Interval = 0;
}
void OnTick(object sender, EventArgs e) {
Ped player = Game.Player.Character;
Vehicle vehicle = player.CurrentVehicle;
if (player.IsInVehicle() && vehicle.Model.IsCar) {
ulong address = vehicle.GetAddress;
uint gears = vehicle.CurrentGear;
float rpm = vehicle.CurrentRPM;
float clutch = vehicle.Clutch;
float throttle = vehicle.Throttle;
float turbo = vehicle.Turbo;
uint currGear = (0xFFFF0000 & gears) >> 16;
uint nextGear = 0x0000FFFF & gears;
// Park/Reverse. Gear 0. Prevent going forward in gear 0.
if (currGear == 0 && !Game.IsControlPressed(0, Control.VehicleBrake) && vehicle.Speed < 1.0f) {
vehicle.HandbrakeOn = true;
vehicle.BrakeLightsOn = true;
}
// Forward gears. Prevent reversing.
else if (currGear > 0 && !Game.IsControlPressed(0, Control.VehicleAccelerate) && Game.IsControlPressed(0, Control.VehicleBrake) && vehicle.Speed < 1.0f)
{
vehicle.HandbrakeOn = true;
vehicle.BrakeLightsOn = true;
}
else
{
vehicle.HandbrakeOn = false;
}
// Game wants to shift up. Triggered at high RPM, high speed.
// Desired result: high RPM, same gear (currGear)
if (currGear < nextGear) {
vehicle.CurrentGear = currGear | (currGear << 16);
vehicle.CurrentRPM = 1.6f;
vehicle.Clutch = 1.0f;
vehicle.Throttle = 1.0f;
}
// Game wants to shift down. Usually triggered when user accelerates
// while in a too high gear.
// Desired result: low RPM or stall, even. Stay in current gear!
// Otherwise: force car to drive anyway to keep RPM up.
// Current: Game cuts engine power
if (currGear > nextGear) {
vehicle.CurrentGear = currGear | (currGear << 16);
vehicle.Clutch = 1.0f;
vehicle.Throttle = 1.0f;
/*if (currGear == 2) {
vehicle.CurrentRPM = Game.GetControlNormal(0, Control.VehicleAccelerate) * 0.40f;
}
else
{
vehicle.Clutch = 1.0f;
vehicle.Throttle = 1.0f;
}*/
}
// Shift up
if (Game.IsControlJustPressed(0, Control.VehicleDuck)) {
vehicle.CurrentGear = currGear + 1 | (currGear + 1 << 16);
vehicle.Clutch = 0.1f;
vehicle.Throttle = 0.5f;
}
// Shift down
if (Game.IsControlJustPressed(0, Control.VehicleSelectNextWeapon)) {
if (currGear > 0) {
vehicle.CurrentGear = currGear - 1 | (currGear - 1 << 16);
if (vehicle.EngineRunning == false) {
vehicle.EngineRunning = true;
}
}
}
// Trying stuff
if (Game.IsControlPressed(0, Control.VehicleAim)) {
vehicle.Throttle = 1.0f;
vehicle.Clutch = 1.0f;
vehicle.CurrentRPM = 2.2f;
}
string info = "RPM: " + rpm +
"\nCurrGear: " + currGear +
"\nNextGear: " + nextGear +
"\nClutch: " + clutch +
"\nThrottle: " + throttle +
"\nTurbo: " + turbo +
"\nAddress: " + address.ToString("X");
Function.Call(Hash.SET_TEXT_FONT, 0);
Function.Call(Hash.SET_TEXT_SCALE, 0.4f, 0.4f);
Function.Call(Hash.SET_TEXT_COLOUR, 255, 255, 255, 255);
Function.Call(Hash.SET_TEXT_WRAP, 0.0, 1.0);
Function.Call(Hash.SET_TEXT_CENTRE, 0);
Function.Call(Hash.SET_TEXT_DROPSHADOW, 0, 0, 0, 0, 0);
Function.Call(Hash.SET_TEXT_EDGE, 1, 0, 0, 0, 205);
Function.Call(Hash._SET_TEXT_ENTRY, "STRING");
Function.Call(Hash._ADD_TEXT_COMPONENT_STRING, info);
Function.Call(Hash._DRAW_TEXT, 0.01, 0.5);
}
}
}
System::UInt32 Vehicle::CurrentGear::get()
{
unsigned char *const address = reinterpret_cast<unsigned char *>(Native::MemoryAccess::GetAddressOfEntity(Handle));
int offset = 0x7a0;
return address == 0 ? 0 : *reinterpret_cast<const System::UInt32 *>(address + offset);
}
void Vehicle::CurrentGear::set(System::UInt32 value)
{
unsigned char *const address = reinterpret_cast<unsigned char *>(Native::MemoryAccess::GetAddressOfEntity(Handle));
int offset = 0x7a0;
*(address + offset) = value;
}
float Vehicle::Clutch::get()
{
unsigned char *const address = reinterpret_cast<unsigned char *>(Native::MemoryAccess::GetAddressOfEntity(Handle));
int offset = 0x7E0;
return address == 0 ? 0 : *reinterpret_cast<const float *>(address + offset);
}
void Vehicle::Clutch::set(float value)
{
System::UInt64 address = Native::MemoryAccess::GetAddressOfEntity(Handle);
int offset = 0x7E0;
*reinterpret_cast<float *>(address + offset) = value;
}
float Vehicle::Turbo::get()
{
unsigned char *const address = reinterpret_cast<unsigned char *>(Native::MemoryAccess::GetAddressOfEntity(Handle));
int offset = 0x7F8;
return address == 0 ? 0 : *reinterpret_cast<const float *>(address + offset);
}
void Vehicle::Turbo::set(float value)
{
System::UInt64 address = Native::MemoryAccess::GetAddressOfEntity(Handle);
int offset = 0x7F8;
*reinterpret_cast<float *>(address + offset) = value;
}
float Vehicle::Throttle::get()
{
System::UInt64 address = Native::MemoryAccess::GetAddressOfEntity(Handle);
int offset = 0x7E4;
return *reinterpret_cast<float *>(address + offset);
}
void Vehicle::Throttle::set(float value)
{
System::UInt64 address = Native::MemoryAccess::GetAddressOfEntity(Handle);
int offset = 0x7E4;
*reinterpret_cast<float *>(address + offset) = value;
}
System::UInt64 Vehicle::GetAddress::get()
{
const System::UInt64 address = Native::MemoryAccess::GetAddressOfEntity(Handle);
return address;
}
@ikt32
Copy link
Author

ikt32 commented Mar 12, 2017

This is a ScriptHookVDotNet file.
vehicle.cpp was modified from ScriptHookVDotNet to access more CVehicle members. If, for some reason, you want to re-build the version I started everything with, SHVDN version 2.something was used. Version 3 onwards is fully C# for game code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment