diff --git a/src/FileHandler.cpp b/src/FileHandler.cpp new file mode 100644 index 0000000..1b62961 --- /dev/null +++ b/src/FileHandler.cpp @@ -0,0 +1,225 @@ +#include "pch.h" +#include "FileHandler.h" +#include "Visual.h" + +// TODO: Clean up this mess, use structures instead? +void FileHandler::GenerateHandlingFile(int pHandling, std::map& storeMap) +{ + FILE* fp = fopen("handling.txt", "w"); + + std::string handlingId = storeMap[FindPlayerPed()->m_pVehicle->m_nModelIndex]; + float fMass = patch::Get(pHandling + 0x4); + float fTurnMass = patch::Get(pHandling + 0xC); + float fDragMult = patch::Get(pHandling + 0x10); + float CentreOfMassX = patch::Get(pHandling + 0x14); + float CentreOfMassY = patch::Get(pHandling + 0x18); + float CentreOfMassZ = patch::Get(pHandling + 0x1C); + int nPercentSubmerged = patch::Get(pHandling + 0x20); + float fTractionMultiplier = patch::Get(pHandling + 0x28); + float fTractionLoss = patch::Get(pHandling + 0xA4); + float TractionBias = patch::Get(pHandling + 0xA8); + float fEngineAcceleration = patch::Get(pHandling + 0x7C) * 12500; + float fEngineInertia = patch::Get(pHandling + 0x80); + int nDriveType = patch::Get(pHandling + 0x74); + int nEngineType = patch::Get(pHandling + 0x75); + float BrakeDeceleration = patch::Get(pHandling + 0x94) * 2500; + float BrakeBias = patch::Get(pHandling + 0x98); + int ABS = patch::Get(pHandling + 0x9C); + float SteeringLock = patch::Get(pHandling + 0xA0); + float SuspensionForceLevel = patch::Get(pHandling + 0xAC); + float SuspensionDampingLevel = patch::Get(pHandling + 0xB0); + float SuspensionHighSpdComDamp = patch::Get(pHandling + 0xB4); + float Suspension_upper_limit = patch::Get(pHandling + 0xB8); + float Suspension_lower_limit = patch::Get(pHandling + 0xBC); + float Suspension_bias = patch::Get(pHandling + 0xC0); + float Suspension_anti_dive_multiplier = patch::Get(pHandling + 0xC4); + float fCollisionDamageMultiplier = patch::Get(pHandling + 0xC8) * 0.338; + int nMonetaryValue = patch::Get(pHandling + 0xD8); + int MaxVelocity = patch::Get(pHandling + 0x84); + MaxVelocity = MaxVelocity * 206 + (MaxVelocity - 0.918668) * 1501; + int modelFlags = patch::Get(pHandling + 0xCC); + int handlingFlags = patch::Get(pHandling + 0xD0); + int front_lights = patch::Get(pHandling + 0xDC); + int rear_lights = patch::Get(pHandling + 0xDD); + int vehicle_anim_group = patch::Get(pHandling + 0xDE); + int nNumberOfGears = patch::Get(pHandling + 0x76); + float fSeatOffsetDistance = patch::Get(pHandling + 0xD4); + + // TODO: make this more readable + 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); + + fclose(fp); +} + +void FileHandler::FetchColorData(std::vector>& storeVec, + std::map>& storeMap) +{ + std::string m_FilePath = GAME_PATH((char*)"/data/carcols.dat"); + + if (std::filesystem::exists(m_FilePath)) + { + std::ifstream file(m_FilePath); + std::string line; + bool bIsCar = false; + bool bIsCol = false; + int nLineCount = 0; + + while (getline(file, line)) + { + // skip commented & emety lines + if (line[0] == '#' || line == "") + { + continue; + } + + // section blocks + if (line[0] == 'c' && line[1] == 'a' && line[2] == 'r') + { + bIsCar = true; + continue; + } + + if (line[0] == 'c' && line[1] == 'o' && line[2] == 'l') + { + bIsCol = true; + continue; + } + + if (line[0] == 'e' && line[1] == 'n' && line[2] == 'd') + { + bIsCar = false; + bIsCol = false; + continue; + } + + if (bIsCol) + { + try + { + std::string temp; + std::stringstream ss(line); + + // fix one instance where . is used instead of , + std::replace(temp.begin(), temp.end(), '.', ','); + + // Format: red, green, blue + int r,g,b; + getline(ss, temp, ','); + r = std::stoi(temp); + getline(ss, temp, ','); + g = std::stoi(temp); + getline(ss, temp, ','); + b = std::stoi(temp); + + storeVec.push_back({r / 255.0f, g / 255.0f, b / 255.0f}); + ++nLineCount; + } + catch (...) + { + flog << "Error parsing carcols.dat, " << line << std::endl; + } + } + + if (bIsCar) + { + std::string temp; + std::stringstream ss(line); + + // Format: modelname, colorindex1, colorindex2,... + getline(ss, temp, ','); + std::string name = temp; + while (getline(ss, temp, ',')) + { + try + { + std::for_each(name.begin(), name.end(), [](char& c) + { + c = ::toupper(c); + }); + + int val = std::stoi(temp); + if (!(std::find(storeMap[name].begin(), storeMap[name].end(), val) != + storeMap[name].end())) + { + storeMap[name].push_back(val); + } + } + catch (...) + { + flog << "Error parsing carcols.dat, " << line << std::endl; + } + } + } + } + + file.close(); + } + else + { + flog << "Carcols.dat not found"; + } +} + +void FileHandler::FetchHandlingID(std::map& storeMap) +{ + std::string m_FilePath = GAME_PATH((char*)"/data/vehicles.ide"); + + if (std::filesystem::exists(m_FilePath)) + { + std::ifstream file(m_FilePath); + std::string line; + + while (getline(file, line)) + { + /* + Format: model, modelname, txdname, type, handlingId, ... + Skip if first thing isn't model id + */ + if (line[0] <= '0' || line[0] >= '9') + { + continue; + } + + // running inside try block to handle user errors, mostly commas + try + { + std::string temp; + std::stringstream ss(line); + + // get model + getline(ss, temp, ','); + int model = std::stoi(temp); + + // get 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()); + + storeMap[model] = temp; + } + catch (...) + { + flog << "Error parsing vehicles.ide, " << line << std::endl; + } + } + + file.close(); + } + else + { + flog << "Vehicle.ide not found"; + } +} \ No newline at end of file diff --git a/src/FileHandler.h b/src/FileHandler.h new file mode 100644 index 0000000..51def1a --- /dev/null +++ b/src/FileHandler.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include + +class FileHandler +{ +public: + FileHandler() = delete; + FileHandler(FileHandler&) = delete; + + /* + Parses data/carcols.dat file and stores color data per vehicle + TODO: Implement something that also parses modloader data + */ + static void FetchColorData(std::vector>& storeVec, + std::map>& storeMap); + /* + Parses data/vehicles.ide file and stores handingId in a map + TODO: Implement something that also parses modloader data + */ + static void FetchHandlingID(std::map& storeMap); + static void GenerateHandlingFile(int pHandling, std::map& storeMap); +}; + diff --git a/src/Player.cpp b/src/Player.cpp index 6b0f5f5..3a8d3b9 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -249,27 +249,30 @@ void Player::ChangePlayerCloth(std::string& name) std::string model = temp.c_str(); getline(ss, temp, '$'); - std::string texture9 = temp.c_str(); + std::string texName = temp.c_str(); CPlayerPed* player = FindPlayerPed(); - if (texture9 == "cutoffchinosblue") + if (texName == "cutoffchinosblue") { player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-697413025, 744365350, body_part); } else { - if (texture9 == "sneakerbincblue") + if (texName == "sneakerbincblue") { player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-915574819, 2099005073, body_part); } else { - if (texture9 == "12myfac") + if (texName == "12myfac") + { player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-1750049245, 1393983095, body_part); + } else - player->m_pPlayerData->m_pPedClothesDesc-> - SetTextureAndModel(texture9.c_str(), model.c_str(), body_part); + { + player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(texName.c_str(), model.c_str(), body_part); + } } } CClothes::RebuildPlayer(player, false); diff --git a/src/ResourceStore.cpp b/src/ResourceStore.cpp index 55d1db5..2fea024 100644 --- a/src/ResourceStore.cpp +++ b/src/ResourceStore.cpp @@ -59,7 +59,7 @@ void ResourceStore::LoadTextureResource(std::string&& name) pEndDic = (RwTexDictionary*)pRLL->link.next; RwTexture *pTex = (RwTexture*)&pRLL[-1]; - m_ImagesList.push_back(std::make_unique()); + m_ImagesList.push_back(std::make_unique()); m_ImagesList.back().get()->m_pRwTexture = pTex; // Fetch IDirec9Texture9* from RwTexture* diff --git a/src/ResourceStore.h b/src/ResourceStore.h index 847f256..282f4c6 100644 --- a/src/ResourceStore.h +++ b/src/ResourceStore.h @@ -28,7 +28,7 @@ struct RwRasterEx : public RwRaster RwD3D9Raster *m_pRenderResource; }; -struct STextureResource +struct TextureResource { std::string m_FileName; std::string m_CategoryName; @@ -43,7 +43,7 @@ enum eResourceType TYPE_BOTH, }; -using TextureResourceList = std::vector>; +using TextureResourceList = std::vector>; class ResourceStore { private: diff --git a/src/Vehicle.cpp b/src/Vehicle.cpp index b8e9bfd..b885604 100644 --- a/src/Vehicle.cpp +++ b/src/Vehicle.cpp @@ -3,6 +3,7 @@ #include "Menu.h" #include "Ui.h" #include "Util.h" +#include "FileHandler.h" #include #include @@ -31,15 +32,15 @@ void Vehicle::FixVehicle(CVehicle *pVeh) Vehicle::Vehicle() { #ifdef GTASA - ParseVehiclesIDE(); + FileHandler::FetchHandlingID(m_VehicleIDE); #endif - ParseCarcolsDAT(); + FileHandler::FetchColorData(m_CarcolsColorData, m_CarcolsCarData); Events::processScriptsEvent += [this] { uint timer = CTimer::m_snTimeInMilliseconds; CPlayerPed* pPlayer = FindPlayerPed(); - CVehicle* pVeh = pPlayer->m_pVehicle; + CVehicle* pVeh = FindPlayerVehicle(-1, false); if (pPlayer && pVeh) { @@ -159,13 +160,19 @@ Vehicle::Vehicle() int chance = 0; if (veh->m_nVehicleClass == CLASS_NORMAL) // Normal + { chance = Random(1, 20); + } if (veh->m_nVehicleClass == CLASS_RICHFAMILY) // Rich family + { chance = Random(1, 4); + } if (veh->m_nVehicleClass == CLASS_EXECUTIVE) // Executive + { chance = Random(1, 3); + } if (chance == 1 && !IsNeonInstalled(veh) && veh->m_pDriver != pPlayer) { @@ -228,7 +235,9 @@ void Vehicle::RemoveComponent(const std::string& component, const bool display_m player->m_pVehicle->RemoveVehicleUpgrade(icomp); if (display_message) + { SetHelpMessage("Component removed", false, false, false); + } } catch (...) { @@ -267,220 +276,8 @@ int Vehicle::GetRandomTrainIdForModel(int model) int id = Random(_start, _end); return train_ids[id]; } - -// Get vehicle HandlingId -void Vehicle::ParseVehiclesIDE() -{ - std::string m_FilePath = std::string(paths::GetGameDirPathA()) + "/data/vehicles.ide"; - - if (fs::exists(m_FilePath)) - { - std::ifstream file(m_FilePath); - 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); - - // 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()); - - m_VehicleIDE[model] = temp; - } - catch (...) - { - flog << "Error while parsing line, " << line << std::endl; - } - } - - file.close(); - } - else flog << "Vehicle.ide file not found"; -} - - -void Vehicle::GenerateHandlingDataFile(int phandling) -{ - FILE* fp = fopen("handling.txt", "w"); - - std::string handlingId = m_VehicleIDE[FindPlayerPed()->m_pVehicle->m_nModelIndex]; - float fMass = patch::Get(phandling + 0x4); - float fTurnMass = patch::Get(phandling + 0xC); - float fDragMult = patch::Get(phandling + 0x10); - float CentreOfMassX = patch::Get(phandling + 0x14); - float CentreOfMassY = patch::Get(phandling + 0x18); - float CentreOfMassZ = patch::Get(phandling + 0x1C); - int nPercentSubmerged = patch::Get(phandling + 0x20); - float fTractionMultiplier = patch::Get(phandling + 0x28); - float fTractionLoss = patch::Get(phandling + 0xA4); - float TractionBias = patch::Get(phandling + 0xA8); - float fEngineAcceleration = patch::Get(phandling + 0x7C) * 12500; - float fEngineInertia = patch::Get(phandling + 0x80); - int nDriveType = patch::Get(phandling + 0x74); - int nEngineType = patch::Get(phandling + 0x75); - float BrakeDeceleration = patch::Get(phandling + 0x94) * 2500; - float BrakeBias = patch::Get(phandling + 0x98); - int ABS = patch::Get(phandling + 0x9C); - float SteeringLock = patch::Get(phandling + 0xA0); - float SuspensionForceLevel = patch::Get(phandling + 0xAC); - float SuspensionDampingLevel = patch::Get(phandling + 0xB0); - float SuspensionHighSpdComDamp = patch::Get(phandling + 0xB4); - float Suspension_upper_limit = patch::Get(phandling + 0xB8); - float Suspension_lower_limit = patch::Get(phandling + 0xBC); - float Suspension_bias = patch::Get(phandling + 0xC0); - float Suspension_anti_dive_multiplier = patch::Get(phandling + 0xC4); - float fCollisionDamageMultiplier = patch::Get(phandling + 0xC8) * 0.338; - int nMonetaryValue = patch::Get(phandling + 0xD8); - - int MaxVelocity = patch::Get(phandling + 0x84); - MaxVelocity = MaxVelocity * 206 + (MaxVelocity - 0.918668) * 1501; - - int modelFlags = patch::Get(phandling + 0xCC); - int handlingFlags = patch::Get(phandling + 0xD0); - - int front_lights = patch::Get(phandling + 0xDC); - int rear_lights = patch::Get(phandling + 0xDD); - int vehicle_anim_group = patch::Get(phandling + 0xDE); - int nNumberOfGears = patch::Get(phandling + 0x76); - float fSeatOffsetDistance = patch::Get(phandling + 0xD4); - - 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); - - fclose(fp); -} #endif -void Vehicle::ParseCarcolsDAT() -{ - std::string m_FilePath = GAME_PATH((char*)"/data/carcols.dat"); - - if (fs::exists(m_FilePath)) - { - std::ifstream file(m_FilePath); - 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); - - std::vector color = { red / 255.0f, green / 255.0f, blue / 255.0f }; - m_CarcolsColorData.push_back(color); - - ++count; - } - catch (...) - { - flog << "Error while parsing car line, " << line << std::endl; - } - } - - if (car_section) - { - std::string temp; - std::stringstream ss(line); - - getline(ss, temp, ','); - std::string name = temp; - while (getline(ss, temp, ',')) - { - try - { - std::for_each(name.begin(), name.end(), [](char& c) - { - c = ::toupper(c); - }); - - int val = std::stoi(temp); - if (!(std::find(m_CarcolsCarData[name].begin(), m_CarcolsCarData[name].end(), val) != - m_CarcolsCarData[name].end())) - m_CarcolsCarData[name].push_back(val); - } - catch (...) - { - flog << "Error while parsing car line, " << line << std::endl; - } - } - } - } - - file.close(); - } - else - { - flog << "Error locating Vehicle.ide"; - } -} - #ifdef GTASA void Vehicle::SpawnVehicle(std::string& smodel) #elif GTAVC @@ -752,6 +549,29 @@ void Vehicle::Draw() } #ifdef GTASA Ui::CheckboxAddress("Decreased traffic", 0x96917A); + // if (Ui::CheckboxWithHint("Disable collisions", &m_bDisableColDetection)) + // { + // if (m_bDisableColDetection) + // { + // patch::SetUChar(0x56717B, 0x7D); + // patch::SetUChar(0x56725D, 0x7D); + // } + // // update flags for exising vehicles + // for (auto veh : CPools::ms_pVehiclePool) + // { + // if (veh == FindPlayerVehicle(-1, false)) + // { + // continue; + // } + // if (m_bDisableColDetection) + // { + // CCollisionData* pColData = veh->GetColModel()->m_pColData; + // // pColData->m_nNumSpheres = 0; + // pColData->m_nNumBoxes = 0; + // pColData->m_nNumTriangles = 0; + // } + // } + // } #endif ImGui::NextColumn(); #ifdef GTASA @@ -1372,7 +1192,7 @@ void Vehicle::Draw() if (ImGui::Button("Save to file", ImVec2(Ui::GetSize(3)))) { - GenerateHandlingDataFile(pHandling); + FileHandler::GenerateHandlingFile(pHandling, m_VehicleIDE); SetHelpMessage("Handling saved", false, false, false); } diff --git a/src/Vehicle.h b/src/Vehicle.h index 6390491..44b0b0e 100644 --- a/src/Vehicle.h +++ b/src/Vehicle.h @@ -3,7 +3,9 @@ #ifdef GTASA #include "Neon.h" #include "Paint.h" +#endif +#ifdef GTASA class Vehicle : public Paint, public Neon #elif GTAVC class Vehicle @@ -32,6 +34,7 @@ private: }; #ifdef GTASA + inline static bool m_bDisableColDetection; inline static std::map m_VehicleIDE; struct m_Neon { @@ -92,10 +95,8 @@ private: static void AddComponent(const std::string& component, bool display_message = true); static void RemoveComponent(const std::string& component, bool display_message = true); static int GetRandomTrainIdForModel(int model); - static void ParseVehiclesIDE(); static void GenerateHandlingDataFile(int phandling); #endif - static void ParseCarcolsDAT(); public: #ifdef GTASA diff --git a/src/Visual.cpp b/src/Visual.cpp index 348e2c5..1a33d10 100644 --- a/src/Visual.cpp +++ b/src/Visual.cpp @@ -29,94 +29,6 @@ Visual::Visual() }; } -int Visual::CalcArrayIndex() -{ - int hour = CClock::ms_nGameClockHours; - -#ifdef GTASA - int result = 0; - - if (m_nTimecycHour == 24) - { - result = hour; - } - else - { - if (hour < 5) result = 0; - if (hour == 5) result = 1; - if (hour == 6) result = 2; - if (7 <= hour && hour < 12) result = 3; - if (12 <= hour && hour < 19) result = 4; - if (hour == 19) result = 5; - if (hour == 20 || hour == 21) result = 6; - if (hour == 22 || hour == 23) result = 7; - } - - return 23 * result + CWeather::OldWeatherType; -#elif GTAVC - return 7 * hour + CWeather::OldWeatherType; -#endif -} - -bool Visual::TimeCycColorEdit3(const char* label, uchar* r, uchar* g, uchar* b, ImGuiColorEditFlags flags) -{ - bool rtn = false; - int val = CalcArrayIndex(); - -#ifdef GTASA - auto red = static_cast(patch::GetPointer(int(r))); - auto green = static_cast(patch::GetPointer(int(g))); - auto blue = static_cast(patch::GetPointer(int(b))); -#elif GTAVC - auto red = static_cast(r); - auto green = static_cast(g); - auto blue = static_cast(b); -#endif - - float col[3]{ red[val] / 255.0f, green[val] / 255.0f, blue[val] / 255.0f }; - - if (ImGui::ColorEdit3(label, col, flags)) - { - red[val] = col[0] * 255; - green[val] = col[1] * 255; - blue[val] = col[2] * 255; - rtn = true; - } - - return rtn; -} - -bool Visual::TimeCycColorEdit4(const char* label, uchar* r, uchar* g, uchar* b, uchar* a, ImGuiColorEditFlags flags) -{ - bool rtn = false; - int val = CalcArrayIndex(); - -#ifdef GTASA - auto red = static_cast(patch::GetPointer(int(r))); - auto green = static_cast(patch::GetPointer(int(g))); - auto blue = static_cast(patch::GetPointer(int(b))); - auto alpha = static_cast(patch::GetPointer(int(a))); -#elif GTAVC - auto red = static_cast(r); - auto green = static_cast(g); - auto blue = static_cast(b); - auto alpha = static_cast(a); -#endif - - float col[4]{ red[val] / 255.0f, green[val] / 255.0f, blue[val] / 255.0f, alpha[val] / 255.0f }; - - if (ImGui::ColorEdit4(label, col, flags)) - { - red[val] = col[0] * 255; - green[val] = col[1] * 255; - blue[val] = col[2] * 255; - alpha[val] = col[3] * 255; - rtn = true; - } - - return rtn; -} - template int GetTCVal(T* addr, int index) { @@ -259,6 +171,99 @@ void Visual::GenerateTimecycFile() #endif } +int Visual::CalcArrayIndex() +{ + int hour = CClock::ms_nGameClockHours; + +#ifdef GTASA + int result = 0; + + if (m_nTimecycHour == 24) + { + result = hour; + } + else + { + if (hour < 5) result = 0; + if (hour == 5) result = 1; + if (hour == 6) result = 2; + if (7 <= hour && hour < 12) result = 3; + if (12 <= hour && hour < 19) result = 4; + if (hour == 19) result = 5; + if (hour == 20 || hour == 21) result = 6; + if (hour == 22 || hour == 23) result = 7; + } + + return 23 * result + CWeather::OldWeatherType; +#elif GTAVC + return 7 * hour + CWeather::OldWeatherType; +#endif +} + +bool Visual::TimeCycColorEdit3(const char* label, uchar* r, uchar* g, uchar* b, ImGuiColorEditFlags flags) +{ + bool rtn = false; + int val = CalcArrayIndex(); + +#ifdef GTASA + auto red = static_cast(patch::GetPointer(int(r))); + auto green = static_cast(patch::GetPointer(int(g))); + auto blue = static_cast(patch::GetPointer(int(b))); +#elif GTAVC + auto red = static_cast(r); + auto green = static_cast(g); + auto blue = static_cast(b); +#endif + + float col[3]{ red[val] / 255.0f, green[val] / 255.0f, blue[val] / 255.0f }; + + if (ImGui::ColorEdit3(label, col, flags)) + { + red[val] = col[0] * 255; + green[val] = col[1] * 255; + blue[val] = col[2] * 255; + rtn = true; + } + + return rtn; +} + +char __cdecl GetWaterLevelNoWaves(float x, float y, float z, int a4, __int64 a5) +{ + return 0; +} + +bool Visual::TimeCycColorEdit4(const char* label, uchar* r, uchar* g, uchar* b, uchar* a, ImGuiColorEditFlags flags) +{ + bool rtn = false; + int val = CalcArrayIndex(); + +#ifdef GTASA + auto red = static_cast(patch::GetPointer(int(r))); + auto green = static_cast(patch::GetPointer(int(g))); + auto blue = static_cast(patch::GetPointer(int(b))); + auto alpha = static_cast(patch::GetPointer(int(a))); +#elif GTAVC + auto red = static_cast(r); + auto green = static_cast(g); + auto blue = static_cast(b); + auto alpha = static_cast(a); +#endif + + float col[4]{ red[val] / 255.0f, green[val] / 255.0f, blue[val] / 255.0f, alpha[val] / 255.0f }; + + if (ImGui::ColorEdit4(label, col, flags)) + { + red[val] = col[0] * 255; + green[val] = col[1] * 255; + blue[val] = col[2] * 255; + alpha[val] = col[3] * 255; + rtn = true; + } + + return rtn; +} + void Visual::Draw() { if (ImGui::BeginTabBar("Visual", ImGuiTabBarFlags_NoTooltip + ImGuiTabBarFlags_FittingPolicyScroll)) @@ -273,6 +278,18 @@ void Visual::Draw() Ui::CheckboxAddress("Armour percentage", 0x589125); Ui::CheckboxAddress("Breath border", 0x589207); Ui::CheckboxAddress("Breath percentage", 0x589209); + if (Ui::CheckboxWithHint("Disable hydrant splash", &m_bDisableHydrant)) + { + if (m_bDisableHydrant) + { + // don't call Fx_c::TriggerWaterHydrant + plugin::patch::Nop(0x4A0D70, 5); + } + else + { + plugin::patch::SetRaw(0x4A0D70, (char*)"\xE9\x94\x3F\xF6\xFF", 5); + } + } Ui::CheckboxAddress("Gray radar", 0xA444A4); Ui::CheckboxAddress("Health border", 0x589353); Ui::CheckboxAddress("Health percentage", 0x589355); @@ -290,11 +307,52 @@ void Visual::Draw() } Ui::CheckboxAddressEx("Hide wanted level", 0x58DD1B, 0x90, 1); + + if (Ui::CheckboxWithHint("Invisible water", &m_bInvisibleWater)) + { + if (!m_bNoWater) + { + if (m_bInvisibleWater) + { + // don't call CWaterLevel::RenderWater() + plugin::patch::Nop(0x53E004, 5); + plugin::patch::Nop(0x53E142, 5); + } + else + { + // restore call CWaterLevel::RenderWater() + plugin::patch::SetRaw(0x53E004, (char*)"\xE8\x47\x16\x1B\x00", 5); + plugin::patch::SetRaw(0x53E142, (char*)"\xE8\x09\x15\x1B\x00", 5); + } + } + } if (Ui::CheckboxWithHint("Lock weather", &m_bLockWeather)) { m_nBacWeatherType = CWeather::OldWeatherType; } + if (Ui::CheckboxWithHint("No water", &m_bNoWater)) + { + if (m_bNoWater) + { + // don't call CWaterLevel::RenderWater() + plugin::patch::Nop(0x53E004, 5); + plugin::patch::Nop(0x53E142, 5); + + // rtn CWaterLevel::GetWaterLevelNoWaves + plugin::patch::SetRaw(0x6E8580, (char*)"\x32\xC0\xC3", 3); + } + else + { + // restore call CWaterLevel::RenderWater() + plugin::patch::SetRaw(0x53E004, (char*)"\xE8\x47\x16\x1B\x00", 5); + plugin::patch::SetRaw(0x53E142, (char*)"\xE8\x09\x15\x1B\x00", 5); + + // restore CWaterLevel::GetWaterLevelNoWaves + plugin::patch::SetRaw(0x6E8580, (char*)"\x51\xD9\x44", 3); + } + } + bool radar_state = (patch::Get(0xBA676C) != 2); if (Ui::CheckboxWithHint("Show radar", &radar_state)) { diff --git a/src/Visual.h b/src/Visual.h index 0da31b4..8ab1f6f 100644 --- a/src/Visual.h +++ b/src/Visual.h @@ -6,6 +6,11 @@ private: inline static bool m_bLockWeather; inline static int m_nBacWeatherType; +#ifdef GTASA + inline static bool m_bInvisibleWater; + inline static bool m_bNoWater; + inline static bool m_bDisableHydrant; +#endif // Timecyc inline static int m_nTimecycHour = 8; inline static std::vector m_WeatherNames