2020-12-02 16:19:16 -05:00
|
|
|
#include "pch.h"
|
|
|
|
#include "Vehicle.h"
|
2021-01-18 04:53:24 -05:00
|
|
|
#include "Menu.h"
|
2021-01-03 06:48:07 -05:00
|
|
|
#include "Ui.h"
|
|
|
|
#include "Util.h"
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
Vehicle::Vehicle()
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
ParseVehiclesIDE();
|
|
|
|
ParseCarcolsDAT();
|
2020-12-02 16:19:16 -05:00
|
|
|
Events::processScriptsEvent += [this]
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (!m_bImagesLoaded)
|
2021-02-24 16:54:45 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
Util::LoadTexturesInDirRecursive(
|
|
|
|
PLUGIN_PATH((char*)"CheatMenu\\vehicles\\images\\"), ".jpg", m_Spawner.m_VehData.m_Categories,
|
|
|
|
m_Spawner.m_VehData.m_ImagesList);
|
|
|
|
Util::LoadTexturesInDirRecursive(
|
|
|
|
PLUGIN_PATH((char*)"CheatMenu\\vehicles\\components\\"), ".jpg", m_TuneData.m_Categories,
|
|
|
|
m_TuneData.m_ImagesList);
|
|
|
|
Util::LoadTexturesInDirRecursive(
|
|
|
|
PLUGIN_PATH((char*)"CheatMenu\\vehicles\\paintjobs\\"), ".png", m_TextureData.m_Categories,
|
|
|
|
m_TextureData.m_ImagesList);
|
|
|
|
|
|
|
|
m_bImagesLoaded = true;
|
2021-02-24 16:54:45 -05:00
|
|
|
}
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
uint timer = CTimer::m_snTimeInMilliseconds;
|
|
|
|
CPlayerPed* player = FindPlayerPed();
|
|
|
|
CVehicle* veh = player->m_pVehicle;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2020-12-19 13:05:12 -05:00
|
|
|
if (player && veh)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
int hveh = CPools::GetVehicleRef(veh);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::HotKeyPressed(Menu::m_HotKeys.flipVeh))
|
2021-01-18 04:53:24 -05:00
|
|
|
{
|
|
|
|
float roll;
|
|
|
|
Command<Commands::GET_CAR_ROLL>(hveh, &roll);
|
|
|
|
roll += 180;
|
|
|
|
Command<Commands::SET_CAR_ROLL>(hveh, roll);
|
|
|
|
Command<Commands::SET_CAR_ROLL>(hveh, roll); // z rot fix
|
|
|
|
}
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::HotKeyPressed(Menu::m_HotKeys.fixVeh))
|
2021-01-18 04:53:24 -05:00
|
|
|
{
|
|
|
|
player->m_pVehicle->Fix();
|
|
|
|
player->m_pVehicle->m_fHealth = 1000.0f;
|
2021-02-24 16:54:45 -05:00
|
|
|
CHud::SetHelpMessage("Vehicle fixed", false, false, false);
|
2021-01-18 04:53:24 -05:00
|
|
|
}
|
2021-02-01 08:31:20 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::HotKeyPressed(Menu::m_HotKeys.vehEngine))
|
2021-02-01 08:31:20 -05:00
|
|
|
{
|
|
|
|
bool state = !veh->m_nVehicleFlags.bEngineBroken || veh->m_nVehicleFlags.bEngineOn;
|
|
|
|
|
|
|
|
if (state)
|
2021-02-24 16:54:45 -05:00
|
|
|
CHud::SetHelpMessage("Vehicle engine off", false, false, false);
|
2021-02-01 08:31:20 -05:00
|
|
|
else
|
2021-02-24 16:54:45 -05:00
|
|
|
CHud::SetHelpMessage("Vehicle engine on", false, false, false);
|
2021-02-01 08:31:20 -05:00
|
|
|
|
|
|
|
veh->m_nVehicleFlags.bEngineBroken = state;
|
|
|
|
veh->m_nVehicleFlags.bEngineOn = !state;
|
|
|
|
}
|
2021-02-02 02:59:01 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::HotKeyPressed(Menu::m_HotKeys.vehInstantStart))
|
2021-02-02 02:59:01 -05:00
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hveh, 40.0f);
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::HotKeyPressed(Menu::m_HotKeys.vehInstantStop))
|
2021-02-02 02:59:01 -05:00
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hveh, 0);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_bNoDamage)
|
2020-12-21 15:24:07 -05:00
|
|
|
{
|
|
|
|
veh->m_nPhysicalFlags.bBulletProof = true;
|
|
|
|
veh->m_nPhysicalFlags.bExplosionProof = true;
|
|
|
|
veh->m_nPhysicalFlags.bFireProof = true;
|
|
|
|
veh->m_nPhysicalFlags.bCollisionProof = true;
|
|
|
|
veh->m_nPhysicalFlags.bMeeleProof = true;
|
2021-02-24 16:54:45 -05:00
|
|
|
veh->m_nVehicleFlags.bCanBeDamaged = true;
|
2020-12-21 15:24:07 -05:00
|
|
|
}
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
player->m_nPedFlags.CantBeKnockedOffBike = m_bDontFallBike ? 1 : 2;
|
|
|
|
Command<Commands::SET_CAR_HEAVY>(hveh, m_bVehHeavy);
|
|
|
|
Command<Commands::SET_CAR_WATERTIGHT>(hveh, m_bVehWatertight);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_UnlimitedNitro.m_bEnabled && player->m_pVehicle->m_nVehicleSubClass == VEHICLE_AUTOMOBILE)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
patch::Set<BYTE>(0x969165, 0, true); // All cars have nitro
|
|
|
|
patch::Set<BYTE>(0x96918B, 0, true); // All taxis have nitro
|
|
|
|
|
|
|
|
if (KeyPressed(VK_LBUTTON))
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (!m_UnlimitedNitro.m_bCompAdded)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
AddComponent("1010", false);
|
2021-06-18 12:49:11 -04:00
|
|
|
m_UnlimitedNitro.m_bCompAdded = true;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_UnlimitedNitro.m_bCompAdded)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
RemoveComponent("1010", false);
|
2021-06-18 12:49:11 -04:00
|
|
|
m_UnlimitedNitro.m_bCompAdded = false;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_bLockSpeed)
|
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hveh, m_fLockSpeed);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Neon.m_bRainbowEffect && timer - m_Neon.m_nRainbowTimer > 50)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
int red, green, blue;
|
|
|
|
|
|
|
|
Util::RainbowValues(red, green, blue, 0.25);
|
2021-01-18 04:53:24 -05:00
|
|
|
InstallNeon(veh, red, green, blue);
|
2021-06-18 12:49:11 -04:00
|
|
|
m_Neon.m_nRainbowTimer = timer;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Traffic neons
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Neon.m_bApplyOnTraffic && timer - m_Neon.m_bTrafficTimer > 1000)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
for (CVehicle* veh : CPools::ms_pVehiclePool)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
int chance = 0;
|
|
|
|
|
|
|
|
if (veh->m_nVehicleClass == CLASS_NORMAL) // Normal
|
2021-02-24 16:54:45 -05:00
|
|
|
chance = Random(1, 20);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (veh->m_nVehicleClass == CLASS_RICHFAMILY) // Rich family
|
2021-02-24 16:54:45 -05:00
|
|
|
chance = Random(1, 4);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (veh->m_nVehicleClass == CLASS_EXECUTIVE) // Executive
|
2021-02-24 16:54:45 -05:00
|
|
|
chance = Random(1, 3);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-01-18 04:53:24 -05:00
|
|
|
if (chance == 1 && !IsNeonInstalled(veh) && veh->m_pDriver != player)
|
2021-02-24 16:54:45 -05:00
|
|
|
InstallNeon(veh, Random(0, 255), Random(0, 255), Random(0, 255));
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
2021-06-18 12:49:11 -04:00
|
|
|
m_Neon.m_bTrafficTimer = timer;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_bBikeFly && veh && veh->IsDriver(player))
|
2020-12-05 16:34:27 -05:00
|
|
|
{
|
|
|
|
if (veh->m_nVehicleSubClass == VEHICLE_BIKE || veh->m_nVehicleSubClass == VEHICLE_BMX)
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
if (sqrt(veh->m_vecMoveSpeed.x * veh->m_vecMoveSpeed.x
|
2021-06-18 12:49:11 -04:00
|
|
|
+ veh->m_vecMoveSpeed.y * veh->m_vecMoveSpeed.y
|
|
|
|
+ veh->m_vecMoveSpeed.z * veh->m_vecMoveSpeed.z
|
|
|
|
) > 0.0
|
|
|
|
&& CTimer::ms_fTimeStep > 0.0)
|
2020-12-05 16:34:27 -05:00
|
|
|
{
|
2020-12-09 08:15:50 -05:00
|
|
|
veh->FlyingControl(3, -9999.9902f, -9999.9902f, -9999.9902f, -9999.9902f);
|
2020-12-05 16:34:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-02 16:19:16 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-03-16 03:12:59 -04:00
|
|
|
Vehicle::~Vehicle()
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
Util::ReleaseTextures(m_Spawner.m_VehData.m_ImagesList);
|
|
|
|
Util::ReleaseTextures(m_TuneData.m_ImagesList);
|
|
|
|
Util::ReleaseTextures(m_TextureData.m_ImagesList);
|
2021-03-16 03:12:59 -04:00
|
|
|
}
|
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
void Vehicle::AddComponent(const std::string& component, const bool display_message)
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
try
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CPlayerPed* player = FindPlayerPed();
|
2020-12-02 16:19:16 -05:00
|
|
|
int icomp = std::stoi(component);
|
|
|
|
int hveh = CPools::GetVehicleRef(player->m_pVehicle);
|
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
CStreaming::RequestModel(icomp, eStreamingFlags::PRIORITY_REQUEST);
|
2021-01-13 13:25:28 -05:00
|
|
|
CStreaming::LoadAllRequestedModels(true);
|
2020-12-02 16:19:16 -05:00
|
|
|
player->m_pVehicle->AddVehicleUpgrade(icomp);
|
|
|
|
CStreaming::SetModelIsDeletable(icomp);
|
|
|
|
|
|
|
|
if (display_message)
|
|
|
|
CHud::SetHelpMessage("Component added", false, false, false);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-02-25 17:45:41 -05:00
|
|
|
flog << "Failed to component to vehicle " << component << std::endl;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Vehicle::RemoveComponent(const std::string& component, const bool display_message)
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
try
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CPlayerPed* player = FindPlayerPed();
|
2020-12-02 16:19:16 -05:00
|
|
|
int icomp = std::stoi(component);
|
|
|
|
int hveh = CPools::GetVehicleRef(player->m_pVehicle);
|
|
|
|
|
|
|
|
player->m_pVehicle->RemoveVehicleUpgrade(icomp);
|
|
|
|
|
|
|
|
if (display_message)
|
|
|
|
CHud::SetHelpMessage("Component removed", false, false, false);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-02-25 17:45:41 -05:00
|
|
|
flog << "Failed to remove component from vehicle " << component << std::endl;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-20 14:23:32 -05:00
|
|
|
// Why did I do this shit? Guess it was the weather
|
2020-12-02 16:19:16 -05:00
|
|
|
int Vehicle::GetRandomTrainIdForModel(int model)
|
|
|
|
{
|
|
|
|
static int train_ids[] = {
|
2021-06-18 12:49:11 -04:00
|
|
|
8, 9, // model 449
|
|
|
|
0, 3, 6, 10, 12, 13, // model 537
|
|
|
|
1, 5, 15 // model 538
|
2020-12-02 16:19:16 -05:00
|
|
|
};
|
|
|
|
int _start = 0, _end = 0;
|
|
|
|
|
|
|
|
switch (model)
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
case 449:
|
|
|
|
_start = 0;
|
|
|
|
_end = 1;
|
|
|
|
break;
|
|
|
|
case 537:
|
|
|
|
_start = 2;
|
|
|
|
_end = 7;
|
|
|
|
break;
|
|
|
|
case 538:
|
|
|
|
_start = 8;
|
|
|
|
_end = 10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CHud::SetHelpMessage("Invalid train model", false, false, false);
|
|
|
|
return -1;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
2021-02-24 16:54:45 -05:00
|
|
|
int id = Random(_start, _end);
|
2020-12-20 14:23:32 -05:00
|
|
|
return train_ids[id];
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get vehicle HandlingId
|
|
|
|
void Vehicle::ParseVehiclesIDE()
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::string m_FilePath = std::string(paths::GetGameDirPathA()) + "/data/vehicles.ide";
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (fs::exists(m_FilePath))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::ifstream file(m_FilePath);
|
2020-12-02 16:19:16 -05:00
|
|
|
std::string line;
|
|
|
|
|
|
|
|
while (getline(file, line))
|
|
|
|
{
|
|
|
|
if (line[0] <= '0' || line[0] >= '9')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
std::stringstream ss(line);
|
|
|
|
|
|
|
|
// model
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
|
|
|
|
int model = std::stoi(temp);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
// modelname, txd, type, handlingId
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
|
|
|
|
temp.erase(std::remove_if(temp.begin(), temp.end(), ::isspace), temp.end());
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
m_VehicleIDE[model] = temp;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-02-25 17:45:41 -05:00
|
|
|
flog << "Error while parsing line, " << line << std::endl;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
else flog << "Vehicle.ide file not found";
|
|
|
|
}
|
|
|
|
|
|
|
|
void Vehicle::ParseCarcolsDAT()
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::string m_FilePath = std::string(paths::GetGameDirPathA()) + "/data/carcols.dat";
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (fs::exists(m_FilePath))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::ifstream file(m_FilePath);
|
2020-12-02 16:19:16 -05:00
|
|
|
std::string line;
|
|
|
|
|
|
|
|
bool car_section = false;
|
|
|
|
bool col_section = false;
|
|
|
|
int count = 0;
|
|
|
|
while (getline(file, line))
|
|
|
|
{
|
|
|
|
if (line[0] == '#' || line == "")
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (line[0] == 'c' && line[1] == 'a' && line[2] == 'r')
|
|
|
|
{
|
|
|
|
car_section = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (line[0] == 'c' && line[1] == 'o' && line[2] == 'l')
|
|
|
|
{
|
|
|
|
col_section = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (line[0] == 'e' && line[1] == 'n' && line[2] == 'd')
|
|
|
|
{
|
|
|
|
car_section = false;
|
|
|
|
col_section = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (col_section)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
std::stringstream ss(line);
|
|
|
|
|
|
|
|
std::replace(temp.begin(), temp.end(), '.', ','); // fix one instance where . is used instead of ,
|
|
|
|
|
|
|
|
// red, green, blue
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
int red = std::stoi(temp);
|
|
|
|
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
int green = std::stoi(temp);
|
|
|
|
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
int blue = std::stoi(temp);
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
std::vector<float> color = {red / 255.0f, green / 255.0f, blue / 255.0f};
|
|
|
|
m_CarcolsColorData.push_back(color);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-02-25 17:45:41 -05:00
|
|
|
flog << "Error while parsing car line, " << line << std::endl;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (car_section)
|
|
|
|
{
|
|
|
|
std::string temp;
|
|
|
|
std::stringstream ss(line);
|
|
|
|
|
|
|
|
getline(ss, temp, ',');
|
|
|
|
std::string name = temp;
|
2021-02-24 16:54:45 -05:00
|
|
|
while (getline(ss, temp, ','))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::for_each(name.begin(), name.end(), [](char& c)
|
|
|
|
{
|
2020-12-02 16:19:16 -05:00
|
|
|
c = ::toupper(c);
|
|
|
|
});
|
|
|
|
|
|
|
|
int val = std::stoi(temp);
|
2021-06-18 12:49:11 -04:00
|
|
|
if (!(std::find(m_CarcolsCarData[name].begin(), m_CarcolsCarData[name].end(), val) !=
|
|
|
|
m_CarcolsCarData[name].end()))
|
|
|
|
m_CarcolsCarData[name].push_back(val);
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-02-25 17:45:41 -05:00
|
|
|
flog << "Error while parsing car line, " << line << std::endl;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
2021-02-25 17:45:41 -05:00
|
|
|
else flog << "Error locating Vehicle.ide";
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
void Vehicle::SpawnVehicle(std::string& smodel)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CPlayerPed* player = FindPlayerPed();
|
2020-12-02 16:19:16 -05:00
|
|
|
int hplayer = CPools::GetPedRef(player);
|
|
|
|
|
|
|
|
int imodel = std::stoi(smodel);
|
2021-02-24 16:54:45 -05:00
|
|
|
CVehicle* veh = nullptr;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2020-12-24 14:31:26 -05:00
|
|
|
int interior = player->m_nAreaCode;
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
if (Command<Commands::IS_MODEL_AVAILABLE>(imodel))
|
|
|
|
{
|
|
|
|
CVector pos = player->GetPosition();
|
|
|
|
int speed = 0;
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (player->m_nPedFlags.bInVehicle && m_Spawner.m_bSpawnInside)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
int hveh = 0;
|
|
|
|
Command<Commands::GET_CAR_CHAR_IS_USING>(hplayer, &hveh);
|
2021-02-24 16:54:45 -05:00
|
|
|
CVehicle* pveh = CPools::GetVehicle(hveh);
|
2020-12-02 16:19:16 -05:00
|
|
|
pos = pveh->GetPosition();
|
|
|
|
|
|
|
|
Command<Commands::GET_CAR_SPEED>(hveh, &speed);
|
|
|
|
|
|
|
|
Command<Commands::WARP_CHAR_FROM_CAR_TO_COORD>(hplayer, pos.x, pos.y, pos.z);
|
|
|
|
|
|
|
|
if (pveh->m_nVehicleClass == VEHICLE_TRAIN)
|
|
|
|
Command<Commands::DELETE_MISSION_TRAIN>(hveh);
|
|
|
|
else
|
|
|
|
Command<Commands::DELETE_CAR>(hveh);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interior == 0)
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Spawner.m_bSpawnInAir && (CModelInfo::IsHeliModel(imodel) || CModelInfo::IsPlaneModel(imodel)))
|
2020-12-02 16:19:16 -05:00
|
|
|
pos.z = 400;
|
2021-02-24 16:54:45 -05:00
|
|
|
else
|
|
|
|
pos.z -= 5;
|
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (CModelInfo::IsTrainModel(imodel))
|
|
|
|
{
|
|
|
|
int train_id = GetRandomTrainIdForModel(imodel);
|
|
|
|
|
|
|
|
if (train_id == -1) // Unknown train id
|
|
|
|
return;
|
|
|
|
|
|
|
|
int hveh = 0;
|
|
|
|
|
|
|
|
// Loading all train related models
|
|
|
|
CStreaming::RequestModel(590, PRIORITY_REQUEST);
|
|
|
|
CStreaming::RequestModel(538, PRIORITY_REQUEST);
|
|
|
|
CStreaming::RequestModel(570, PRIORITY_REQUEST);
|
|
|
|
CStreaming::RequestModel(569, PRIORITY_REQUEST);
|
|
|
|
CStreaming::RequestModel(537, PRIORITY_REQUEST);
|
|
|
|
CStreaming::RequestModel(449, PRIORITY_REQUEST);
|
|
|
|
|
|
|
|
CStreaming::LoadAllRequestedModels(false);
|
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
CTrain* train = nullptr;
|
|
|
|
CTrain* carraige = nullptr;
|
|
|
|
int track = Random(0, 1);
|
|
|
|
int node = CTrain::FindClosestTrackNode(pos, &track);
|
2021-06-18 12:49:11 -04:00
|
|
|
CTrain::CreateMissionTrain(pos, (Random(0, 1)) == 1 ? true : false, train_id, &train, &carraige, node,
|
|
|
|
track, false);
|
2020-12-24 14:31:26 -05:00
|
|
|
|
|
|
|
veh = (CVehicle*)train;
|
|
|
|
hveh = CPools::GetVehicleRef(veh);
|
2020-12-02 16:19:16 -05:00
|
|
|
if (veh->m_pDriver)
|
|
|
|
Command<Commands::DELETE_CHAR>(CPools::GetPedRef(veh->m_pDriver));
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Spawner.m_bSpawnInside)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
Command<Commands::WARP_CHAR_INTO_CAR>(hplayer, hveh);
|
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hveh, speed);
|
|
|
|
}
|
|
|
|
Command<Commands::MARK_MISSION_TRAIN_AS_NO_LONGER_NEEDED>(hveh);
|
2020-12-24 14:31:26 -05:00
|
|
|
Command<Commands::MARK_CAR_AS_NO_LONGER_NEEDED>(hveh);
|
2020-12-02 16:19:16 -05:00
|
|
|
CStreaming::SetModelIsDeletable(590);
|
|
|
|
CStreaming::SetModelIsDeletable(538);
|
|
|
|
CStreaming::SetModelIsDeletable(570);
|
|
|
|
CStreaming::SetModelIsDeletable(569);
|
|
|
|
CStreaming::SetModelIsDeletable(537);
|
|
|
|
CStreaming::SetModelIsDeletable(449);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CStreaming::RequestModel(imodel, PRIORITY_REQUEST);
|
|
|
|
CStreaming::LoadAllRequestedModels(false);
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Spawner.m_nLicenseText[0] != '\0')
|
|
|
|
Command<Commands::CUSTOM_PLATE_FOR_NEXT_CAR>(imodel, m_Spawner.m_nLicenseText);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2020-12-24 14:31:26 -05:00
|
|
|
int hveh = 0;
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Spawner.m_bSpawnInside)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-02-19 12:23:08 -05:00
|
|
|
Command<Commands::CREATE_CAR>(imodel, pos.x, pos.y, pos.z + 4.0f, &hveh);
|
2020-12-02 16:19:16 -05:00
|
|
|
veh = CPools::GetVehicle(hveh);
|
|
|
|
veh->SetHeading(player->GetHeading());
|
|
|
|
Command<Commands::WARP_CHAR_INTO_CAR>(hplayer, hveh);
|
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hveh, speed);
|
|
|
|
}
|
2020-12-10 14:36:18 -05:00
|
|
|
else
|
2021-02-24 16:54:45 -05:00
|
|
|
{
|
2020-12-10 14:36:18 -05:00
|
|
|
player->TransformFromObjectSpace(pos, CVector(0, 10, 0));
|
|
|
|
|
2020-12-28 15:12:40 -05:00
|
|
|
Command<Commands::CREATE_CAR>(imodel, pos.x, pos.y, pos.z + 3.0f, &hveh);
|
2020-12-10 14:36:18 -05:00
|
|
|
veh = CPools::GetVehicle(hveh);
|
2021-02-24 16:54:45 -05:00
|
|
|
veh->SetHeading(player->GetHeading() + 55.0f);
|
2020-12-10 14:36:18 -05:00
|
|
|
}
|
2020-12-26 14:40:02 -05:00
|
|
|
veh->m_nDoorLock = CARLOCK_UNLOCKED;
|
2020-12-24 14:31:26 -05:00
|
|
|
veh->m_nAreaCode = interior;
|
|
|
|
Command<Commands::MARK_CAR_AS_NO_LONGER_NEEDED>(CPools::GetVehicleRef(veh));
|
2020-12-02 16:19:16 -05:00
|
|
|
CStreaming::SetModelIsDeletable(imodel);
|
|
|
|
}
|
2020-12-24 14:31:26 -05:00
|
|
|
veh->m_nVehicleFlags.bHasBeenOwnedByPlayer = true;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Vehicle::GetNameFromModel(int model)
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CBaseModelInfo* info = CModelInfo::GetModelInfo(model);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
return (const char*)info + 0x32;
|
|
|
|
}
|
|
|
|
|
2021-01-03 06:48:07 -05:00
|
|
|
int Vehicle::GetModelFromName(const char* name)
|
|
|
|
{
|
|
|
|
int model = 0;
|
2021-02-24 16:54:45 -05:00
|
|
|
CBaseModelInfo* model_info = CModelInfo::GetModelInfo((char*)name, &model);
|
2021-01-03 06:48:07 -05:00
|
|
|
|
|
|
|
if (model > 0 && model < 1000000 && GetNameFromModel(model) != "")
|
|
|
|
return model;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
void Vehicle::GenerateHandlingDataFile(int phandling)
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
FILE* fp = fopen("handling.txt", "w");
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
std::string handlingId = m_VehicleIDE[FindPlayerPed()->m_pVehicle->m_nModelIndex];
|
2020-12-02 16:19:16 -05:00
|
|
|
float fMass = patch::Get<float>(phandling + 0x4);
|
|
|
|
float fTurnMass = patch::Get<float>(phandling + 0xC);
|
|
|
|
float fDragMult = patch::Get<float>(phandling + 0x10);
|
|
|
|
float CentreOfMassX = patch::Get<float>(phandling + 0x14);
|
|
|
|
float CentreOfMassY = patch::Get<float>(phandling + 0x18);
|
|
|
|
float CentreOfMassZ = patch::Get<float>(phandling + 0x1C);
|
|
|
|
int nPercentSubmerged = patch::Get<int>(phandling + 0x20);
|
|
|
|
float fTractionMultiplier = patch::Get<float>(phandling + 0x28);
|
|
|
|
float fTractionLoss = patch::Get<float>(phandling + 0xA4);
|
|
|
|
float TractionBias = patch::Get<float>(phandling + 0xA8);
|
|
|
|
float fEngineAcceleration = patch::Get<float>(phandling + 0x7C) * 12500;
|
|
|
|
float fEngineInertia = patch::Get<float>(phandling + 0x80);
|
|
|
|
int nDriveType = patch::Get<BYTE>(phandling + 0x74);
|
|
|
|
int nEngineType = patch::Get<BYTE>(phandling + 0x75);
|
|
|
|
float BrakeDeceleration = patch::Get<float>(phandling + 0x94) * 2500;
|
|
|
|
float BrakeBias = patch::Get<float>(phandling + 0x98);
|
|
|
|
int ABS = patch::Get<BYTE>(phandling + 0x9C);
|
|
|
|
float SteeringLock = patch::Get<float>(phandling + 0xA0);
|
|
|
|
float SuspensionForceLevel = patch::Get<float>(phandling + 0xAC);
|
|
|
|
float SuspensionDampingLevel = patch::Get<float>(phandling + 0xB0);
|
|
|
|
float SuspensionHighSpdComDamp = patch::Get<float>(phandling + 0xB4);
|
|
|
|
float Suspension_upper_limit = patch::Get<float>(phandling + 0xB8);
|
|
|
|
float Suspension_lower_limit = patch::Get<float>(phandling + 0xBC);
|
|
|
|
float Suspension_bias = patch::Get<float>(phandling + 0xC0);
|
|
|
|
float Suspension_anti_dive_multiplier = patch::Get<float>(phandling + 0xC4);
|
|
|
|
float fCollisionDamageMultiplier = patch::Get<float>(phandling + 0xC8) * 0.338;
|
|
|
|
int nMonetaryValue = patch::Get<int>(phandling + 0xD8);
|
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
int MaxVelocity = patch::Get<float>(phandling + 0x84);
|
2020-12-02 16:19:16 -05:00
|
|
|
MaxVelocity = MaxVelocity * 206 + (MaxVelocity - 0.918668) * 1501;
|
|
|
|
|
|
|
|
int modelFlags = patch::Get<int>(phandling + 0xCC);
|
|
|
|
int handlingFlags = patch::Get<int>(phandling + 0xD0);
|
|
|
|
|
|
|
|
int front_lights = patch::Get<BYTE>(phandling + 0xDC);
|
|
|
|
int rear_lights = patch::Get<BYTE>(phandling + 0xDD);
|
|
|
|
int vehicle_anim_group = patch::Get<BYTE>(phandling + 0xDE);
|
|
|
|
int nNumberOfGears = patch::Get<BYTE>(phandling + 0x76);
|
|
|
|
float fSeatOffsetDistance = patch::Get<float>(phandling + 0xD4);
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
fprintf(
|
|
|
|
fp,
|
|
|
|
"\n%s\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%d\t%.5g\t%.5g\t%.5g\t%d\t%d\t%.5g\t%.5g\t%c\t%c\t%.5g\t%.5g\t%d\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%.5g\t%d\t%d\t%d\t%d\t%d\t%d",
|
|
|
|
handlingId.c_str(), fMass, fTurnMass, fDragMult, CentreOfMassX, CentreOfMassY, CentreOfMassZ, nPercentSubmerged,
|
|
|
|
fTractionMultiplier, fTractionLoss, TractionBias, nNumberOfGears,
|
|
|
|
MaxVelocity, fEngineAcceleration, fEngineInertia, nDriveType, nEngineType, BrakeDeceleration, BrakeBias, ABS,
|
|
|
|
SteeringLock, SuspensionForceLevel, SuspensionDampingLevel,
|
|
|
|
SuspensionHighSpdComDamp, Suspension_upper_limit, Suspension_lower_limit, Suspension_bias,
|
|
|
|
Suspension_anti_dive_multiplier, fSeatOffsetDistance,
|
|
|
|
fCollisionDamageMultiplier, nMonetaryValue, modelFlags, handlingFlags, front_lights, rear_lights,
|
|
|
|
vehicle_anim_group);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
void Vehicle::Draw()
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
2021-02-24 16:54:45 -05:00
|
|
|
static CPlayerPed* player = FindPlayerPed();
|
2020-12-02 16:19:16 -05:00
|
|
|
static int hplayer = CPools::GetPedRef(player);
|
|
|
|
|
|
|
|
if (ImGui::Button("Blow up cars", ImVec2(Ui::GetSize(3))))
|
|
|
|
((void(*)(void))0x439D80)();
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
if (ImGui::Button("Fix vehicle", ImVec2(Ui::GetSize(3))))
|
|
|
|
{
|
2020-12-21 15:24:07 -05:00
|
|
|
if (player && player->m_pVehicle)
|
|
|
|
{
|
2020-12-02 16:19:16 -05:00
|
|
|
player->m_pVehicle->Fix();
|
2020-12-21 15:24:07 -05:00
|
|
|
player->m_pVehicle->m_fHealth = 1000.0f;
|
|
|
|
}
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
if (ImGui::Button("Flip vehicle", ImVec2(Ui::GetSize(3))))
|
|
|
|
{
|
2021-02-15 18:58:02 -05:00
|
|
|
if (player->m_nPedFlags.bInVehicle)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
int hveh = CPools::GetVehicleRef(player->m_pVehicle);
|
|
|
|
float roll;
|
|
|
|
|
|
|
|
Command<Commands::GET_CAR_ROLL>(hveh, &roll);
|
|
|
|
roll += 180;
|
|
|
|
Command<Commands::SET_CAR_ROLL>(hveh, roll);
|
|
|
|
Command<Commands::SET_CAR_ROLL>(hveh, roll); // z rot fix
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
|
|
|
if (ImGui::BeginTabBar("Vehicle", ImGuiTabBarFlags_NoTooltip + ImGuiTabBarFlags_FittingPolicyScroll))
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CVehicle* pVeh = player->m_pVehicle;
|
2020-12-21 15:24:07 -05:00
|
|
|
bool is_driver = pVeh && player->m_pVehicle->IsDriver(player);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
|
|
|
|
|
|
|
if (ImGui::BeginTabItem("Checkboxes"))
|
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::BeginChild("CheckboxesChild");
|
|
|
|
ImGui::Columns(2, 0, false);
|
|
|
|
|
|
|
|
Ui::CheckboxAddress("Aggressive drivers", 0x96914F);
|
|
|
|
Ui::CheckboxAddress("Aim while driving", 0x969179);
|
|
|
|
Ui::CheckboxAddress("All cars have nitro", 0x969165);
|
|
|
|
Ui::CheckboxAddress("All taxis have nitro", 0x96918B);
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Bikes fly", &m_bBikeFly);
|
2020-12-02 16:19:16 -05:00
|
|
|
Ui::CheckboxAddress("Boats fly", 0x969153);
|
2020-12-05 16:34:27 -05:00
|
|
|
Ui::CheckboxAddress("Cars fly", 0x969160);
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Cars heavy", &m_bVehHeavy);
|
|
|
|
if (Ui::CheckboxWithHint("Damage proof", &m_bNoDamage,
|
|
|
|
"Every vehicle entered will be damage proof\nBullet, Collision, Explosion, Fire, Meele etc"))
|
2020-12-09 08:15:50 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (pVeh && !m_bNoDamage)
|
2020-12-21 15:24:07 -05:00
|
|
|
{
|
|
|
|
pVeh->m_nVehicleFlags.bCanBeDamaged = true;
|
|
|
|
pVeh->m_nPhysicalFlags.bBulletProof = false;
|
|
|
|
pVeh->m_nPhysicalFlags.bExplosionProof = false;
|
|
|
|
pVeh->m_nPhysicalFlags.bFireProof = false;
|
|
|
|
pVeh->m_nPhysicalFlags.bCollisionProof = false;
|
|
|
|
pVeh->m_nPhysicalFlags.bMeeleProof = false;
|
|
|
|
}
|
2020-12-09 08:15:50 -05:00
|
|
|
}
|
2020-12-21 15:24:07 -05:00
|
|
|
Ui::CheckboxAddress("Decreased traffic", 0x96917A);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::NextColumn();
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Don't fall off bike", &m_bDontFallBike);
|
2020-12-21 15:24:07 -05:00
|
|
|
Ui::CheckboxAddress("Drive on water", 0x969152);
|
2020-12-05 16:34:27 -05:00
|
|
|
Ui::CheckboxAddressEx("Lock train camera", 0x52A52F, 171, 6);
|
2020-12-02 16:19:16 -05:00
|
|
|
Ui::CheckboxAddress("Float away when hit", 0x969166);
|
|
|
|
Ui::CheckboxAddress("Green traffic lights", 0x96914E);
|
|
|
|
Ui::CheckboxAddress("Perfect handling", 0x96914C);
|
|
|
|
Ui::CheckboxAddress("Tank mode", 0x969164);
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Unlimited nitro", &m_UnlimitedNitro.m_bEnabled, "Nitro will activate when left clicked\n\
|
2020-12-02 16:19:16 -05:00
|
|
|
\nEnabling this would disable\nAll cars have nitro\nAll taxis have nitro");
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Watertight car", &m_bVehWatertight);
|
2020-12-02 16:19:16 -05:00
|
|
|
Ui::CheckboxAddress("Wheels only", 0x96914B);
|
|
|
|
ImGui::Columns(1);
|
|
|
|
|
2020-12-21 15:24:07 -05:00
|
|
|
if (is_driver)
|
|
|
|
{
|
|
|
|
ImGui::NewLine();
|
|
|
|
ImGui::TextWrapped("For current vehicle,");
|
|
|
|
|
|
|
|
ImGui::Columns(2, 0, false);
|
|
|
|
|
2020-12-24 14:31:26 -05:00
|
|
|
bool state = pVeh->m_nVehicleFlags.bAlwaysSkidMarks;
|
|
|
|
if (Ui::CheckboxWithHint("Always skid marks", &state, nullptr))
|
|
|
|
pVeh->m_nVehicleFlags.bAlwaysSkidMarks = state;
|
|
|
|
|
|
|
|
state = pVeh->m_nPhysicalFlags.bBulletProof;
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::CheckboxWithHint("Bullet proof", &state, nullptr, m_bNoDamage))
|
2020-12-21 15:24:07 -05:00
|
|
|
pVeh->m_nPhysicalFlags.bBulletProof = state;
|
|
|
|
|
|
|
|
state = pVeh->m_nPhysicalFlags.bCollisionProof;
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::CheckboxWithHint("Collision proof", &state, nullptr, m_bNoDamage))
|
2020-12-21 15:24:07 -05:00
|
|
|
pVeh->m_nPhysicalFlags.bCollisionProof = state;
|
|
|
|
|
2020-12-24 14:31:26 -05:00
|
|
|
state = pVeh->m_nVehicleFlags.bDisableParticles;
|
|
|
|
if (Ui::CheckboxWithHint("Disable particles", &state, nullptr))
|
|
|
|
pVeh->m_nVehicleFlags.bDisableParticles = state;
|
|
|
|
|
|
|
|
state = pVeh->m_nVehicleFlags.bVehicleCanBeTargetted;
|
|
|
|
if (Ui::CheckboxWithHint("Driver targetable", &state, "Driver can be targeted"))
|
|
|
|
pVeh->m_nVehicleFlags.bVehicleCanBeTargetted = state;
|
|
|
|
|
2020-12-21 15:24:07 -05:00
|
|
|
state = !pVeh->m_nVehicleFlags.bEngineBroken || pVeh->m_nVehicleFlags.bEngineOn;
|
|
|
|
if (Ui::CheckboxWithHint("Engine on", &state, nullptr, !is_driver))
|
|
|
|
{
|
|
|
|
pVeh->m_nVehicleFlags.bEngineBroken = !state;
|
|
|
|
pVeh->m_nVehicleFlags.bEngineOn = state;
|
2021-02-24 16:54:45 -05:00
|
|
|
}
|
2020-12-21 15:24:07 -05:00
|
|
|
state = pVeh->m_nPhysicalFlags.bExplosionProof;
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::CheckboxWithHint("Explosion proof", &state, nullptr, m_bNoDamage))
|
2020-12-21 15:24:07 -05:00
|
|
|
pVeh->m_nPhysicalFlags.bExplosionProof = state;
|
|
|
|
|
|
|
|
state = pVeh->m_nPhysicalFlags.bFireProof;
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::CheckboxWithHint("Fire proof", &state, nullptr, m_bNoDamage))
|
2020-12-21 15:24:07 -05:00
|
|
|
pVeh->m_nPhysicalFlags.bFireProof = state;
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2021-01-18 04:53:24 -05:00
|
|
|
ImGui::NextColumn();
|
2020-12-21 15:24:07 -05:00
|
|
|
|
2020-12-24 14:31:26 -05:00
|
|
|
state = pVeh->m_nVehicleFlags.bVehicleCanBeTargettedByHS;
|
|
|
|
if (Ui::CheckboxWithHint("HS targetable", &state, "Heat Seaker missile can target this"))
|
|
|
|
pVeh->m_nVehicleFlags.bVehicleCanBeTargettedByHS = state;
|
2020-12-21 15:24:07 -05:00
|
|
|
|
|
|
|
state = !pVeh->m_bIsVisible;
|
|
|
|
if (Ui::CheckboxWithHint("Invisible car", &state, nullptr, !is_driver))
|
|
|
|
pVeh->m_bIsVisible = !state;
|
|
|
|
|
|
|
|
state = !pVeh->ms_forceVehicleLightsOff;
|
|
|
|
if (Ui::CheckboxWithHint("Lights on", &state, nullptr, !is_driver))
|
|
|
|
pVeh->ms_forceVehicleLightsOff = !state;
|
|
|
|
|
|
|
|
state = pVeh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE;
|
|
|
|
if (Ui::CheckboxWithHint("Lock doors", &state, nullptr, !is_driver))
|
|
|
|
{
|
|
|
|
if (state)
|
|
|
|
pVeh->m_nDoorLock = CARLOCK_LOCKED_PLAYER_INSIDE;
|
|
|
|
else
|
|
|
|
pVeh->m_nDoorLock = CARLOCK_UNLOCKED;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = pVeh->m_nPhysicalFlags.bMeeleProof;
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::CheckboxWithHint("Melee proof", &state, nullptr, m_bNoDamage))
|
2020-12-21 15:24:07 -05:00
|
|
|
pVeh->m_nPhysicalFlags.bMeeleProof = state;
|
2020-12-24 14:31:26 -05:00
|
|
|
|
2021-01-18 04:53:24 -05:00
|
|
|
state = pVeh->m_nVehicleFlags.bPetrolTankIsWeakPoint;
|
|
|
|
if (Ui::CheckboxWithHint("Petrol tank blow", &state, "Vehicle will blow up if petrol tank is shot"))
|
|
|
|
pVeh->m_nVehicleFlags.bPetrolTankIsWeakPoint = state;
|
|
|
|
|
2021-02-24 16:54:45 -05:00
|
|
|
state = pVeh->m_nVehicleFlags.bSirenOrAlarm;
|
2021-01-18 04:53:24 -05:00
|
|
|
if (Ui::CheckboxWithHint("Siren", &state))
|
|
|
|
pVeh->m_nVehicleFlags.bSirenOrAlarm = state;
|
|
|
|
|
2020-12-24 14:31:26 -05:00
|
|
|
state = pVeh->m_nVehicleFlags.bTakeLessDamage;
|
|
|
|
if (Ui::CheckboxWithHint("Take less dmg", &state, nullptr))
|
|
|
|
pVeh->m_nVehicleFlags.bTakeLessDamage = state;
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-21 15:24:07 -05:00
|
|
|
ImGui::Columns(1);
|
|
|
|
}
|
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginTabItem("Menus"))
|
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::BeginChild("MenusChild");
|
2020-12-21 15:24:07 -05:00
|
|
|
Ui::EditFloat("Density multiplier", 0x8A5B20, 0, 1, 10);
|
2020-12-02 16:19:16 -05:00
|
|
|
if (ImGui::CollapsingHeader("Enter nearest vehicle as"))
|
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CPlayerPed* player = FindPlayerPed();
|
2020-12-02 16:19:16 -05:00
|
|
|
int hplayer = CPools::GetPedRef(player);
|
2021-02-24 16:54:45 -05:00
|
|
|
CVehicle* veh = Util::GetClosestVehicle();
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (veh)
|
|
|
|
{
|
|
|
|
int seats = veh->m_nMaxPassengers;
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Columns(2, 0, false);
|
|
|
|
|
|
|
|
ImGui::Text(GetNameFromModel(veh->m_nModelIndex).c_str());
|
|
|
|
ImGui::NextColumn();
|
2021-06-15 13:11:11 -04:00
|
|
|
ImGui::Text("Total seats: %d", (seats + 1));
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Columns(1);
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (ImGui::Button("Driver", ImVec2(Ui::GetSize(2))))
|
|
|
|
Command<Commands::WARP_CHAR_INTO_CAR>(hplayer, veh);
|
|
|
|
|
|
|
|
for (int i = 0; i < seats; ++i)
|
|
|
|
{
|
|
|
|
if (i % 2 != 1)
|
|
|
|
ImGui::SameLine();
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (ImGui::Button((std::string("Passenger ") + std::to_string(i + 1)).c_str(),
|
|
|
|
ImVec2(Ui::GetSize(2))))
|
2020-12-02 16:19:16 -05:00
|
|
|
Command<Commands::WARP_CHAR_INTO_CAR_AS_PASSENGER>(hplayer, veh, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ImGui::Text("No nearby vehicles");
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Separator();
|
|
|
|
}
|
2021-01-03 06:48:07 -05:00
|
|
|
if (ImGui::CollapsingHeader("Remove vehicles in radius"))
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::InputInt("Radius", &m_nVehRemoveRadius);
|
2021-01-03 06:48:07 -05:00
|
|
|
ImGui::Spacing();
|
2021-02-24 16:54:45 -05:00
|
|
|
if (ImGui::Button("Remove vehicles", Ui::GetSize(1)))
|
2021-01-03 06:48:07 -05:00
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CPlayerPed* player = FindPlayerPed();
|
|
|
|
for (CVehicle* veh : CPools::ms_pVehiclePool)
|
2021-01-03 06:48:07 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (DistanceBetweenPoints(veh->GetPosition(), player->GetPosition()) < m_nVehRemoveRadius
|
|
|
|
&& player->m_pVehicle != veh)
|
2021-01-03 06:48:07 -05:00
|
|
|
Command<Commands::DELETE_CAR>(CPools::GetVehicleRef(veh));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Separator();
|
|
|
|
}
|
2020-12-02 16:19:16 -05:00
|
|
|
if (ImGui::CollapsingHeader("Traffic options"))
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
static std::vector<Ui::NamedMemory> color{{"Black", 0x969151}, {"Pink", 0x969150}};
|
|
|
|
static std::vector<Ui::NamedMemory> type{
|
|
|
|
{"Cheap", 0x96915E}, {"Country", 0x96917B}, {"Fast", 0x96915F}
|
|
|
|
};
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
Ui::RadioButtonAddress("Color", color);
|
|
|
|
ImGui::Spacing();
|
|
|
|
Ui::RadioButtonAddress("Type", type);
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Separator();
|
|
|
|
}
|
2020-12-21 15:24:07 -05:00
|
|
|
|
2020-12-20 14:23:32 -05:00
|
|
|
if (player && player->m_pVehicle)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
CVehicle* pVeh = player->m_pVehicle;
|
|
|
|
int hVeh = CPools::GetVehicleRef(pVeh);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditFloat("Dirt level", (int)pVeh + 0x4B0, 0, 7.5, 15);
|
|
|
|
if (pVeh->m_nVehicleClass == VEHICLE_AUTOMOBILE && ImGui::CollapsingHeader("Doors"))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
ImGui::Columns(2, 0, false);
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::RadioButton("Damage", &m_nDoorMenuButton, 0);
|
|
|
|
ImGui::RadioButton("Fix", &m_nDoorMenuButton, 1);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::NextColumn();
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::RadioButton("Open", &m_nDoorMenuButton, 2);
|
|
|
|
ImGui::RadioButton("Pop", &m_nDoorMenuButton, 3);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Columns(1);
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
int seats = pVeh->m_nMaxPassengers + 1; // passenger + driver
|
2020-12-25 12:44:41 -05:00
|
|
|
int doors = seats == 4 ? 6 : 4;
|
2021-06-18 12:49:11 -04:00
|
|
|
int hveh = CPools::GetVehicleRef(pVeh);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (ImGui::Button("All", ImVec2(Ui::GetSize())))
|
|
|
|
{
|
|
|
|
for (int i = 0; i < doors; ++i)
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
switch (m_nDoorMenuButton)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
case 0:
|
|
|
|
Command<Commands::DAMAGE_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
Command<Commands::FIX_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Command<Commands::OPEN_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Command<Commands::POP_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-25 12:44:41 -05:00
|
|
|
for (int i = 0; i != doors; ++i)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (ImGui::Button(m_DoorNames[i].c_str(), ImVec2(Ui::GetSize(2))))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
switch (m_nDoorMenuButton)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
case 0:
|
|
|
|
Command<Commands::DAMAGE_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
Command<Commands::FIX_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Command<Commands::OPEN_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Command<Commands::POP_CAR_DOOR>(hveh, i);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i % 2 != 1)
|
|
|
|
ImGui::SameLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Separator();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::CollapsingHeader("Set speed"))
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Lock speed", &m_bLockSpeed);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::InputFloat("Set", &m_fLockSpeed);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
m_fLockSpeed = m_fLockSpeed > 100 ? 100 : m_fLockSpeed;
|
|
|
|
m_fLockSpeed = m_fLockSpeed < 0 ? 0 : m_fLockSpeed;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (ImGui::Button("Set speed##brn", ImVec2(Ui::GetSize(2))))
|
2021-06-18 12:49:11 -04:00
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hVeh, m_fLockSpeed);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
if (ImGui::Button("Instant stop##brn", ImVec2(Ui::GetSize(2))))
|
2021-06-18 12:49:11 -04:00
|
|
|
Command<Commands::SET_CAR_FORWARD_SPEED>(hVeh, 0);
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginTabItem("Spawn"))
|
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Columns(2, 0, false);
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Spawn inside", &m_Spawner.m_bSpawnInside, "Spawn inside vehicle as driver");
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::NextColumn();
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Spawn aircraft in air", &m_Spawner.m_bSpawnInAir);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Columns(1);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowContentRegionWidth() - 2.5);
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::InputTextWithHint("##LicenseText", "License plate text", m_Spawner.m_nLicenseText, 9);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::DrawImages(m_Spawner.m_VehData.m_ImagesList, ImVec2(100, 75), m_Spawner.m_VehData.m_Categories,
|
|
|
|
m_Spawner.m_VehData.m_Selected, m_Spawner.m_VehData.m_Filter, SpawnVehicle, nullptr,
|
|
|
|
[](std::string str)
|
|
|
|
{
|
|
|
|
return GetNameFromModel(std::stoi(str));
|
|
|
|
});
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
2021-02-19 02:41:50 -05:00
|
|
|
if (player->m_pVehicle && player->m_nPedFlags.bInVehicle)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-02-24 16:54:45 -05:00
|
|
|
CVehicle* veh = FindPlayerPed()->m_pVehicle;
|
2020-12-02 16:19:16 -05:00
|
|
|
int hveh = CPools::GetVehicleRef(veh);
|
|
|
|
if (ImGui::BeginTabItem("Color"))
|
|
|
|
{
|
|
|
|
Paint::UpdateNodeListRecursive(veh);
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (ImGui::Button("Reset color", ImVec2(Ui::GetSize())))
|
|
|
|
{
|
|
|
|
Paint::ResetNodeColor(veh, Paint::veh_nodes::selected);
|
|
|
|
CHud::SetHelpMessage("Color reset", false, false, false);
|
|
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
|
|
|
Ui::ListBoxStr("Component", Paint::veh_nodes::names_vec, Paint::veh_nodes::selected);
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (ImGui::ColorEdit3("Color picker", m_Color.m_fColorPicker))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
uchar r = m_Color.m_fColorPicker[0] * 255;
|
|
|
|
uchar g = m_Color.m_fColorPicker[1] * 255;
|
|
|
|
uchar b = m_Color.m_fColorPicker[2] * 255;
|
|
|
|
Paint::SetNodeColor(veh, Paint::veh_nodes::selected, {r, g, b, 255}, m_Color.m_bMatFilter);
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Columns(2, NULL, false);
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::Checkbox("Material filter", &m_Color.m_bMatFilter);
|
|
|
|
ImGui::RadioButton("Primary", &m_Color.m_nRadioButton, 1);
|
|
|
|
ImGui::RadioButton("Secondary", &m_Color.m_nRadioButton, 2);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::NextColumn();
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::Checkbox("Show all", &m_Color.bShowAll);
|
|
|
|
ImGui::RadioButton("Tertiary", &m_Color.m_nRadioButton, 3);
|
|
|
|
ImGui::RadioButton("Quaternary", &m_Color.m_nRadioButton, 4);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Columns(1);
|
|
|
|
ImGui::Text("Select color preset:");
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
int count = (int)m_CarcolsColorData.size();
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImVec2 size = Ui::GetSize();
|
2021-06-18 12:49:11 -04:00
|
|
|
int btnsInRow = ImGui::GetWindowContentRegionWidth() / (size.y * 2);
|
|
|
|
int btnSize = (ImGui::GetWindowContentRegionWidth() - int(ImGuiStyleVar_ItemSpacing) * (btnsInRow -
|
|
|
|
0.6 * btnsInRow)) / btnsInRow;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::BeginChild("Colorss");
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (m_Color.bShowAll)
|
|
|
|
for (int colorId = 0; colorId < count; ++colorId)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::ColorButton(colorId, m_CarcolsColorData[colorId], ImVec2(btnSize, btnSize)))
|
|
|
|
*(uint8_replacement*)(int(veh) + 0x433 + m_Color.m_nRadioButton) = colorId;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if ((colorId + 1) % btnsInRow != 0)
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::SameLine(0.0, 4.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::string vehName = GetNameFromModel(player->m_pVehicle->m_nModelIndex);
|
|
|
|
for (auto entry : m_CarcolsCarData)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (entry.first == vehName)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
|
|
|
int count = 1;
|
2021-06-18 12:49:11 -04:00
|
|
|
for (int colorId : entry.second)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::ColorButton(colorId, m_CarcolsColorData[colorId],
|
|
|
|
ImVec2(btnSize, btnSize)))
|
|
|
|
*(uint8_replacement*)(int(veh) + 0x433 + m_Color.m_nRadioButton) = colorId;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (count % btnsInRow != 0)
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::SameLine(0.0, 4.0);
|
|
|
|
++count;
|
|
|
|
}
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginTabItem("Neons"))
|
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (ImGui::Button("Remove neon", ImVec2(Ui::GetSize())))
|
|
|
|
{
|
2021-01-18 04:53:24 -05:00
|
|
|
RemoveNeon(veh);
|
2020-12-02 16:19:16 -05:00
|
|
|
CHud::SetHelpMessage("Neon removed", false, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Columns(2, NULL, false);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2021-01-18 04:53:24 -05:00
|
|
|
bool pulsing = IsPulsingEnabled(veh);
|
2021-01-07 16:07:45 -05:00
|
|
|
if (Ui::CheckboxWithHint("Pulsing neons", &pulsing))
|
2021-02-24 16:54:45 -05:00
|
|
|
SetPulsing(veh, pulsing);
|
2021-01-07 16:07:45 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Rainbow neons", &m_Neon.m_bRainbowEffect, "Rainbow effect to neon lights");
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::NextColumn();
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::CheckboxWithHint("Traffic neons", &m_Neon.m_bApplyOnTraffic, "Adds neon lights to traffic vehicles.\n\
|
2020-12-02 16:19:16 -05:00
|
|
|
Only some vehicles will have them.");
|
|
|
|
ImGui::Columns(1);
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if (ImGui::ColorEdit3("Color picker", m_Neon.m_fColorPicker))
|
|
|
|
InstallNeon(veh, m_Neon.m_fColorPicker[0] * 255, m_Neon.m_fColorPicker[1] * 255,
|
|
|
|
m_Neon.m_fColorPicker[2] * 255);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("Select neon preset:");
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
int count = (int)m_CarcolsColorData.size();
|
2020-12-02 16:19:16 -05:00
|
|
|
ImVec2 size = Ui::GetSize();
|
2021-06-18 12:49:11 -04:00
|
|
|
int btnsInRow = ImGui::GetWindowContentRegionWidth() / (size.y * 2);
|
|
|
|
int btnSize = (ImGui::GetWindowContentRegionWidth() - int(ImGuiStyleVar_ItemSpacing) * (btnsInRow -
|
|
|
|
0.6 * btnsInRow)) / btnsInRow;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::BeginChild("Neonss");
|
|
|
|
|
|
|
|
for (int color_id = 0; color_id < count; ++color_id)
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
if (Ui::ColorButton(color_id, m_CarcolsColorData[color_id], ImVec2(btnSize, btnSize)))
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
std::vector<float>& color = m_CarcolsColorData[color_id];
|
2021-02-24 16:54:45 -05:00
|
|
|
InstallNeon(veh, color[0] * 255, color[1] * 255, color[2] * 255);
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
if ((color_id + 1) % btnsInRow != 0)
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::SameLine(0.0, 4.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginTabItem("Textures"))
|
|
|
|
{
|
|
|
|
Paint::UpdateNodeListRecursive(veh);
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (ImGui::Button("Reset texture", ImVec2(Ui::GetSize())))
|
|
|
|
{
|
|
|
|
Paint::ResetNodeTexture(veh, Paint::veh_nodes::selected);
|
|
|
|
CHud::SetHelpMessage("Texture reset", false, false, false);
|
|
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
|
|
|
Ui::ListBoxStr("Component", Paint::veh_nodes::names_vec, Paint::veh_nodes::selected);
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
|
|
|
int maxpjob, curpjob;
|
|
|
|
Command<Commands::GET_NUM_AVAILABLE_PAINTJOBS>(hveh, &maxpjob);
|
|
|
|
|
|
|
|
if (maxpjob > 0)
|
|
|
|
{
|
|
|
|
Command<Commands::GET_CURRENT_VEHICLE_PAINTJOB>(hveh, &curpjob);
|
|
|
|
|
|
|
|
if (ImGui::InputInt("Paintjob", &curpjob))
|
|
|
|
{
|
|
|
|
if (curpjob > maxpjob)
|
|
|
|
curpjob = -1;
|
|
|
|
if (curpjob < -1)
|
2021-02-24 16:54:45 -05:00
|
|
|
curpjob = maxpjob - 1;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
Command<Commands::GIVE_VEHICLE_PAINTJOB>(hveh, curpjob);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
}
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::SameLine();
|
2021-06-18 12:49:11 -04:00
|
|
|
ImGui::Checkbox("Material filter", &m_Color.m_bMatFilter);
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::Spacing();
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::DrawImages(m_TextureData.m_ImagesList, ImVec2(100, 80), m_TextureData.m_Categories, m_TextureData.m_Selected,
|
|
|
|
m_TextureData.m_Filter,
|
|
|
|
[](std::string& str)
|
|
|
|
{
|
|
|
|
Paint::SetNodeTexture(FindPlayerPed()->m_pVehicle, Paint::veh_nodes::selected, str,
|
|
|
|
m_Color.m_bMatFilter);
|
|
|
|
},
|
|
|
|
nullptr,
|
|
|
|
[](std::string& str)
|
|
|
|
{
|
|
|
|
return str;
|
|
|
|
});
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginTabItem("Tune"))
|
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::DrawImages(m_TuneData.m_ImagesList, ImVec2(100, 80), m_TuneData.m_Categories, m_TuneData.m_Selected,
|
|
|
|
m_TuneData.m_Filter,
|
|
|
|
[](std::string& str) { AddComponent(str); },
|
|
|
|
[](std::string& str) { RemoveComponent(str); },
|
|
|
|
[](std::string& str) { return str; },
|
|
|
|
[](std::string& str)
|
|
|
|
{
|
|
|
|
return ((bool(*)(int, CVehicle*))0x49B010)(std::stoi(str), player->m_pVehicle);
|
|
|
|
}
|
2020-12-02 16:19:16 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginTabItem("Handling"))
|
|
|
|
{
|
|
|
|
ImGui::Spacing();
|
2021-02-24 16:54:45 -05:00
|
|
|
|
|
|
|
CBaseModelInfo* info = CModelInfo::GetModelInfo(player->m_pVehicle->m_nModelIndex);
|
2021-06-18 12:49:11 -04:00
|
|
|
int pHandling = patch::Get<WORD>((int)info + 0x4A, false);
|
|
|
|
pHandling *= 0xE0;
|
|
|
|
pHandling += 0xC2B9DC;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
if (ImGui::Button("Reset handling", ImVec2(Ui::GetSize(3))))
|
|
|
|
{
|
|
|
|
gHandlingDataMgr.LoadHandlingData();
|
|
|
|
CHud::SetHelpMessage("Handling reset", false, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
if (ImGui::Button("Save to file", ImVec2(Ui::GetSize(3))))
|
|
|
|
{
|
2021-06-18 12:49:11 -04:00
|
|
|
GenerateHandlingDataFile(pHandling);
|
2020-12-02 16:19:16 -05:00
|
|
|
CHud::SetHelpMessage("Handling saved", false, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
if (ImGui::Button("Read more", ImVec2(Ui::GetSize(3))))
|
2021-06-18 12:49:11 -04:00
|
|
|
ShellExecute(NULL, "open", "https://projectcerbera.com/gta/sa/tutorials/handling", NULL, NULL,
|
|
|
|
SW_SHOWNORMAL);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::Spacing();
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::BeginChild("HandlingChild");
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
static std::vector<Ui::NamedValue> abs{{"On", 1}, {"Off", 0}};
|
|
|
|
Ui::EditRadioButtonAddressEx("Abs", pHandling + 0x9C, abs);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditFloat("Anti dive multiplier", pHandling + 0xC4, 0.0f, 0.0f, 1.0f);
|
|
|
|
Ui::EditFloat("Brake bias", pHandling + 0x98, 0.0f, 0.0f, 1.0f);
|
|
|
|
Ui::EditFloat("Brake deceleration", pHandling + 0x94, 0.0f, 0.0f, 20.0f, 2500.0f);
|
|
|
|
Ui::EditFloat("Centre of mass X", pHandling + 0x14, -10.0f, -10.0f, 10.0f);
|
|
|
|
Ui::EditFloat("Centre of mass Y", pHandling + 0x18, -10.0f, -10.0f, 10.0f);
|
|
|
|
Ui::EditFloat("Centre of mass Z", pHandling + 0x1C, -10.0f, -10.0f, 10.0f);
|
|
|
|
Ui::EditFloat("Collision damage multiplier", pHandling + 0xC8, 0.0f, 0.0f, 1.0f, 0.3381f);
|
|
|
|
Ui::EditFloat("Damping level", pHandling + 0xB0, -10.0f, -10.0f, 10.0f); // test later
|
|
|
|
Ui::EditFloat("Drag mult", pHandling + 0x10, 0.0f, 0.0f, 30.0f);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
static std::vector<Ui::NamedValue> drive_type{
|
|
|
|
{"Front wheel drive", 70}, {"Rear wheel drive", 82}, {"Four wheel drive", 52}
|
|
|
|
};
|
|
|
|
Ui::EditRadioButtonAddressEx("Drive type", pHandling + 0x74, drive_type);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditFloat("Engine acceleration", pHandling + 0x7C, 0.0f, 0.0f, 49.0f, 12500.0f);
|
|
|
|
Ui::EditFloat("Engine inertia", pHandling + 0x80, 0.0f, 0.0f, 400.0f);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
static std::vector<Ui::NamedValue> engine_type{{"Petrol", 80}, {"Diseal", 68}, {"Electric", 69}};
|
|
|
|
Ui::EditRadioButtonAddressEx("Engine type", pHandling + 0x75, engine_type);
|
2021-01-05 01:29:26 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
std::vector<Ui::NamedValue> front_lights{{"Long", 0}, {"Small", 1}, {"Big", 2}, {"Tall", 3}};
|
|
|
|
Ui::EditRadioButtonAddressEx("Front lights", pHandling + 0xDC, front_lights);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditFloat("Force level", pHandling + 0xAC, -10.0f, -10.0f, 10.0f); // test later
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditBits("Handling flags", pHandling + 0xD0, m_HandlingFlagNames);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditFloat("High speed damping", pHandling + 0xB4, -10.0f, -10.0f, 10.0f); // test later
|
|
|
|
Ui::EditFloat("Lower limit", pHandling + 0xBC, -10.0f, -10.0f, 10.0f); // test later
|
|
|
|
Ui::EditFloat("Mass", pHandling + 0x4, 1.0f, 1.0f, 50000.0f);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
///fcommon.UpdateAddress({ name = 'Max velocity',address = phandling + 0x84 ,size = 4,min = 0,max = 2,is_float = true,cvalue = 0.01 , save = false })
|
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditBits("Model flags", pHandling + 0xCC, m_ModelFlagNames);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditAddress<int>("Monetary value", pHandling + 0xD8, 1, 1, 100000);
|
|
|
|
Ui::EditAddress<BYTE>("Number of gears", pHandling + 0x76, 1, 1, 10);
|
|
|
|
Ui::EditAddress<BYTE>("Percent submerged", pHandling + 0x20, 10, 10, 120);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
static std::vector<Ui::NamedValue> rear_lights{{"Long", 0}, {"Small", 1}, {"Big", 2}, {"Tall", 3}};
|
|
|
|
Ui::EditRadioButtonAddressEx("Rear lights", pHandling + 0xDD, rear_lights);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-06-18 12:49:11 -04:00
|
|
|
Ui::EditFloat("Seat offset distance", pHandling + 0xD4, 0.0f, 0.0f, 1.0f);
|
|
|
|
Ui::EditFloat("Steering lock", pHandling + 0xA0, 10.0f, 10.0f, 50.0f);
|
|
|
|
Ui::EditFloat("Suspension bias", pHandling + 0xC0, 0.0f, 0.0f, 1.0f);
|
|
|
|
Ui::EditFloat("Traction bias", pHandling + 0xA8, 0.0f, 0.0f, 1.0f);
|
|
|
|
Ui::EditFloat("Traction loss", pHandling + 0xA4, 0.0f, 0.0f, 1.0f);
|
|
|
|
Ui::EditFloat("Traction multiplier", pHandling + 0x28, 0.5f, 0.5f, 2.0f);
|
|
|
|
Ui::EditFloat("Turn mass", pHandling + 0xC, 20.0f, 20.0f, 1000.0f); // test later
|
|
|
|
Ui::EditFloat("Upper limit", pHandling + 0xB8, -1.0f, -1.0f, 1.0f);
|
|
|
|
Ui::EditAddress<BYTE>("Vehicle anim group", pHandling + 0xDE, 0, 0, 20);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
|
|
|
ImGui::EndChild();
|
2021-02-24 16:54:45 -05:00
|
|
|
|
2020-12-02 16:19:16 -05:00
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::EndTabBar();
|
|
|
|
}
|
|
|
|
}
|