#include "CustomFiberThread.h"
#include "Scripting.h"
#include "../ScriptHook/Log.h"
#include <windows.h>
#include <stdio.h>
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( "RiotModeNative100" );
}
CPool< void* >* RiotThread::GetPedPoolNative()
{
return reinterpret_cast< CPool< void* >* >( *reinterpret_cast< DWORD* >( Game::GetBase() + 0x18A72BC ) );
}
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();
}
b8 RiotThread::GetClosestPedFromPed( Scripting::Ped *Searcher, Scripting::Ped *Seek )
{
if( Searcher == NULL || Seek == NULL )
return false;
if( GetPedCount() == 0 )
return false;
Vector3 SearcherVector = GetPedVector( Searcher );
float LowestDistance = -1.f;
for( u32 i = 0; i < GetPedCount(); i++ )
{
Ped Search;
if( GetPedByIndex( i, &Search ) == false )
continue;
Vector3 SeekVector = GetPedVector( Seek );
if( LowestDistance == -1.f )
{
LowestDistance = SeekVector.Distance( &SearcherVector );
continue;
}
else
{
float Dist = SeekVector.Distance( &SearcherVector );
if( Dist < LowestDistance )
{
Seek->Set( Search.Get() );
LowestDistance = Dist;
continue;
}
}
}
if( Seek->IsValid() )
{
return DoesCharExist( *Seek );
}
return false;
}
Scripting::Vector3 RiotThread::GetPedVector( Scripting::Ped *In )
{
float x, y, z;
Scripting::GetCharCoordinates( *In, &x, &y, &z );
return Vector3( x, y, z );
}
Player RiotThread::GetPlayer()
{
Player playerIndex = ConvertIntToPlayerIndex(GetPlayerId());
return playerIndex;
}
Scripting::Ped RiotThread::GetPlayerPed()
{
Ped ped;
GetPlayerChar( GetPlayer(), &ped );
return ped;
}
Scripting::eWeapon RiotThread::GetRandomWeapon( int RandMax )
{
// Include melee as the last three, so if melee weapons is enabled, randmax += 3;
u32 WeaponsAlright[ 16 ] = { 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2, 3 };
srand( GetTickCount() );
//RandMax == 13, Firing weapons only
//RandMax == 16, Melee and firing weapons included
return static_cast< Scripting::eWeapon >( WeaponsAlright[ rand() % RandMax ] );
}
u32 RiotThread::GetPedGroup( Scripting::Ped *In )
{
if( In == NULL ) return 0;
u32 GroupIdx;
Scripting::GetPedGroupIndex( *In, &GroupIdx );
return GroupIdx;
}
f32 RiotThread::RandomFloat()
{
srand( GetTickCount() % 1000 );
float Scale = RAND_MAX + 1;
float BaseF = rand() / Scale;
float FineF = rand() / Scale;
return BaseF + FineF / Scale;
}
void RiotThread::SetupRelationships()
{
// Make everyone just hate everyone, lol
SetRelationship( 5, 8, 8 ); // Rioters hate themselves
if( m_bTargetPlayer )
{
SetRelationship( 5, 8, 0 ); // Rioters hate player (you)
SetPlayerCanBeHassledByGangs( this->GetPlayer(), true );
SetRelationship( 5, 0, 8 ); // Player hate rioters
}
else
{
SetRelationship( 1, 8, 0 ); // Rioters ignore player (you)
}
SetRelationship( 5, 8, 3 ); // Rioters hate cops
SetRelationship( 5, 3, 8 ); // Cops hate rioters
SetRelationship( 5, 8, 2 ); // Rioters hate CIVFEMALE
SetRelationship( 5, 8, 1 ); // Rioters hate CIVMALE
SetRelationship( 5, 2, 8 ); // CIVFEMALE hate rioters
SetRelationship( 5, 1, 8 ); // CIVMALE hate rioters
}
/*
LOAD_CHAR_DECISION_MAKER(3, ZcharDec)
LOAD_COMBAT_DECISION_MAKER(3, ZcombatDec)
SET_DECISION_MAKER_ATTRIBUTE_CAUTION(ZcharDec.a, 2)
SET_DECISION_MAKER_ATTRIBUTE_CAUTION(ZcombatDec.a, 2)
*/
b8 RiotThread::SetupDecisionMaker()
{
// DM:
// [2,2] Seems to be the most aggressive setting in terms of weaponry
// [9,5] Seems to be agressive also
// [2,9] Anarchy Script..
// [3,3] From zombie script
// Cation:
// [2,2] From zombie script
// [10,10] From my script
Log::Debug( "Loading decision makers" );
LoadCharDecisionMaker( 2, &m_CharDecisionMaker );
LoadCombatDecisionMaker( 9, &m_CombatDecisionMaker );
bool bAlright = ( DoesDecisionMakerExist( m_CharDecisionMaker ) && DoesDecisionMakerExist( m_CombatDecisionMaker ) );
if( bAlright == false )
{
Log::Debug( "Error loading decision makers..." );
return false;
}
// SetDecisionMakerAttributeCaution( m_CombatDecisionMaker, 10 );
// SetDecisionMakerAttributeRetreatingBehaviour( m_CombatDecisionMaker, 4 );
// SetDecisionMakerAttributeCaution( m_CharDecisionMaker, 10 );
// SetDecisionMakerAttributeRetreatingBehaviour( m_CharDecisionMaker, 4 );
Log::Debug( "Loaded decision makers" );
return true;
}
// TODO: Turn fist-fights into GUN FIGHTS, WRAAAA
// TODO: Peds will not offensively attack you with the menu option disabled, however may defend themselves
void RiotThread::RunScript()
{
m_bEnabled = true;
m_bTargetPlayer = false;
m_bCopsGoCrazy = true;
m_bPedsUseCars = true;
m_bUseDecisionMaker = false;
m_bPedsWanted = true;
m_bMadDrivers = true;
m_bEmergancyServicesDisabled = true;
CreateKeyboard();
CreateMenu();
bool bSetupDMSuccess = SetupDecisionMaker();
while( IsThreadAlive() )
{
if( m_bEnabled && ( !NetworkIsSessionStarted() ) )
{
Ped LocalPed = GetPlayerPed();
SetPedDensityMultiplier( 70.f ); //More peds! (was 80.f)
SwitchMadDrivers( m_bMadDrivers );
AllowEmergencyServices( !m_bEmergancyServicesDisabled );
AllowGangRelationshipsToBeChangedByNextCommand( true );
SetupRelationships();
for( u32 i = 0; i < GetPedCount(); i++ )
{
Ped Index;
if( GetPedByIndex( i, &Index ) )
{
if( IsCharDead( Index )
|| IsCharFatallyInjured( Index )
|| IsPedAMissionPed( Index ) )
continue;
u32 IndexGroup = GetPedGroup( &Index );
if( m_bCopsGoCrazy == false && IndexGroup == 3 )
continue; //Cops
SetCharAsMissionChar( Index ); // This is what makes them commit acts of hair-trigger violence
if( m_bUseDecisionMaker && bSetupDMSuccess )
{
SetCharDecisionMaker( Index, m_CharDecisionMaker );
SetCombatDecisionMaker( Index, m_CombatDecisionMaker );
}
if( HasCharGotWeapon( Index, eWeapon::WEAPON_ANYWEAPON ) == false )
{
AllowTargetWhenInjured( Index, 1 );
SetCharWillMoveWhenInjured( Index, 1 );
SetCharWillDoDrivebys( Index, 1 );
SetCharWillUseCarsInCombat( Index, m_bPedsUseCars );
SetCharCanBeShotInVehicle( Index, 1 );
SetCharCanBeKnockedOffBike( Index, 1 );
SetCharCantBeDraggedOut( Index, 0 );
SetCharWantedByPolice( Index, ( m_bPedsWanted && IndexGroup != 3 ) );
CoverPoint cp;
cp.Set( 1 );
SetCharWillUseCover( Index, cp );
SetPedWontAttackPlayerWithoutWantedLevel( Index, 0 );
SetCharDropsWeaponsWhenDead( Index, false ); //TODO: Menu var
SetSenseRange( Index, 100.f );
SetCharAccuracy( Index, 100 );
SetCharRelationshipGroup( Index, 8 );
if( IndexGroup != 3 )
{
eWeapon RandomWeapon = GetRandomWeapon( m_bPedsUseMelee ? 16 : 13 );
GiveWeaponToChar( Index, RandomWeapon, 9999, 0 );
// GiveDelayedWeaponToChar( Index, RandomWeapon, 9999, 1 );
SetCurrentCharWeapon( Index, RandomWeapon, true );
BlockPedWeaponSwitching( Index, true );
}
TaskCombatHatedTargetsAroundChar( Index, 100.f );
SetCharKeepTask( Index, true );
}
}
}
Wait( 100 );
}
}
}
void RiotThread::OnStart()
{
//Init
m_pMenu = NULL;
Log::Debug( "OnStart Executed" );
}
void RiotThread::OnKill()
{
// Destroy
IKeyboardHookService *kbhService = ScriptHookManager::RequestService<IKeyboardHookService>( "KeyboardHook" );
kbhService->RemoveHandler( this );
if( m_pMenu )
{
m_pMenu->Release();
m_pMenu = NULL;
}
ScriptThread::OnKill();
Log::Debug( "OnKill Executed" );
}
void RiotThread::CreateKeyboard()
{
IKeyboardHookService *kbhService = ScriptHookManager::RequestService<IKeyboardHookService>( "KeyboardHook" );
kbhService->AddHandler( this );
}
void RiotThread::CreateMenu()
{
IMenuService *menuService = ScriptHookManager::RequestService< IMenuService >( "Menu" );
m_pMenu = menuService->CreateMenu();
// Normal Menu
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_bPedsUseMelee ? "Disable peds use melee weapons" : "Enable peds use melee weapons" );
AddMenuItemCustom( 5, m_bUseDecisionMaker ? "Disable decision maker" : "Enable decision maker" );
AddMenuItemCustom( 6, m_bPedsWanted ? "Disable peds wanted" : "Enable peds wanted" );
AddMenuItemCustom( 7, m_bMadDrivers ? "Disable mad drivers" : "Enable mad drives" );
AddMenuItemCustom( 8, m_bEmergancyServicesDisabled ? "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_bPedsUseMelee = !m_bPedsUseMelee;
SetMenuItemCustom( 4, m_bPedsUseMelee ? "Disable peds use melee weapons" : "Enable peds use melee weapons" );
break;
}
case 5:
{
m_bUseDecisionMaker = !m_bUseDecisionMaker;
SetMenuItemCustom( 5, m_bUseDecisionMaker ? "Disable decision maker" : "Enable decision maker" );
break;
}
case 6:
{
m_bPedsWanted = !m_bPedsWanted;
SetMenuItemCustom( 6, m_bPedsWanted ? "Disable peds wanted" : "Enable peds wanted" );
break;
}
case 7:
{
m_bMadDrivers = !m_bMadDrivers;
SetMenuItemCustom( 7, m_bMadDrivers ? "Disable mad drivers" : "Enable mad drives" );
break;
}
case 8:
{
m_bEmergancyServicesDisabled = !m_bEmergancyServicesDisabled;
SetMenuItemCustom( 8, m_bEmergancyServicesDisabled ? "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();
}
}
}