diff --git a/src/test/events/test_events.cpp b/src/test/events/test_events.cpp index 6313653..03257b7 100644 --- a/src/test/events/test_events.cpp +++ b/src/test/events/test_events.cpp @@ -9,6 +9,9 @@ #include "CClock.h" #include "CTimer.h" +// My code +#include "test/test_ped.h" + #endif //GTASA // TODO Move Chaos mode events into its own file. @@ -122,17 +125,16 @@ void KillPlayerInMiddleOfMap() } - +//CVehicle* cVehicle; // This seems to work in this class. //#define _CHAOS_MODE void TestEvents::ChaosModeEvent() { + // Put this outside of the preprocessors here so the preprocessors don't comment it out. PlayerFunctions* playerFunctions = new PlayerFunctions(); - CPlayerPed* player = FindPlayerPed(); - - + CPlayerPed* player = FindPlayerPed(); //if(PlayerFunctions::m_bRespawnMiddleOfMap) // This doesn't seem to toggle it on/off properly @@ -155,17 +157,59 @@ void TestEvents::ChaosModeEvent() // 6-18-2024 @ 3:37AM // I figured out how to get timers working on here, this is running in Events::gameProcessEvent in cheatmenu.cpp // This does work. Copied from overlay.cpp on lines 429-432 - size_t game_ms = CTimer::m_snTimeInMilliseconds; - static size_t interval = 0; + //size_t game_ms = CTimer::m_snTimeInMilliseconds; + //static size_t interval = 0; + + // Toggle the gravity values, this seems to screw with it for a couple seconds and has a fun effect. + PedTestPage::InsaneGravity(); + PedTestPage::NormalGravity(); + +// Crashes +#ifdef _TEST1 + // Try to make this blow the player up if they press the horn button 5 times. + //m_nHornCounter + // This doesn't seem to work. + //if(CVehicle::m_nHornCounter > 1) + uint hornCounter = cVehicle->m_nHornCounter; + + //if(cVehicle.m_nHornCounter > 1) + // Will this work? + if(PlayerFunctions::IsPlayerInVehicle() && hornCounter > 5) + { + // This might fix the timer? + if (game_ms - interval > 1000) + { + PlayerFunctions::SpawnBombOnPlayer(); + } + } +#endif //_TEST1 + + // Doesn't work, disabled. +#ifdef _TEST1 + // Spawn a bomb on the players vehicle if it is upside down every second :P + if (PlayerFunctions::IsPlayerInVehicle()) + { + if (CVehicle::IsUpsideDown && game_ms - interval > 1000) + { + PlayerFunctions::SpawnBombOnPlayer(); + } + } +#endif //_TEST1 + + // I disabled this code to test something else. +#ifdef _TEST1 // Add test timer for this, this works! if (game_ms - interval > 1000) { // KillPlayerInVehicle(); interval = game_ms; } - + KillPlayerInMiddleOfMap(); +#endif //_TEStT1 + + #endif //_CHAOS_MODE } diff --git a/src/test/functions/misc_functions.cpp b/src/test/functions/misc_functions.cpp new file mode 100644 index 0000000..293c61c --- /dev/null +++ b/src/test/functions/misc_functions.cpp @@ -0,0 +1,226 @@ +#include "pch.h" +#include "misc_functions.h" + + +////////////////////////// +// Misc options +////////////////////////// + +// Untested +/// +/// Opens the save menu, only works if the player is not dead. +/// +void MiscFunctions::OpenSaveMenu() +{ + CPlayerPed* player = FindPlayerPed(); + if (!player->IsAlive()) + { + Command(); + } +} + + +/// +/// Toggle the player talking or not. +/// +void MiscFunctions::TogglePlayerSpeech(bool toggle) +{ + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + + if (toggle) + { + Command(hplayer); + } + else + { + Command(hplayer); + } +} + +////////////////// +// Begin untested functions +////////////////// + +// Test messing with a void or boolean from the code in a memory address +/* +// 0x4B1330 +bool CEventHitByWaterCannon::AffectsPed +*/ + +// Will this work? Possibly patch out the code so the player or peds aren't effected by a firetruck water cannon. +// I don't think this works like this though but it looks like I can replace functions in the code, +// using the reversed code as a guide on what the functions are doing. +// TODO Test this later! +bool ToggleWaterCannonTest() +{ + return false; +} + + +void ToggleWaterCannonHit() +{ + patch::ReplaceFunction(0x4B1330, *ToggleWaterCannonTest, true); +} + +// This is untested but it should work like this. +void ChangeClothes(CPed* player, const char* textureName, const char* modelName, int bodyPart) +{ + + //Command(player, "tshirt2horiz", "tshirt2", 0); + Command(player, textureName, modelName, bodyPart); +} + +/// +/// Change the players current outfit, this isn't tested yet. +/// +void ChangePlayerClothes() +{ + CPed* player = FindPlayerPed(); + // https://wiki.multitheftauto.com/wiki/CJ_Clothes + // player, textureName, modelName, bodyPart + // Sun glasses + //Command(player, "glasses01dark", "glasses01", 15); + ChangeClothes(player, "glasses01dark", "glasses01", CLOTHES_MODEL_GLASSES); + // White striped shirt. + //Command(player, "tshirt2horiz", "tshirt2", 0); + ChangeClothes(player, "tshirt2horiz", "tshirt2", CLOTHES_MODEL_TORSO); + // Camo green pants + ChangeClothes(player, "worktrcamogrn", "worktr", CLOTHES_MODEL_LEGS); + // Shoes + ChangeClothes(player, "sneakerbincblu", "sneaker", CLOTHES_MODEL_SHOES); + // Watch ,this one didn't seem to have an enum for it + ChangeClothes(player, "watchcro", "watch", 14); + +} + + + + +/// +/// // Change the current day of the week, from 1-7. Untested. +/// +/// Date to set the game time to. +void ChangeCurrentDay(int dayToSet) +{ + patch::Set(0xB7014E, dayToSet, true); +} + +/// +/// Get the current day of the week, from 1-7. Untested. +/// +void GetCurrentDay() +{ + patch::Get(0xB7014E); +} + +////////////////// +// End untested functions +////////////////// + +////////////////////////// +// Blip options +////////////////////////// + + +void MiscFunctions::HideAllBlips(bool toggle) +{ + + if (toggle) + { + Command(true); + } + else + { + Command(false); + + } + // Will it work like this also? + //Command(toggle); +} + +////////////////////////// +// +////////////////////////// + + + +////////////////////////// +// Garage functions +// These are untested but they should work. +////////////////////////// + +bool MiscFunctions::IsGarageOpen(int garageId) +{ + if(Command(garageId)) + { + return true; + } + else + { + return false; + } + +} + +bool MiscFunctions::IsGarageClosed(int garageId) +{ + if (Command(garageId)) + { + return true; + } + else + { + return false; + } +} +void MiscFunctions::OpenGarage(int garageId) +{ + Command(garageId); +} + +void MiscFunctions::CloseGarage(int garageId) +{ + Command(garageId); + +} + +void MiscFunctions::ActivateGarage(int garageId) +{ + Command(garageId); + //Util::SetMessage("You have enabled the garage with id " + garageId); +} + + +void MiscFunctions::DeactivateGarage(int garageId) +{ + Command(garageId); + //Util::SetMessage("You have disabled the garage with id " + garageId); +} + +void MiscFunctions::SetGarageType(int garageId, int garageType) +{ + Command(garageId, garageType); + Util::SetMessage(std::format("You have changed the garage with id {} to type id {} ", garageId, garageType).c_str()); +} + +void MiscFunctions::SetResprayFree(int garageId, bool toggle) +{ + if (toggle) + { + Command(garageId, true); + Util::SetMessage("Resprays are now free at this Pay N Spray!"); + // Resprays are now free at this Pay N Spray! + } + else + { + Command(garageId, false); + Util::SetMessage("Resprays are no longer free at this Pay N Spray!"); + // Resprays are no longer free at this Pay N Spray! + } + +} + +////////////////////////// +// +////////////////////////// \ No newline at end of file diff --git a/src/test/functions/misc_functions.h b/src/test/functions/misc_functions.h new file mode 100644 index 0000000..5f83bbb --- /dev/null +++ b/src/test/functions/misc_functions.h @@ -0,0 +1,26 @@ +#pragma once +//#include "pch.h" + +// TODO Make this stuff not static +class MiscFunctions +{ +public: + // Garage functions + static bool IsGarageOpen(int garageId); + static bool IsGarageClosed(int garageId); + static void OpenGarage(int garageId); + static void CloseGarage(int garageId); + + static void ActivateGarage(int garageId); + static void DeactivateGarage(int garageId); + // https://library.sannybuilder.com/#/sa/enums/GarageType + static void SetGarageType(int garageId, int garageType); + static void SetResprayFree(int garageId, bool state); + + static void OpenSaveMenu(); + static void TogglePlayerSpeech(bool toggle); + + // Blip functions + static void HideAllBlips(bool toggle); + +}; \ No newline at end of file diff --git a/src/test/functions/ped_functions.cpp b/src/test/functions/ped_functions.cpp new file mode 100644 index 0000000..877e955 --- /dev/null +++ b/src/test/functions/ped_functions.cpp @@ -0,0 +1,111 @@ +#include "pch.h" +#include "ped_functions.h" +#include "enums/audio_ids.h" + + +#ifdef GTASA +#include "CExplosion.h" +#include "CPopulation.h" +#include "CTaskComplexWanderStandard.h" +#include "CSprite.h" +#endif + +// Enable test features in this class. +#define _TEST + +// Spawn random ped + +// Taken from plugin-sdk examples under PedSpawner in Main.cpp +// TODO Convert these to an enum sometime. +int pedModelIds[] = { 0, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 57, 58, 59, 60, 61, 62, 66, 67, 68, 70, 71, 72, 73, 78, 79, 80, 81, 82, 83, 84, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 127, 128, 132, + 133, 134, 135, 136, 137, 142, 143, 144, 146, 147, 153, 154, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170, 171, + 173, 174, 175, 176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 200, 202, 203, 204, 206, 209, 210, 212, 213, 217, 220, + 221, 222, 223, 227, 228, 229, 230, 234, 235, 236, 239, 240, 241, 242, 247, 248, 249, 250, 252, 253, 254, 255, 258, 259, 260, 261, 262, + 9, 10, 11, 12, 13, 31, 38, 39, 40, 41, 53, 54, 55, 56, 63, 64, 69, 75, 76, 77, 85, 87, 88, 89, 90, 91, 92, 93, 129, 130, 131, 138, 139, + 140, 141, 145, 148, 150, 151, 152, 157, 169, 172, 178, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 201, 205, 207, 211, 214, 215, + 216, 218, 219, 224, 225, 226, 231, 232, 233, 237, 238, 243, 244, 245, 246, 251, 256, 257, 263 }; + +// Cluckin bell, +int miscPedIds[] = { 167, }; + +int copModelIds[] = { 280, 281, 282, 283, 284, 285, 286, 287, 288, }; + +// I wonder how to return this value to use it in the events, so if the ped talks or dies they blow up. +// I would need to return the ped. +#ifdef GTASA +void PedFunctions::SpawnRandomPed() +{ + CPlayerPed* player = FindPlayerPed(); + // Taken from plugin-sdk examples under PedSpawner in Main.cpp + // https://github.com/DK22Pac/plugin-sdk/blob/master/examples/PedSpawner/Main.cpp + // Ped + int modelID = pedModelIds[rand() % 250]; // Random model id + CStreaming::RequestModel(modelID, 0); // Request the model + CStreaming::LoadAllRequestedModels(false); // Whatever this does. + CPed* ped = new CCivilianPed(CPopulation::IsFemale(modelID) ? PED_TYPE_CIVFEMALE : PED_TYPE_CIVMALE, modelID); + + + // New + // Idk how this one works + //ped->m_pIntelligence + + // Add blip for char +#ifdef _TEST + // This works but doesn't get removed when the ped dies. + // Puts a red marker over them. + // https://library.sannybuilder.com/#/sa/default/0187 + + // TODO Figure out how to store marker and delete it when they die. + Command(ped); +#endif //_TEST + + if (ped) + { + // TODO Figure out how to draw a health bar above the peds head. + + // This looks like it's getting the offset of the current players coordinates. + ped->SetPosn(FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 5.0f, 3.0f))); + ped->SetOrientation(0.0f, 0.0f, 0.0f); + // This should make the spawned in ped hate the player and want to kill them + // Idea taken from here in this cleo script.: https://gtaforums.com/topic/993040-sa-cleo-detect-that-the-char-is-trying-to-attack-another-char/ + // This didn't work + ped->m_acquaintance.m_nHate = PED_TYPE_PLAYER1; + ped->m_acquaintance.m_nHate = PED_TYPE_PLAYER2; + // Give the ped a MP5 + //ped->GiveWeapon(WEAPON_MP5, 999, true); + + // Stop the ped from talking + //ped->DisablePedSpeech(1); + + // Give them 1000 health + ped->m_fHealth = 1000; + // Set ped to Regular + ped->m_nPedType = PED_TYPE_CIVMALE; + // Stop the medics from being able to revive the ped. + ped->m_nPedFlags.bAllowMedicsToReviveMe = false; + CVector pedPos = ped->GetPosition(); + + // This doesn't work, it would need to be in an event. + //if (ped->m_nPedFlags.bIsTalking) + //{ + // // Spawn a bomb on them if they speak. + // Command(pedPos.x, pedPos.y, pedPos.z, EXPLOSION_CAR); + // Command(pedPos.x, pedPos.y, pedPos.z, AudioIds::EXPLOSION_SOUND); + //} + + + + CWorld::Add(ped); + ped->PositionAnyPedOutOfCollision(); + ped->m_pIntelligence->m_TaskMgr.SetTask(new CTaskComplexWanderStandard(4, rand() % 8, true), 4, false); + // What is nCommand, for the char value? + //ped->m_pIntelligence->m_TaskMgr.SetTask(new CTaskSimpleUseGun(player, player->GetPosition(), 'TT', 1U, false)); + //ped->m_pIntelligence->m_TaskMgr.SetTask(new CTaskSimpleFight()); + + // This makes it to where the ped can be cleared by the game. + ped->CanBeDeleted(); + } +} +#endif //GTASA \ No newline at end of file diff --git a/src/test/functions/ped_functions.h b/src/test/functions/ped_functions.h new file mode 100644 index 0000000..e4f9549 --- /dev/null +++ b/src/test/functions/ped_functions.h @@ -0,0 +1,10 @@ +#pragma once +class PedFunctions +{ +public: + // List of the ped model ids + //int pedModelIds[]; + + static void SpawnRandomPed(); +}; + diff --git a/src/test/functions/player_functions.cpp b/src/test/functions/player_functions.cpp index d1e695f..49cc135 100644 --- a/src/test/functions/player_functions.cpp +++ b/src/test/functions/player_functions.cpp @@ -5,10 +5,10 @@ #include "CExplosion.h" - /// /// Mostly helper functions for the player. /// +/// PlayerFunctions::PlayerFunctions() { @@ -18,6 +18,20 @@ PlayerFunctions::PlayerFunctions() //} } +bool PlayerFunctions::IsPlayerDead() +{ + CPlayerPed* player = FindPlayerPed(); + if(!player->IsAlive()) + { + return true; + } + else + { + return false; + } + return false; +} + void PlayerFunctions::KillPlayer() { CPlayerPed* player = FindPlayerPed(); @@ -25,55 +39,83 @@ void PlayerFunctions::KillPlayer() player->m_fArmour = 0; } +////////////////////////// +// Cheat functions +////////////////////////// + /// -/// Sets the never wanted value, incomplete +/// Sets the never wanted value, untested /// /// If never wanted is on -static void SetNeverWanted(bool toggle) +void PlayerFunctions::SetNeverWanted(bool toggle) { + // TODO Possibly replace these with byte instead of bool. if(toggle) { // Enable never wanted + patch::Set(0x969171, 1, true); } else { // Disable never wanted + patch::Set(0x969171, 1, true); } } /// -/// Sets the player as invincible, incomplete +/// Sets the player as invincible, untested /// /// If the player is invincible. -static void SetInvincible(bool toggle) +void PlayerFunctions::SetInvincible(bool toggle) { + CPed* player = FindPlayerPed(); + // Taken from player.cpp on line 124, looks like this is running the infinite health cheat using the memory address if (toggle) { - // Enable invincibility + // Enable invincibility + patch::Set(0x96916D, 1, true); + player->m_nPhysicalFlags.bBulletProof = 1; + player->m_nPhysicalFlags.bCollisionProof = 1; + player->m_nPhysicalFlags.bExplosionProof = 1; + player->m_nPhysicalFlags.bFireProof = 1; + player->m_nPhysicalFlags.bMeleeProof = 1; } else { // Disable invincibility + patch::Set(0x96916D, 0, true); + player->m_nPhysicalFlags.bBulletProof = 0; + player->m_nPhysicalFlags.bCollisionProof = 0; + player->m_nPhysicalFlags.bExplosionProof = 0; + player->m_nPhysicalFlags.bFireProof = 0; + player->m_nPhysicalFlags.bMeleeProof = 0; } } /// -/// Sets the infinte ammo cheat, incomplete. +/// Sets the infinte ammo cheat, untested. /// /// If infinite ammo is active. -static void SetInfiniteAmmo(bool toggle) +void PlayerFunctions::SetInfiniteAmmo(bool toggle) { + // TODO Possibly replace these with byte instead of bool. + if (toggle) { // Enable infinite ammo + patch::Set(0x969178, 1, true); } else { // Disable infinite ammo + patch::Set(0x969178, 0, true); } } -// This should work in here, untested +////////////////////////// +// +////////////////////////// + /// /// Spawn a bomb on the player with sound, like a grenade or satchel charge. @@ -99,18 +141,12 @@ void PlayerFunctions::SpawnBombOnPlayer() Command(playerPos.x, playerPos.y, playerPos.z, EXPLOSION_CAR); - // https://library.sannybuilder.com/#/sa/default/018C - // These might work: https://sampwiki.blast.hk/wiki/SoundID - Command(playerPos.x, playerPos.y, playerPos.z, AudioIds::EXPLOSION_SOUND); + PlayerFunctions::AddSoundOnPlayer(AudioIds::EXPLOSION_SOUND); - // This does about the same as above with a bit more code. - - - // Will this work? + // Alternative method to do this. //int explosionId = CExplosion::AddExplosion(FindPlayerPed(), FindPlayerPed(), EXPLOSION_CAR, playerPos, 1000, 1, 1.0f, true); //CExplosion::GetExplosionPosition(explosionId); - //CExplosion::RemoveAllExplosionsInArea(); #endif //GTASA } @@ -147,6 +183,54 @@ bool PlayerFunctions::IsPlayerInArea(float x1, float y1, float z1, float x2, flo } } +////////////////////////// +// Vehicle functions +////////////////////////// + + +////////////////////////// +// Check for the player being in all types of vehicles +////////////////////////// + +bool IsPlayerInBoat() +{ + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + if (Command(hplayer)) { + return true; + } + else + { + return false; + } +} + +bool IsPlayerInHeli() +{ + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + if (Command(hplayer)) { + return true; + } + else + { + return false; + } +} + +bool IsPlayerInPlane() +{ + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + if (Command(hplayer)) { + return true; + } + else + { + return false; + } +} + /// /// Check if player is in a train /// @@ -164,6 +248,11 @@ bool PlayerFunctions::IsPlayerInTrain() } } + +/// +/// Check if the player is in a vehicle +/// +/// If the player is in a vehicle. bool PlayerFunctions::IsPlayerInVehicle() { CPlayerPed* player = FindPlayerPed(); @@ -178,3 +267,69 @@ bool PlayerFunctions::IsPlayerInVehicle() } } +////////////////////////// +// +////////////////////////// + +/// +/// Check if the player is stuck under a car +/// +bool PlayerFunctions::IsPedStuckUnderCar() +{ +#ifdef GTASA + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + + + // I don't think this will work making it like this. + bool bIsPlayerStuckUnderCar = Command(player); + + if (bIsPlayerStuckUnderCar) + { + return true; + } + else + { + return false; + } + +#endif //GTASA +} + +////////////////////////// +// +////////////////////////// + + +////////////////////////// +// Sound testing +////////////////////////// + +// https://library.sannybuilder.com/#/sa/default/018C +// List of sound ids: https://sampwiki.blast.hk/wiki/SoundID +/// +/// Play a sound on the player at their current coordinates. +/// +/// The audio id to play +void PlayerFunctions::AddSoundOnPlayer(int audioId) +{ + CPlayerPed* player = FindPlayerPed(); + CVector playerPos = player->GetPosition(); + //Command(playerPos.x, playerPos.y, playerPos.z, AudioIds::EXPLOSION_SOUND); + // Will this work? + Command(playerPos.x, playerPos.y, playerPos.z, audioId); +} + +// This is untested. +/// +/// Play a sound at the specifed coordinates, takes an x,y,z and an audio id. +/// +/// The id of the sound to play +void AddSoundAtCoords(float posX, float posY, float posZ, int audioId) +{ + Command(posX, posY, posZ, audioId); +} + +////////////////////////// +// +////////////////////////// \ No newline at end of file diff --git a/src/test/functions/player_functions.h b/src/test/functions/player_functions.h index b4216b0..66a7cde 100644 --- a/src/test/functions/player_functions.h +++ b/src/test/functions/player_functions.h @@ -12,4 +12,10 @@ public: static bool IsPlayerInVehicle(); static bool IsPlayerInArea(float x1, float y1, float z1, float x2, float y2, float z2); static bool IsPlayerInTrain(); + static bool IsPedStuckUnderCar(); + static void AddSoundOnPlayer(int audioId); + static bool IsPlayerDead(); + static void SetNeverWanted(bool toggle); + static void SetInvincible(bool toggle); + static void SetInfiniteAmmo(bool toggle); }; diff --git a/src/test/functions/vehicle_functions.cpp b/src/test/functions/vehicle_functions.cpp index 3253180..a3f4175 100644 --- a/src/test/functions/vehicle_functions.cpp +++ b/src/test/functions/vehicle_functions.cpp @@ -33,35 +33,35 @@ void VehicleFunctions::PlayerInCarMsg() } } -/// -/// Check if the players current vehicle is in the water -/// -/// If the current vehicle is in water. bool VehicleFunctions::IsCarInWater() { -#ifdef GTASA - CPlayerPed* player = FindPlayerPed(); - int hplayer = CPools::GetPedRef(player); - CVehicle* pVeh = nullptr; + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + CVehicle* pVeh = nullptr; - // TODO Possibly Move this into a vehicle_functions file. - // First we check if the player is in a vehicle - if (PlayerFunctions::IsPlayerInVehicle()) { - CVehicle* pVeh = player->m_pVehicle; - int hVeh = CPools::GetVehicleRef(pVeh); - // https://library.sannybuilder.com/#/sa/default/04D8 - bool isCarInWater = Command(hVeh); + if (PlayerFunctions::IsPlayerInVehicle()) + { + CVehicle* pVeh = player->m_pVehicle; + // Will this work? + int hVeh = CPools::GetVehicleRef(pVeh); + bool bIsCarInWater = Command(hVeh); + + if (bIsCarInWater) + { + return true; + + } + else + { + return false; + } + } + else + { + // This should make this do nothing. + return false; + } + + return false; +} - // If the car is not in water - if (!isCarInWater) - { - return false; - } - // If the car is in water - else - { - return true; - } - } -#endif //GTASA -} \ No newline at end of file diff --git a/src/test/misc/misc_test.cpp b/src/test/misc/misc_test.cpp new file mode 100644 index 0000000..222a23a --- /dev/null +++ b/src/test/misc/misc_test.cpp @@ -0,0 +1,87 @@ +#include "pch.h" +#include "misc_test.h" +#include "CBirds.h" + +#include "CVehicle.h" +#include "CVehicleModelInfo.h" + +// New +#ifdef GTASA +#include "CExplosion.h" +#include "CPopulation.h" +#include "CTaskComplexWanderStandard.h" +#include "CSprite.h" +#endif + +MiscTestPage::MiscTestPage() +{ + +} + +// Testing for messing with the code for the birds in the game. +void BirdMenu() +{ + //if(ImGui::Button("")) + //{ + // + //} + + // Create 10 birds with 20 added to the z coord. + // I don't know if this'll work. + CPlayerPed* player = FindPlayerPed(); + CVector playerPos = player->GetPosition(); + float posX = playerPos.x; + float posY = playerPos.y; + // Spawn 20 above the player + float posZ = playerPos.z + 20; + + // Set the targetPos to a CVector + CVector targetPos = CVector(posX, posY, posZ); + // Create the birds. + CBirds::CreateNumberOfBirds(playerPos, targetPos, 10, 1, true); +} + + +static void PlayerPedTest() +{ + CPlayerPed* player = FindPlayerPed(); + + // Got this from https://github.com/JuniorDjjr/CLEOPlus/blob/main/CLEOPlus/Coop.cpp#L30 + // I think I can modify more for the player or other peds using this + CPlayerPed* playerTest = CWorld::Players[1].m_pPed; +} + +// TODO Figure out how to put a random put in a vehicle. +static void PedVehicleTest() +{ + +} + + +static void VehicleModelTest() +{ + // Player and vehicle check are needed + CPlayerPed* playerPed = FindPlayerPed(); + CVector playerPos = playerPed->GetPosition(); + CVehicle* playerVehicle = playerPed->m_pVehicle; + + if(playerVehicle) + { + //cVehicleParams + //CVehicleModelInfo:: + // Will this work? Toggle the lights off if on. + if (CVehicleModelInfo::ms_lightsOn) + { + !CVehicleModelInfo::ms_lightsOn; + } + else + { + CVehicleModelInfo::ms_lightsOn; + } + } + + + + //CVehicleModelInfo::m_nVehicleClass; + //CVehicleModelInfo::m_nVehicleType; +} \ No newline at end of file diff --git a/src/test/misc/misc_test.h b/src/test/misc/misc_test.h new file mode 100644 index 0000000..d6d34cb --- /dev/null +++ b/src/test/misc/misc_test.h @@ -0,0 +1,11 @@ +#pragma once +class MiscTestPage +{ +public: + // Blank constructor, I could do something with these. + MiscTestPage(); + MiscTestPage(const MiscTestPage&); + // Menu functions + void MiscTestMenu(); +}; + diff --git a/src/test/test_garage.cpp b/src/test/test_garage.cpp new file mode 100644 index 0000000..c2d8121 --- /dev/null +++ b/src/test/test_garage.cpp @@ -0,0 +1,145 @@ +#include "pch.h" +#include "test_garage.h" +#include "functions/misc_functions.h" + +#ifdef GTASA +#endif //GTASA + +/* + File created by kelson8 +*/ + + +/* +* These values came from below: +* https://wiki.multitheftauto.com/wiki/Garage +* +"Life's a Beach" Mission Garage (Commerce) 1643.43, -1520.3, 14.3438 +1 LSPD Police Impound Garage (not working) - +2 "Los Desperados" Mission Garage (El Corona) 1877.41, -2096.51, 14.0391 +3 Eight Ball Autos (El Corona) 1843.37, -1856.32, 13.875 +4 "Cesar Vialpando" Mission Garage (El Corona) 1798.69, -2146.73, 14 +5 Player Garage (El Corona) 1698.91, -2088.74, 14.1406 +6 LS Burglary Garage (Playe del Seville) 2741.07, -2004.78, 14.875 +7 LowRider Tuning Garage (Willowfield) 2644.86, -2039.23, 14.0391 +8 Pay 'n' Spray (Idlewood) 2071.48, -1831.42, 14.5625 +9 Player Garage (Ganton) 2505.52, -1690.99, 14.3281 +10 Transfender (Temple) 1041.35, -1025.93, 32.6719 +11 Pay 'n' Spray (Temple) 1024.98, -1029.35, 33.1953 +12 Pay 'n' Spray (Santa Maria Beach) 488.28, -1734.7, 12.3906 +13 Player Garage (Santa Maria Beach) 322.4141, -1769.0312, 5.25 +14 Player Garage (Mulholland)* 1353.48, -626.63, 109.82 +15 Wheel Archangels (Ocean Flats) -2716.35, 217.48, 5.3828 +16 "T-Bone Mendez" Mission Garage (Ocean Flats) -2730.47, 72.32, 5.3516 +17 Player Garage (Hashbury) -2454.12, -123.06, 26.9844 +18 Transfender (Doherty) -1935.86, 239.53, 35.3516 +19 Pay 'n' Spray (Downtown) -1904.53, 277.9, 42.9531 +20 SF Burglary Garage (Doherty) -2102.93, -16.05, 36.4844 +21 Player Garage (Doherty) -2026.91, 129.41, 30.4531 +22 Mission Garage (Doherty) -2038.93, 178.81, 29.9375 +23 "Ran Fa Li" Mission Garage (Chinatown) -2162.03, 654.66, 53.375 +24 Michelle's Pay 'n' Spray (Downtown) -1786.81, 1209.42, 25.8359 +25 Player Garage (Calton Heights) -2105.2, 896.93, 77.4453 +26 SFPD Police Impound Garage (not working) - +27 Pay 'n' Spray (Juniper Hollow) -2425.73, 1027.99, 52.2812 +28 Player Garage (Paradiso) -2696.01, 821.45, 50.8516 +29 LVPD Police Impound Garage (not working) - +30 Airport Hangar (Las Venturas Airport) 1586.26, 1222.7, 19.75 +31 LV Burglary Garage (Pilgrim) 2609.52, 1438.37, 11.5938 +32 Pay 'n' Spray (Royal Casino) (not working) - +33 Transfender (Come-A-Lot) 2386.66, 1043.6, 11.5938 +34 Player Garage (Rockshore West) 2449.55, 698.08, 11.6797 +35 Welding Wedding Bomb-workshop [front] (Redsands East) 2006, 2303.73, 11.3125 +Welding Wedding Bomb-workshop [back] (Redsands East) 2006, 2317.6, 11.3125 + +36 Pay 'n' Spray (Redsands East) 1968.74, 2162.49, 12.0938 +37 Player Garage (Redsands West) 1408.64, 1902.69, 11.6797 +38 Player Garage (Prickle Pine) 1278.7, 2529.81, 11.3203 +39 Player Garage (Whitewood Estates) 929.55, 2012.06, 11.6797 +40 Pay 'n' Spray (El Quebrados) -1420.55, 2591.16, 57.7422 +41 Pay 'n' Spray (Fort Carson) -100, 1111.41, 21.6406 +42 Player Garage (Fort Carson) -360.77, 1194.26, 20.5938 +43 Player Garage (Verdant Meadows) 429.98, 2546.52, 17.3516 +44 "Interdiction" Mission Garage (El Castillo del Diablo)* -389.59, 2227.91, 42.9219 +45 Airport Hangar [right] (Verdant Meadows) +Airport Hangar [left] (Verdant Meadows) + 397.48, 2476.63, 19.5156 +412.12, 2476.63, 19.5156 +46 "Puncture Wounds" Mission Garage (Angel Pine)* -2113.04, -2460.62, 30.9141 +47 Pay 'n' Spray (Dillimore) 720.02, -462.52, 16.8594 +48 Player Garage (Palomino Creek) 2231.24, 168.73, 27.7734 +49 Player Garage (Dillimore) +*/ + +enum GarageList +{ + +}; + +GarageTestPage::GarageTestPage() +{ + +} + +#ifdef GTASA +void GarageTestPage::GarageMenu() +{ + + // This didn't seem to work. + ImGui::Text("Ganton Garage"); + if (ImGui::Button("Open")) + { + //if(MiscFunctions::IsGarageClosed(9)) + //{ + MiscFunctions::OpenGarage(9); + Util::SetMessage("Garage opened"); + //} + } + ImGui::SameLine(); + if (ImGui::Button("Close")) + { + //if (MiscFunctions::IsGarageOpen(9)) { + MiscFunctions::CloseGarage(9); + Util::SetMessage("Garage closed"); + //} + } + ImGui::SameLine(); + if (ImGui::Button("Activate")) + { + MiscFunctions::ActivateGarage(9); + Util::SetMessage("You have activated the garage"); + } + + ImGui::SameLine(); + if (ImGui::Button("Deactivate")) + { + MiscFunctions::DeactivateGarage(9); + Util::SetMessage("You have deactivated the garage"); + } + + // Seemed to not open the menu with these here + if (ImGui::Button("Is Closed?")) + { + if (MiscFunctions::IsGarageClosed(9)) { + Util::SetMessage("The garage is closed"); + } + } + + if (ImGui::Button("Is Open?")) + { + if (MiscFunctions::IsGarageOpen(9)) { + Util::SetMessage("The garage is open"); + } + + } + + +} + +#endif //GTASA + +// Drawing the menu +void GarageTestPage::GarageTestMenu() +{ + GarageMenu(); +} \ No newline at end of file diff --git a/src/test/test_garage.h b/src/test/test_garage.h new file mode 100644 index 0000000..2eb1e35 --- /dev/null +++ b/src/test/test_garage.h @@ -0,0 +1,9 @@ +#pragma once +class GarageTestPage +{ +public: + GarageTestPage(); + void GarageTestMenu(); + static void GarageMenu(); +}; + diff --git a/src/test/test_ped.cpp b/src/test/test_ped.cpp index 023666c..cf62e8d 100644 --- a/src/test/test_ped.cpp +++ b/src/test/test_ped.cpp @@ -6,11 +6,15 @@ #include "CExplosion.h" #include "CPopulation.h" #include "CTaskComplexWanderStandard.h" +#include "CSprite.h" #endif // My code #include "functions/player_functions.h" #include "../enums/audio_ids.h" +#include "functions/vehicle_functions.h" +#include "functions/ped_functions.h" + // Incomplete. // https://library.sannybuilder.com/#/sa/default/0672 @@ -50,17 +54,6 @@ static std::vector soundIds = { // BIKE_BOAT_SCHOOL_RESULTS_MUSIC, FLIGHT_SCHOOL_RESULTS_MUSIC //}; -// Taken from plugin-sdk examples under PedSpawner in Main.cpp -int pedModelIds[] = { 0, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 57, 58, 59, 60, 61, 62, 66, 67, 68, 70, 71, 72, 73, 78, 79, 80, 81, 82, 83, 84, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 127, 128, 132, - 133, 134, 135, 136, 137, 142, 143, 144, 146, 147, 153, 154, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170, 171, - 173, 174, 175, 176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 200, 202, 203, 204, 206, 209, 210, 212, 213, 217, 220, - 221, 222, 223, 227, 228, 229, 230, 234, 235, 236, 239, 240, 241, 242, 247, 248, 249, 250, 252, 253, 254, 255, 258, 259, 260, 261, 262, - 9, 10, 11, 12, 13, 31, 38, 39, 40, 41, 53, 54, 55, 56, 63, 64, 69, 75, 76, 77, 85, 87, 88, 89, 90, 91, 92, 93, 129, 130, 131, 138, 139, - 140, 141, 145, 148, 150, 151, 152, 157, 169, 172, 178, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 201, 205, 207, 211, 214, 215, - 216, 218, 219, 224, 225, 226, 231, 232, 233, 237, 238, 243, 244, 245, 246, 251, 256, 257, 263 }; - static void SuicideMenu() { #ifdef GTASA @@ -95,8 +88,14 @@ static void BombMenu() // https://library.sannybuilder.com/#/sa/default/018C // These might work: https://sampwiki.blast.hk/wiki/SoundID - //Command(playerPos.x, playerPos.y, playerPos.z, 1159); - Command(playerPos.x, playerPos.y, playerPos.z, AudioIds::EXPLOSION_SOUND); + // + // Working + //Command(playerPos.x, playerPos.y, playerPos.z, AudioIds::EXPLOSION_SOUND); + // + // + + // This works like this. + PlayerFunctions::AddSoundOnPlayer(AudioIds::EXPLOSION_SOUND); // This does about the same as above with a bit more code. //CExplosion::AddExplosion(FindPlayerPed(), FindPlayerPed(), EXPLOSION_CAR, playerPos, 1000, 1, 1.0f, true); @@ -186,8 +185,6 @@ static void ShowCoordsMenu() // This works!! // 6-14-2024 @ 2:34PM Util::SetMessage(std::format("X: {} Y: {} Z: {}", playerX, playerY, playerZ).c_str()); - //Util::SetMessage("X: " + playerXChar + " Y: " + playerYChar + " Z: " + playerZChar); - } #endif //GTASA } @@ -276,44 +273,98 @@ static void GravityValuesMenu() #endif //GTASA } -// This should spawn a random ped. -#ifdef GTASA -static void SpawnRandomPed() +void PedTestPage::InsaneGravity() { - CPlayerPed* player = FindPlayerPed(); - // Taken from plugin-sdk examples under PedSpawner in Main.cpp - // https://github.com/DK22Pac/plugin-sdk/blob/master/examples/PedSpawner/Main.cpp - int modelID = pedModelIds[rand() % 250]; // Random model id - CStreaming::RequestModel(modelID, 0); // Request the model - CStreaming::LoadAllRequestedModels(false); // Whatever this does. - CPed* ped = new CCivilianPed(CPopulation::IsFemale(modelID) ? PED_TYPE_CIVFEMALE : PED_TYPE_CIVMALE, modelID); + // Make game timer, + // Toggle gravity from Maniac to Normal + float maniacGravity = 0.9; + float normalGravity = 0.008; - // New - // Idk how this one works - //ped->m_pIntelligence - - if (ped) - { - // Is this getting the offset for the coordinates? - ped->SetPosn(FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 5.0f, 3.0f))); - ped->SetOrientation(0.0f, 0.0f, 0.0f); - CWorld::Add(ped); - ped->PositionAnyPedOutOfCollision(); - ped->m_pIntelligence->m_TaskMgr.SetTask(new CTaskComplexWanderStandard(4, rand() % 8, true), 4, false); + size_t game_ms = CTimer::m_snTimeInMilliseconds; + static size_t interval = 0; + if (game_ms - interval > 10000) { + // + if (GAME_GRAVITY = normalGravity) + { + GAME_GRAVITY = maniacGravity; + interval = game_ms; + } } } +void PedTestPage::NormalGravity() +{ + float maniacGravity = 0.9; + float normalGravity = 0.008; + + size_t game_ms = CTimer::m_snTimeInMilliseconds; + static size_t interval = 0; + if (game_ms - interval > 5000) { + // + if (GAME_GRAVITY = maniacGravity) + { + GAME_GRAVITY = normalGravity; + interval = game_ms; + } + } +} + +// I couldn't get this working. +#ifdef _TEST1 +#ifdef GTASA +static void SpawnRandomCopPed() +{ + //CVehicle* cVehicle = nullptr; + CPlayerPed* player = FindPlayerPed(); + // Taken from plugin-sdk examples under PedSpawner in Main.cpp + // https://github.com/DK22Pac/plugin-sdk/blob/master/examples/PedSpawner/Main.cpp + // Cop Ped + int copRandModelID = copModelIds[rand() % 250]; // Random model id + CStreaming::RequestModel(copRandModelID, 0); // Request the model + CStreaming::LoadAllRequestedModels(false); // Whatever this does. + //CPed* ped = new CCivilianPed(CPopulation::IsFemale(modelID) ? PED_TYPE_CIVFEMALE : PED_TYPE_CIVMALE, modelID); + //CPed* ped = new CCivilianPed(CPopulation::IsFemale(modelID) ? PED_TYPE_CIVFEMALE : PED_TYPE_CIVMALE, modelID); + + + // Vehicle + //CVehicle *vehicle = new CVehicle(); + CVehicle* SpawnVehicle(unsigned int modelIndex, CVector position) + { + + } + + // This might be fun, have the cop run over the player. + CCopPed* copPed = new CCopPed(copRandModelID); + + //CVehicle* cVehicle = new CVehicle(MODEL_DODO); + + copPed->KillPedWithCar(); + CStreaming::SetModelIsDeletable(copRandModelID); + +} +#endif //GTASA + +#endif //_TEST1 static void SpawnPedMenu() { if (ImGui::Button("Spawn Ped")) { - SpawnRandomPed(); + //SpawnRandomPed(); + // Moved this into PedFunctions. + PedFunctions::SpawnRandomPed(); } + +#ifdef _TEST1 + if (ImGui::Button("Spawn Random Cop ped")) + { + SpawnRandomCopPed(); + } +#endif //_TEST1 } -#endif //GTASA +//#endif //GTASA @@ -369,6 +420,70 @@ static void MiscTestMenu() } } #endif //GTASA + + if(ImGui::Button("Is player under car?")) + { + if (PlayerFunctions::IsPedStuckUnderCar()) { + Util::SetMessage("You are being crushed!"); + } + else + { + Util::SetMessage("You are not under a car."); + } + } + + if (ImGui::Button("Add blip for current pos")) + { + CVector playerPos = player->GetPosition(); + + // This works + //bool pos = Command(playerPos.x, playerPos.y, playerPos.z); + // https://library.sannybuilder.com/#/sa/default/02A8 + // https://gtamods.com/wiki/Blip + + Command(playerPos.x, playerPos.y, playerPos.z, RADAR_SPRITE_AMMUGUN); + + + // Test, didn't work + //CSprite playerSprite = Command(playerPos.x, playerPos.y, playerPos.z, RADAR_SPRITE_AMMUGUN); + + // This doesn't seem to store the value or remove the blip. + //bool blip = Command(playerPos.x, playerPos.y, playerPos.z, RADAR_SPRITE_AMMUGUN); + //bool doesBlipExist = Command(blip); + ////if (blipPos) + //if (doesBlipExist) + //{ + // Command(blip); + // Util::SetMessage("Removed current blip."); + //} + + } + + if (ImGui::Button("Add blip for vehicle")) + { + CVehicle* pVeh = nullptr; + + + if (PlayerFunctions::IsPlayerInVehicle()) { + pVeh = player->m_pVehicle; + Command(pVeh); + Util::SetMessage("You have added a blip for your vehicle."); + } + + } + + // I'm not sure how to remove these yet. + if (ImGui::Button("Remove blip for vehicle")) + { + CVehicle* pVeh = nullptr; + + if (PlayerFunctions::IsPlayerInVehicle()) { + pVeh = player->m_pVehicle; + Command(pVeh); + Util::SetMessage("You have removed a blip for your vehicle."); + } + } + #endif //_TEST1 } @@ -439,6 +554,113 @@ static void SetRespawnMiddleOfMapMenu() } +// Use Swat rope test, this is in the reversed gta sa project, I wonder if I can use it in the plugin-sdk? +// I don't know if it'll work with the player. +static void CreateSwatRopeOnPed() +{ +#ifdef GTASA + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + + CVector playerCoords = player->GetPosition(); + + //CVector testLocation = CVector(2, 2, 2); + // Will this work? + CVector testLocation = playerCoords; + + // Add some distance to the x and y so they don't spawn right on the player. + // Z is the height, I'll leave it alone for now. + testLocation.x = testLocation.x + 2; + testLocation.y = testLocation.y + 2; + + // pedType, modelId, x, y, z + // Ped male + // Sweet + Command(PED_TYPE_CIVMALE, 270, testLocation.x, testLocation.y, testLocation.z); +#endif //GTASA +} + +// + +// Untested +/// +/// Teleport to marker test, this seems to work but doesn't put the player on the ground. +/// + +static void TeleportToMarkerTest() +{ + // Idk what this below is doing but its defined in teleport.cpp. + tRadarTrace* ms_RadarTrace = reinterpret_cast(patch::GetPointer(0x5838B0 + 2)); + CPlayerPed* player = FindPlayerPed(); + int hplayer = CPools::GetPedRef(player); + CVector playerPos = player->GetPosition(); + + //Test + CEntity* pPlayerEntity = FindPlayerEntity(-1); + + tRadarTrace targetBlip = ms_RadarTrace[LOWORD(FrontEndMenuManager.m_nTargetBlipIndex)]; + if (targetBlip.m_nRadarSprite != RADAR_SPRITE_WAYPOINT) + { + Util::SetMessage(TEXT("Teleport.TargetBlipText")); + return; + } + + // I don't know how to get the location of the current marker. + // This should place the player on the ground. + // This doesn't work. +#ifdef _TEST1 + float ground, water; + CEntity* pPlayerEntity = FindPlayerEntity(-1); + ground = CWorld::FindGroundZFor3DCoord(playerPos.x, playerPos.y, 1000, nullptr, &pPlayerEntity) + 1.0f; + + Command(playerPos.x, playerPos.y, true, &water); + playerPos.z = ground > water ? ground : water; + +#endif //_TEST1 + player->SetPosn(targetBlip.m_vecPos); + +} + +static void TeleportTestMenu() +{ + if (ImGui::Button("Teleport to marker")) + { + // I don't think this'll work. + TeleportToMarkerTest(); + } +} + +void PedTest() +{ + ImGui::Text("Find unsuspecting target ped"); + if(ImGui::Button("Test #1")) + { + //CWorld::FindUnsuspectingTargetPed(); + } + + ImGui::Text("Clear peds and everything in area"); + if (ImGui::Button("Test #2")) + { + CPlayerPed* player = FindPlayerPed(); + CWorld::ClearExcitingStuffFromArea(player->GetPosition(), 20, true); + Util::SetMessage("Killed everything in the area!"); + } + + // This didn't seem to work + ImGui::Text("Start a fire in your area"); + if (ImGui::Button("Test #3")) + { + CPlayerPed* player = FindPlayerPed(); + CEntity* playerEntity = FindPlayerEntity(-1); + + CVector playerPos = player->GetPosition(); + CWorld::SetWorldOnFire(playerPos.x, playerPos.y, playerPos.z, 20, playerEntity); + } + +} + + + /// /// Main code for PlayerTestMenu /// @@ -478,11 +700,15 @@ void PedTestPage::PlayerTestMenu() TestChangeRespawnMenu(); SetRespawnMiddleOfMapMenu(); + TeleportTestMenu(); + #endif //GTASA // I could probably set this to activate when the player goes into it and send a message saying you are in the zone. AreaCheckTestMenu(); MiscTestMenu(); + + PedTest(); #endif //TEST } \ No newline at end of file diff --git a/src/test/test_ped.h b/src/test/test_ped.h index c2c31b3..eadd8d0 100644 --- a/src/test/test_ped.h +++ b/src/test/test_ped.h @@ -10,4 +10,6 @@ public: PedTestPage(const PedTestPage&); //static void PedTestMenu(); void PlayerTestMenu(); + static void InsaneGravity(); + static void NormalGravity(); }; diff --git a/src/test/weather_test.cpp b/src/test/weather_test.cpp new file mode 100644 index 0000000..0d5bc26 --- /dev/null +++ b/src/test/weather_test.cpp @@ -0,0 +1,37 @@ +#include "pch.h" +#include "weather_test.h" +#ifdef GTASA +#include "CWeather.h" +#endif //GTASA + +//What will this do? +void EarthQuakeTest() +{ + float earthQuakeTest = 1.0f; + if (CWeather::Earthquake = earthQuakeTest) + { + + } +} + + +/// +/// Update the weather, I think this is delayed. +/// +/// The weather type to be set +void UpdateWeather(eWeatherType weatherType) +{ + CWeather::ForcedWeatherType = weatherType; +} + +/// +/// Update the weather now. +/// +/// The weather type to be set +void UpdateWeatherNow(eWeatherType weatherType) +{ + CWeather::ForcedWeatherType = weatherType; + CWeather::OldWeatherType = weatherType; + CWeather::NewWeatherType = weatherType; +} + diff --git a/src/test/weather_test.h b/src/test/weather_test.h new file mode 100644 index 0000000..9f1acb1 --- /dev/null +++ b/src/test/weather_test.h @@ -0,0 +1,5 @@ +#pragma once +class WeatherTest +{ +}; +