#include "CustomFiberThread.h" #include "Scripting.h" #include "../ScriptHook/Log.h" #include #include using namespace Scripting; // ASSEMBLY FUNCTIONS, MAYBE CAN NOT BE A CLASS FUNCTION __declspec( noinline ) u32 GTA4_GetHandleFromPed( CPool< void* >* pPool, void *Ped ) { _asm mov ecx, pPool; _asm mov eax, Ped; _asm sub eax, [ecx]; _asm cdq; _asm idiv dword ptr [ecx+12]; _asm mov edx, eax; _asm mov eax, [ecx+4]; _asm movzx eax, byte ptr [eax+edx]; _asm shl edx, 8; _asm add eax, edx; } // ASSEMBLY FUNCTIONS, MAYBE CAN NOT BE A CLASS FUNCTION RiotThread::RiotThread() { SetName( "RiotIV_050" ); } CPool< void* >* RiotThread::GetPedPoolNative() { // HACKHACK: Static address for GTAIV 1.0.6.0; DEPRECIATED!!! // return reinterpret_cast< CPool< void* >* >( *reinterpret_cast< DWORD* >( Game::GetBase() + 0x18A72BC ) ); return reinterpret_cast< CPool< void* >* >( *reinterpret_cast< DWORD* >( m_ulPedPoolBase ) ); } u32 RiotThread::GetPedCount() { if( GetPedPoolNative() == NULL ) return 0; return GetPedPoolNative()->Count(); } b8 RiotThread::GetPedByIndex( int idx, Ped *Out ) { if( !Out ) return false; Out->Set( 0 ); if( GetPedCount() == 0 ) return false; void *CurrentPedIdx = GetPedPoolNative()->at( idx ); if( CurrentPedIdx == NULL ) return false; Out->Set( GTA4_GetHandleFromPed( GetPedPoolNative(), CurrentPedIdx ) ); return ( Out->IsValid() && DoesCharExist( *Out ) ); } Scripting::Vector3 RiotThread::GetPedVector( Scripting::Ped *In ) { Vector3 Ret(0,0,0); Scripting::GetCharCoordinates( *In, &Ret.X, &Ret.Y, &Ret.Z ); return Ret; } Player RiotThread::GetPlayer() { Player playerIndex = ConvertIntToPlayerIndex(GetPlayerId()); return playerIndex; } Scripting::Ped RiotThread::GetPlayerPed() { Ped ped; GetPlayerChar( GetPlayer(), &ped ); return ped; } Scripting::eWeapon RiotThread::GetRandomWeapon() { srand( GetTickCount() ); return static_cast< eWeapon >( m_UsableWeaponry[ rand() % m_UsableWeaponry.size() ] ); } b8 RiotThread::IsPedPolice( Scripting::Ped ped ) { eModel CurrentModel; Scripting::GetCharModel( ped, &CurrentModel ); return ( ( CurrentModel == MODEL_M_Y_COP ) || ( CurrentModel == MODEL_M_Y_COP_TRAFFIC ) || ( CurrentModel == MODEL_M_M_FATCOP_01 ) || ( CurrentModel == MODEL_CS_MITCHCOP ) || ( CurrentModel == MODEL_M_Y_SWAT ) || ( CurrentModel == MODEL_M_M_FBI ) || ( CurrentModel == MODEL_M_Y_STROOPER ) ); } b8 RiotThread::ShouldRiot( Scripting::Ped ped ) { if( m_DontRiotHashes.empty() ) { return true; } for( size_t i = 0; i < m_DontRiotHashes.size(); i++ ) { if( IsCharModel( ped, static_cast< Scripting::eModel >( m_DontRiotHashes[ i ] ) ) ) { return false; } } return true; } b8 RiotThread::IsPedAllowedToRiot( Scripting::Ped ped ) { if( m_RiotHashes.empty() ) return true; for( size_t i = 0; i < m_RiotHashes.size(); i++ ) { if( IsCharModel( ped, static_cast< Scripting::eModel >( m_RiotHashes[ i ] ) ) ) { return true; } } return false; } b8 RiotThread::CausePedToRiot( Scripting::Ped LocalPed, Scripting::Ped RiotPed ) { // Check if ped exists if( DoesCharExist( RiotPed ) == false ) { return false; } // Check the model for status if( ShouldRiot( RiotPed ) == false || IsPedAllowedToRiot( RiotPed ) == false ) { if( IsPedAMissionPed( RiotPed ) ) { MarkCharAsNoLongerNeeded( &RiotPed ); } return false; } // If not "visible", delete them, not needed if( IsCharVisible( RiotPed ) == false ) { if( IsPedAMissionPed( RiotPed ) ) { MarkCharAsNoLongerNeeded( &RiotPed ); DeleteChar( &RiotPed ); } return false; } // If dead, fatally injured // if mission ped, unmark, stop if( IsCharDead( RiotPed ) || IsCharFatallyInjured( RiotPed ) ) { if( IsPedAMissionPed( RiotPed ) ) { MarkCharAsNoLongerNeeded( &RiotPed ); } return false; } // If cops rioting is disabled and ped is police, stop if( m_bCopsGoCrazy == false && IsPedPolice( RiotPed ) ) { if( IsPedAMissionPed( RiotPed ) ) { MarkCharAsNoLongerNeeded( &RiotPed ); } return false; } // If usable weaponry is available if( m_UsableWeaponry.size() > 0 ) { //if NOT police (already have weapons) if( IsPedPolice( RiotPed ) == false ) { //if have a gun already, and not police, stop if( Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_MELEE ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_HANDGUN ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_HEAVY ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_RIFLE ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_SHOTGUN ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_SMG ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_SNIPER ) || Scripting::IsCharArmed( RiotPed, WEAPON_SLOT_THROWN ) ) { return false; } } } // Range checking to avoid crashes Scripting::Vector3 LocalVec = GetPedVector( &LocalPed ); Scripting::Vector3 PedVec = GetPedVector( &RiotPed ); if( PedVec.Distance( &LocalVec ) > m_fMaximumRange ) { // HACKHACK: If outside of maximum range mark as no longer needed... if( IsPedAMissionPed( RiotPed ) ) { MarkCharAsNoLongerNeeded( &RiotPed ); } return false; } if( IsPedAMissionPed( RiotPed ) == false ) { // Setup violent tendencies SetCharAsMissionChar( RiotPed ); SetCharAsEnemy( RiotPed, m_bTargetPlayer ); SetPedDiesWhenInjured( RiotPed, true ); AllowTargetWhenInjured( RiotPed, true ); SetCharWillMoveWhenInjured( RiotPed, true ); SetCharWillDoDrivebys( RiotPed, true ); SetCharWillUseCarsInCombat( RiotPed, m_bPedsUseCars ); SetPedWontAttackPlayerWithoutWantedLevel( RiotPed, 0 ); SetSenseRange( RiotPed, m_fMaximumRange ); SetCharAccuracy( RiotPed, 100 ); if( IsPedPolice( RiotPed ) == false ) { SetCharWantedByPolice( RiotPed, m_bPedsWanted ); SetCharRelationshipGroup( RiotPed, 8 ); // If weaponry available, give random weapon if( m_UsableWeaponry.size() > 0 ) { eWeapon RandomWeapon = GetRandomWeapon(); GiveWeaponToChar( RiotPed, RandomWeapon, ( RandomWeapon > 3 ) ? 9999 : 0, 0 ); SetCurrentCharWeapon( RiotPed, RandomWeapon, true ); BlockPedWeaponSwitching( RiotPed, true ); } else { // Melee if no weapons are set RemoveAllCharWeapons( RiotPed ); } } // Set attacking task TaskCombatHatedTargetsAroundChar( RiotPed, m_fMaximumRange ); SetCharKeepTask( RiotPed, true ); } return true; } void RiotThread::SpawnNewRioter( Ped LocalPed, Vector3 SpawnVector ) { Scripting::PrintStringWithLiteralStringNow( "STRING", "Spawning new riot ped", 3000, true ); srand( GetTickCount() ); eModel ModelSpawn = static_cast< eModel >( m_SpawnHashes[ rand() % m_SpawnHashes.size() ] ); RequestModel( ModelSpawn ); while( HasModelLoaded( ModelSpawn ) == false ) { Wait(10); } Ped OutPed; CreateChar( 2, ModelSpawn, SpawnVector.X, SpawnVector.Y, SpawnVector.Z, &OutPed, true ); if( OutPed.IsValid() ) { while( DoesCharExist( OutPed ) == false ) { Wait(10); } while( IsCharVisible( OutPed ) == false ) { Wait(10); } SetCharHealth( OutPed, 200 ); MarkCharAsNoLongerNeeded( &OutPed ); } } void RiotThread::SetupRelationships() { SetRelationship( 5, 8, 8 ); // Rioters hate themselves SetRelationship( 5, 8, 3 ); // Rioters hate police SetPlayerCanBeHassledByGangs( GetPlayer(), m_bTargetPlayer ); if( m_bTargetPlayer ) { SetRelationship( 5, 8, 0 ); // Rioters hate player (you) SetRelationship( 5, 0, 8 ); // Player hate rioters if( m_bCopsGoCrazy ) { SetRelationship( 5, 0, 3 ); //Cops hate player (you) } } else { SetRelationship( 1, 8, 0 ); // Rioters ignore player (you) SetRelationship( 1, 0, 8 ); // Player ignore rioters } if( m_bCopsGoCrazy ) { SetRelationship( 5, 3, 8 ); // Cops hate rioters } } std::vector< int > RiotThread::StringToIntList( const char *str ) { std::vector< int > ReturnVector; if( str == NULL ) { ReturnVector.clear(); return ReturnVector; } // char *pch = strtok( const_cast< char* >( str ), "," ); if( pch == NULL ) { ReturnVector.push_back( atoi( str ) ); } else { while( pch ) { ReturnVector.push_back( atoi( pch ) ); pch = strtok( 0, "," ); } } return ReturnVector; } void RiotThread::SetupSettingsFile() { Log::Debug( "Loading Settings..." ); m_pConfigService = ScriptHookManager::RequestService< IConfigService >( "Config" ); if( m_pConfigService ) { IConfig* Configuration = m_pConfigService->Create( IConfigService::ConfigTypeXml ); if( Configuration == NULL ) return; Configuration->Set( "RiotIV", "Enabled", "1" ); Configuration->Set( "RiotIV", "TargetPlayer", "0" ); Configuration->Set( "RiotIV", "CrazyCops", "1" ); Configuration->Set( "RiotIV", "PedsUseCars", "1" ); Configuration->Set( "RiotIV", "PedsWanted", "1" ); Configuration->Set( "RiotIV", "MadDrivers", "1" ); Configuration->Set( "RiotIV", "EmergencyServicesDisabled", "1" ); Configuration->Set( "RiotIV", "PedMultiplierEnforce", "NONE" ); Configuration->Set( "RiotIV", "UsableWeaponry", "4,5,7,9,10,11,12,13,14,15,16,17,18" ); Configuration->Set( "RiotIV", "DontRiotHashes", "" ); Configuration->Set( "RiotIV", "SpawnHashes", "1794146792" ); Configuration->Set( "RiotIV", "RiotHashes", "ANY" ); Configuration->Set( "RiotIV", "MaximumRange", "100.0" ); char *pszModulePath = GetModulePath(); if( pszModulePath == 0 || strlen( pszModulePath ) == 0 ) return; Log::Debug( "Module Path [%s]", pszModulePath ); char pszConfigPath[ MAX_PATH ] = { 0 }; strcat_s( pszConfigPath, MAX_PATH, GetModulePath() ); strcat_s( pszConfigPath, MAX_PATH, "Riot.xml" ); Log::Debug( "Loading configuration from [%s]", pszConfigPath ); WIN32_FIND_DATAA wfd; if ( FindFirstFileA( pszConfigPath, &wfd ) != INVALID_HANDLE_VALUE ) { Configuration->Load( pszConfigPath ); // HACKHACK: Save after we load to ensure any new values are inserted into the file for future loading Configuration->Save( pszConfigPath ); } else { Configuration->Save( pszConfigPath ); } m_bEnabled = ( Configuration->GetInteger( "RiotIV", "Enabled", 1 ) == 1 ); m_bTargetPlayer = ( Configuration->GetInteger( "RiotIV", "TargetPlayer", 0 ) == 1 ); m_bCopsGoCrazy = ( Configuration->GetInteger( "RiotIV", "CrazyCops", 0 ) == 1 ); m_bPedsUseCars = ( Configuration->GetInteger( "RiotIV", "PedsUseCars", 1 ) == 1 ); m_bPedsWanted = ( Configuration->GetInteger( "RiotIV", "PedsWanted", 0 ) == 1 ); m_bMadDrivers = ( Configuration->GetInteger( "RiotIV", "MadDrivers", 0 ) == 1 ); m_bEmergencyServicesDisabled = ( Configuration->GetInteger( "RiotIV", "EmergencyServicesDisabled", 0 ) == 1 ); m_fMaximumRange = Configuration->GetFloat( "RiotIV", "MaximumRange", 100.f ); CONST CHAR* PedMultiEnforce = Configuration->GetString( "RiotIV", "PedMultiplierEnforce" ); CONST CHAR* UsableWeapons = Configuration->GetString( "RiotIV", "UsableWeaponry" ); CONST CHAR* DontRiotHashes = Configuration->GetString( "RiotIV", "DontRiotHashes" ); CONST CHAR* RiotHashes = Configuration->GetString( "RiotIV", "RiotHashes" ); CONST CHAR* SpawnHashes = Configuration->GetString( "RiotIV", "SpawnHashes" ); m_UsableWeaponry = StringToIntList( UsableWeapons ); m_DontRiotHashes = StringToIntList( DontRiotHashes ); m_SpawnHashes = StringToIntList( SpawnHashes ); if( _stricmp( PedMultiEnforce, "NONE" ) == 0 ) { m_bForcePedMultiplier = false; } else { m_bForcePedMultiplier = true; m_fPedMultiplier = static_cast< f32 >( atof( PedMultiEnforce ) ); } if( _stricmp( RiotHashes, "ANY" ) == 0 ) { m_RiotHashes.clear(); } else { m_RiotHashes = StringToIntList( RiotHashes ); } Configuration->Release(); } else { Log::Debug( "Unable to load configuration service.." ); } } char* RiotThread::GetModulePath() { static char pszPath[ MAX_PATH ] = { 0 }; if( strlen( pszPath ) > 0 ) return pszPath; GetModuleFileNameA( m_hModule, pszPath, sizeof( pszPath ) ); u32 i = strlen( pszPath ); while( i > 0 && pszPath[i] != '\\' ) { i--; } pszPath[i] = 0; strcat_s( pszPath, MAX_PATH, "\\" ); return pszPath; } void RiotThread::UpdateCode() { HMODULE hMainModule = GetModuleHandleW( NULL ); Log::Debug( "Finding signiture..[0x%X][0x%X]", hMainModule, Game::GetBase() ); m_ulPedPoolBase = Code::FindAddress::DetectPattern( reinterpret_cast< unsigned long >( hMainModule ), 0xFFFFFF, ( BYTE* )"\x55\x8B\xEC\x83\xE4\xF0\x8B\x15\x00\x00\x00\x00\x81\xEC\xEC\x00\x00\x00", ( CHAR* )"xxxxxxxx????xxxxxx" ); if( m_ulPedPoolBase == NULL ) { Log::Fatal( "PedPoolBase not found...critical error" ); ExitProcess(0); } else { Log::Debug( "PedPoolBase 001 [0x%X]", m_ulPedPoolBase ); m_ulPedPoolBase += 8; Log::Debug( "PedPoolBase 002 [0x%X]", m_ulPedPoolBase ); m_ulPedPoolBase = *reinterpret_cast< unsigned long* >( m_ulPedPoolBase ); Log::Debug( "PedPoolBase FIN [0x%X]", m_ulPedPoolBase ); Log::Debug( "Address - Base = [0x%X]", m_ulPedPoolBase - reinterpret_cast< unsigned long >( hMainModule ) ); } } void RiotThread::RunScript() { SetupSettingsFile(); CreateKeyboard(); CreateMenu(); while( IsThreadAlive() ) { if( NetworkIsSessionStarted() == false ) { Ped LocalPed = GetPlayerPed(); if( LocalPed.IsValid() == false ) continue; Vector3 LocalVector = GetPedVector( &LocalPed ); if( m_bSpawnRandomPedNextFrame && m_SpawnHashes.size() ) { SpawnNewRioter( LocalPed, Vector3( LocalVector.X + 2.f, LocalVector.Y, LocalVector.Z ) ); m_bSpawnRandomPedNextFrame = false; } if( m_bForcePedMultiplier ) { SetPedDensityMultiplier( m_fPedMultiplier ); } SwitchMadDrivers( m_bMadDrivers ); AllowEmergencyServices( !m_bEmergencyServicesDisabled ); SetPoliceIgnorePlayer( GetPlayer(), m_bEmergencyServicesDisabled ); if( m_bEmergencyServicesDisabled ) { SetCharWantedByPolice( LocalPed, false ); ClearWantedLevel( GetPlayer() ); ClearAreaOfCops( LocalVector.X, LocalVector.Y, LocalVector.Z, m_fMaximumRange ); } if( m_bEnabled ) { AllowGangRelationshipsToBeChangedByNextCommand( true ); SetupRelationships(); for( u32 i = 0; i < GetPedCount(); i++ ) { Ped Index; Index.Set( 0 ); if( GetPedByIndex( i, &Index ) ) { if( Index.IsNull() ) continue; if( Index.Get() == LocalPed.Get() ) continue; if( CausePedToRiot( LocalPed, Index ) == false ) continue; } } } } Wait( 10 ); } } void RiotThread::OnStart() { m_pMenu = NULL; } void RiotThread::OnKill() { IKeyboardHookService *kbhService = ScriptHookManager::RequestService( "KeyboardHook" ); kbhService->RemoveHandler( this ); if( m_pMenu ) { m_pMenu->Release(); m_pMenu = NULL; } ScriptThread::OnKill(); } void RiotThread::CreateKeyboard() { IKeyboardHookService *kbhService = ScriptHookManager::RequestService( "KeyboardHook" ); kbhService->AddHandler( this ); } void RiotThread::CreateMenu() { IMenuService *menuService = ScriptHookManager::RequestService< IMenuService >( "Menu" ); m_pMenu = menuService->CreateMenu(); m_pMenu->SetTitle( "Riot mode" ); AddMenuItemCustom( 0, m_bEnabled ? "Disable Riot Mode" : "Enable Riot Mode" ); AddMenuItemCustom( 1, m_bTargetPlayer ? "Disable peds targetting player" : "Enable peds targetting player" ); AddMenuItemCustom( 2, m_bCopsGoCrazy ? "Disable cops rioting" : "Enable cops rioting" ); AddMenuItemCustom( 3, m_bPedsUseCars ? "Disable peds use cars in combat" : "Enable peds use cars in combat" ); AddMenuItemCustom( 4, m_bPedsWanted ? "Disable peds wanted" : "Enable peds wanted" ); AddMenuItemCustom( 5, m_bMadDrivers ? "Disable mad drivers" : "Enable mad drives" ); AddMenuItemCustom( 6, m_bEmergencyServicesDisabled ? "Enable emergancy services" : "Disable emergancy services" ); m_pMenu->SetEventHandler( this ); } void RiotThread::AddMenuItemCustom( int idx, char *pszFormat, ... ) { char FormattedBuffer[ 1024 ] = { 0 }; va_list va_alist; va_start( va_alist, pszFormat ); _vsnprintf( FormattedBuffer + strlen( FormattedBuffer ), sizeof( FormattedBuffer ) - strlen( FormattedBuffer ), pszFormat, va_alist ); va_end( va_alist ); m_pMenu->AddItem( idx, FormattedBuffer ); } void RiotThread::SetMenuItemCustom( int idx, char *pszFormat, ... ) { char FormattedBuffer[ 1024 ] = { 0 }; va_list va_alist; va_start( va_alist, pszFormat ); _vsnprintf( FormattedBuffer + strlen( FormattedBuffer ), sizeof( FormattedBuffer ) - strlen( FormattedBuffer ), pszFormat, va_alist ); va_end( va_alist ); m_pMenu->SetItem( idx, FormattedBuffer ); } void RiotThread::OnMenuSelectionChanged( IMenu *menu, u32 id ) { // None? } void RiotThread::OnMenuSelected( IMenu *menu, u32 id ) { switch( id ) { case 0: { m_bEnabled = !m_bEnabled; SetMenuItemCustom( 0, m_bEnabled ? "Disable Riot Mode" : "Enable Riot Mode" ); break; } case 1: { m_bTargetPlayer = !m_bTargetPlayer; SetMenuItemCustom( 1, m_bTargetPlayer ? "Disable peds targetting player" : "Enable peds targetting player" ); break; } case 2: { m_bCopsGoCrazy = !m_bCopsGoCrazy; SetMenuItemCustom( 2, m_bCopsGoCrazy ? "Disable cops rioting" : "Enable cops rioting" ); break; } case 3: { m_bPedsUseCars = !m_bPedsUseCars; SetMenuItemCustom( 3, m_bPedsUseCars ? "Disable peds use cars in combat" : "Enable peds use cars in combat" ); break; } case 4: { m_bPedsWanted = !m_bPedsWanted; SetMenuItemCustom( 4, m_bPedsWanted ? "Disable peds wanted" : "Enable peds wanted" ); break; } case 5: { m_bMadDrivers = !m_bMadDrivers; SetMenuItemCustom( 5, m_bMadDrivers ? "Disable mad drivers" : "Enable mad drives" ); break; } case 6: { m_bEmergencyServicesDisabled = !m_bEmergencyServicesDisabled; SetMenuItemCustom( 6, m_bEmergencyServicesDisabled ? "Enable emergancy services" : "Disable emergancy services" ); break; } } } void RiotThread::OnKeyboardHookEvent( const IKeyboardHookHandler::KeyEventArgs &args ) { if( args.VirtualKey == VK_INSERT && !args.WasKeyDownBefore ) { if( m_pMenu ) { m_pMenu->Show(); } } if( args.VirtualKey == VK_F3 && !args.WasKeyDownBefore ) { m_bSpawnRandomPedNextFrame = true; } }