Add ped functions, add a few more checks

for player functions, update vehicle functions.
Add more test events. Add misc functions, and misc test page.
Add garage test functions, update test_ped, add weather test.
This commit is contained in:
kelson8 2024-07-01 00:50:43 -04:00
parent 0a05a87dd4
commit 02c166f4a7
Signed by: kelson8
GPG Key ID: 3D738D9DD7239E13
16 changed files with 1191 additions and 91 deletions

View File

@ -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
}

View File

@ -0,0 +1,226 @@
#include "pch.h"
#include "misc_functions.h"
//////////////////////////
// Misc options
//////////////////////////
// Untested
/// <summary>
/// Opens the save menu, only works if the player is not dead.
/// </summary>
void MiscFunctions::OpenSaveMenu()
{
CPlayerPed* player = FindPlayerPed();
if (!player->IsAlive())
{
Command<Commands::ACTIVATE_SAVE_MENU>();
}
}
/// <summary>
/// Toggle the player talking or not.
/// </summary>
void MiscFunctions::TogglePlayerSpeech(bool toggle)
{
CPlayerPed* player = FindPlayerPed();
int hplayer = CPools::GetPedRef(player);
if (toggle)
{
Command<Commands::ENABLE_CHAR_SPEECH>(hplayer);
}
else
{
Command<Commands::DISABLE_CHAR_SPEECH>(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<Commands::GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP>(player, "tshirt2horiz", "tshirt2", 0);
Command<Commands::GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP>(player, textureName, modelName, bodyPart);
}
/// <summary>
/// Change the players current outfit, this isn't tested yet.
/// </summary>
void ChangePlayerClothes()
{
CPed* player = FindPlayerPed();
// https://wiki.multitheftauto.com/wiki/CJ_Clothes
// player, textureName, modelName, bodyPart
// Sun glasses
//Command<Commands::GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP>(player, "glasses01dark", "glasses01", 15);
ChangeClothes(player, "glasses01dark", "glasses01", CLOTHES_MODEL_GLASSES);
// White striped shirt.
//Command<Commands::GIVE_PLAYER_CLOTHES_OUTSIDE_SHOP>(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);
}
/// <summary>
/// // Change the current day of the week, from 1-7. Untested.
/// </summary>
/// <param name="dayToSet">Date to set the game time to.</param>
void ChangeCurrentDay(int dayToSet)
{
patch::Set<byte>(0xB7014E, dayToSet, true);
}
/// <summary>
/// Get the current day of the week, from 1-7. Untested.
/// </summary>
void GetCurrentDay()
{
patch::Get<byte>(0xB7014E);
}
//////////////////
// End untested functions
//////////////////
//////////////////////////
// Blip options
//////////////////////////
void MiscFunctions::HideAllBlips(bool toggle)
{
if (toggle)
{
Command<Commands::HIDE_ALL_FRONTEND_BLIPS>(true);
}
else
{
Command<Commands::HIDE_ALL_FRONTEND_BLIPS>(false);
}
// Will it work like this also?
//Command<Commands::HIDE_ALL_FRONTEND_BLIPS>(toggle);
}
//////////////////////////
//
//////////////////////////
//////////////////////////
// Garage functions
// These are untested but they should work.
//////////////////////////
bool MiscFunctions::IsGarageOpen(int garageId)
{
if(Command<Commands::IS_GARAGE_OPEN>(garageId))
{
return true;
}
else
{
return false;
}
}
bool MiscFunctions::IsGarageClosed(int garageId)
{
if (Command<Commands::IS_GARAGE_CLOSED>(garageId))
{
return true;
}
else
{
return false;
}
}
void MiscFunctions::OpenGarage(int garageId)
{
Command<Commands::OPEN_GARAGE>(garageId);
}
void MiscFunctions::CloseGarage(int garageId)
{
Command<Commands::CLOSE_GARAGE>(garageId);
}
void MiscFunctions::ActivateGarage(int garageId)
{
Command<Commands::ACTIVATE_GARAGE>(garageId);
//Util::SetMessage("You have enabled the garage with id " + garageId);
}
void MiscFunctions::DeactivateGarage(int garageId)
{
Command<Commands::DEACTIVATE_GARAGE>(garageId);
//Util::SetMessage("You have disabled the garage with id " + garageId);
}
void MiscFunctions::SetGarageType(int garageId, int garageType)
{
Command<Commands::CHANGE_GARAGE_TYPE>(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<Commands::SET_FREE_RESPRAYS>(garageId, true);
Util::SetMessage("Resprays are now free at this Pay N Spray!");
// Resprays are now free at this Pay N Spray!
}
else
{
Command<Commands::SET_FREE_RESPRAYS>(garageId, false);
Util::SetMessage("Resprays are no longer free at this Pay N Spray!");
// Resprays are no longer free at this Pay N Spray!
}
}
//////////////////////////
//
//////////////////////////

View File

@ -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);
};

View File

@ -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<Commands::ADD_BLIP_FOR_CHAR>(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<Commands::ADD_EXPLOSION>(pedPos.x, pedPos.y, pedPos.z, EXPLOSION_CAR);
// Command<Commands::ADD_ONE_OFF_SOUND>(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

View File

@ -0,0 +1,10 @@
#pragma once
class PedFunctions
{
public:
// List of the ped model ids
//int pedModelIds[];
static void SpawnRandomPed();
};

View File

@ -5,10 +5,10 @@
#include "CExplosion.h"
/// <summary>
/// Mostly helper functions for the player.
/// </summary>
///
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
//////////////////////////
/// <summary>
/// Sets the never wanted value, incomplete
/// Sets the never wanted value, untested
/// </summary>
/// <param name="toggle">If never wanted is on</param>
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<bool>(0x969171, 1, true);
}
else
{
// Disable never wanted
patch::Set<bool>(0x969171, 1, true);
}
}
/// <summary>
/// Sets the player as invincible, incomplete
/// Sets the player as invincible, untested
/// </summary>
/// <param name="toggle">If the player is invincible.</param>
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<bool>(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<bool>(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;
}
}
/// <summary>
/// Sets the infinte ammo cheat, incomplete.
/// Sets the infinte ammo cheat, untested.
/// </summary>
/// <param name="toggle">If infinite ammo is active.</param>
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<bool>(0x969178, 1, true);
}
else
{
// Disable infinite ammo
patch::Set<bool>(0x969178, 0, true);
}
}
// This should work in here, untested
//////////////////////////
//
//////////////////////////
/// <summary>
/// Spawn a bomb on the player with sound, like a grenade or satchel charge.
@ -99,18 +141,12 @@ void PlayerFunctions::SpawnBombOnPlayer()
Command<Commands::ADD_EXPLOSION>(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<Commands::ADD_ONE_OFF_SOUND>(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<Commands::IS_CHAR_IN_ANY_BOAT>(hplayer)) {
return true;
}
else
{
return false;
}
}
bool IsPlayerInHeli()
{
CPlayerPed* player = FindPlayerPed();
int hplayer = CPools::GetPedRef(player);
if (Command<Commands::IS_CHAR_IN_ANY_HELI>(hplayer)) {
return true;
}
else
{
return false;
}
}
bool IsPlayerInPlane()
{
CPlayerPed* player = FindPlayerPed();
int hplayer = CPools::GetPedRef(player);
if (Command<Commands::IS_CHAR_IN_ANY_PLANE>(hplayer)) {
return true;
}
else
{
return false;
}
}
/// <summary>
/// Check if player is in a train
/// </summary>
@ -164,6 +248,11 @@ bool PlayerFunctions::IsPlayerInTrain()
}
}
/// <summary>
/// Check if the player is in a vehicle
/// </summary>
/// <returns>If the player is in a vehicle.</returns>
bool PlayerFunctions::IsPlayerInVehicle()
{
CPlayerPed* player = FindPlayerPed();
@ -178,3 +267,69 @@ bool PlayerFunctions::IsPlayerInVehicle()
}
}
//////////////////////////
//
//////////////////////////
/// <summary>
/// Check if the player is stuck under a car
/// </summary>
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<Commands::IS_CHAR_STUCK_UNDER_CAR>(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
/// <summary>
/// Play a sound on the player at their current coordinates.
/// </summary>
/// <param name="audioId">The audio id to play</param>
void PlayerFunctions::AddSoundOnPlayer(int audioId)
{
CPlayerPed* player = FindPlayerPed();
CVector playerPos = player->GetPosition();
//Command<Commands::ADD_ONE_OFF_SOUND>(playerPos.x, playerPos.y, playerPos.z, AudioIds::EXPLOSION_SOUND);
// Will this work?
Command<Commands::ADD_ONE_OFF_SOUND>(playerPos.x, playerPos.y, playerPos.z, audioId);
}
// This is untested.
/// <summary>
/// Play a sound at the specifed coordinates, takes an x,y,z and an audio id.
/// </summary>
/// <param name="audioId">The id of the sound to play</param>
void AddSoundAtCoords(float posX, float posY, float posZ, int audioId)
{
Command<Commands::ADD_ONE_OFF_SOUND>(posX, posY, posZ, audioId);
}
//////////////////////////
//
//////////////////////////

View File

@ -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);
};

View File

@ -33,35 +33,35 @@ void VehicleFunctions::PlayerInCarMsg()
}
}
/// <summary>
/// Check if the players current vehicle is in the water
/// </summary>
/// <returns>If the current vehicle is in water.</returns>
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<Commands::IS_CAR_IN_WATER>(hVeh);
if (PlayerFunctions::IsPlayerInVehicle())
{
CVehicle* pVeh = player->m_pVehicle;
// Will this work?
int hVeh = CPools::GetVehicleRef(pVeh);
bool bIsCarInWater = Command<Commands::IS_CAR_IN_WATER>(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
}

View File

@ -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;
}

11
src/test/misc/misc_test.h Normal file
View File

@ -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();
};

145
src/test/test_garage.cpp Normal file
View File

@ -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();
}

9
src/test/test_garage.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
class GarageTestPage
{
public:
GarageTestPage();
void GarageTestMenu();
static void GarageMenu();
};

View File

@ -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<std::string> 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<Commands::ADD_ONE_OFF_SOUND>(playerPos.x, playerPos.y, playerPos.z, 1159);
Command<Commands::ADD_ONE_OFF_SOUND>(playerPos.x, playerPos.y, playerPos.z, AudioIds::EXPLOSION_SOUND);
//
// Working
//Command<Commands::ADD_ONE_OFF_SOUND>(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<Commands::ADD_SPRITE_BLIP_FOR_COORD>(playerPos.x, playerPos.y, playerPos.z);
// https://library.sannybuilder.com/#/sa/default/02A8
// https://gtamods.com/wiki/Blip
Command<Commands::ADD_SPRITE_BLIP_FOR_COORD>(playerPos.x, playerPos.y, playerPos.z, RADAR_SPRITE_AMMUGUN);
// Test, didn't work
//CSprite playerSprite = Command<Commands::ADD_SPRITE_BLIP_FOR_COORD>(playerPos.x, playerPos.y, playerPos.z, RADAR_SPRITE_AMMUGUN);
// This doesn't seem to store the value or remove the blip.
//bool blip = Command<Commands::ADD_SPRITE_BLIP_FOR_COORD>(playerPos.x, playerPos.y, playerPos.z, RADAR_SPRITE_AMMUGUN);
//bool doesBlipExist = Command<Commands::DOES_BLIP_EXIST>(blip);
////if (blipPos)
//if (doesBlipExist)
//{
// Command<Commands::REMOVE_BLIP>(blip);
// Util::SetMessage("Removed current blip.");
//}
}
if (ImGui::Button("Add blip for vehicle"))
{
CVehicle* pVeh = nullptr;
if (PlayerFunctions::IsPlayerInVehicle()) {
pVeh = player->m_pVehicle;
Command<Commands::ADD_BLIP_FOR_CAR>(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<Commands::REMOVE_BLIP>(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<Commands::CREATE_SWAT_ROPE>(PED_TYPE_CIVMALE, 270, testLocation.x, testLocation.y, testLocation.z);
#endif //GTASA
}
//
// Untested
/// <summary>
/// Teleport to marker test, this seems to work but doesn't put the player on the ground.
/// </summary>
static void TeleportToMarkerTest()
{
// Idk what this below is doing but its defined in teleport.cpp.
tRadarTrace* ms_RadarTrace = reinterpret_cast<tRadarTrace*>(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<Commands::GET_WATER_HEIGHT_AT_COORDS>(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);
}
}
/// <summary>
/// Main code for PlayerTestMenu
/// </summary>
@ -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
}

View File

@ -10,4 +10,6 @@ public:
PedTestPage(const PedTestPage&);
//static void PedTestMenu();
void PlayerTestMenu();
static void InsaneGravity();
static void NormalGravity();
};

37
src/test/weather_test.cpp Normal file
View File

@ -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)
{
}
}
/// <summary>
/// Update the weather, I think this is delayed.
/// </summary>
/// <param name="weatherType">The weather type to be set</param>
void UpdateWeather(eWeatherType weatherType)
{
CWeather::ForcedWeatherType = weatherType;
}
/// <summary>
/// Update the weather now.
/// </summary>
/// <param name="weatherType">The weather type to be set</param>
void UpdateWeatherNow(eWeatherType weatherType)
{
CWeather::ForcedWeatherType = weatherType;
CWeather::OldWeatherType = weatherType;
CWeather::NewWeatherType = weatherType;
}

5
src/test/weather_test.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
class WeatherTest
{
};