Files
gtav-src/script/dev_ng/singleplayer/include/public/oddjob_aggro.sch
T
2025-09-29 00:52:08 +02:00

461 lines
16 KiB
Scheme
Executable File

//////////////////////////////////////////////////////////////////////////////////////////
// //
// SCRIPT NAME : oddjob_aggro //
// AUTHOR : Steven Messinger //
// DESCRIPTION : Group of functions to trackf if the player has //
// triggered aggo on a ped //
// TODO : Optimize.. can spread these updates over a few frames //
// NOTE : Currently the best way to use this check and keep your //
// script optimized is to only check one actor each frame. //
//////////////////////////////////////////////////////////////////////////////////////////
///
USING "globals.sch"
USING "commands_misc.sch"
USING "script_maths.sch"
ENUM EAggro
//Use These
//IS_BITMASK_AS_ENUM_SET()
//SET_BITMASK_AS_ENUM()
//Do not use SET_BIT() OT IS_BIT_SET()
EAggro_Aiming = BIT0, //2
EAggro_Wanted = BIT1, //4
EAggro_ShotNear = BIT2, //8
EAggro_HeardShot = BIT3, //16
EAggro_Attacked = BIT4, //32
EAggro_MinorAttacked= BIT5, //64
EAggro_UsingGasCan = BIT6, //128
EAggro_JackingCar = BIT7
ENDENUM
STRUCT AGGRO_ARGS
INT iBitFieldDontCheck = 0
INT aimTimer = 0
FLOAT fAimRange = 15.0
INT fAimTime = 1500 //1.5 seconds
INT iGunShotHearRange = 45
FLOAT fExplosionRange = 25.0
INT iShotIRange = 5 //shot impact range
//The problem with having this here is that we'll need a new AGGRO_ARGS struct for every ped we're checking
//VEHICLE_INDEX pedVehicle
ENDSTRUCT
// Used for major attack
BOOL bSetStartHealth = FALSE
INT iAggroStartHealth, iAggroCurrentHealth, iAggroHealthDelta
FUNC BOOL CHECK_AIMING(PED_INDEX target, AGGRO_ARGS& aggroArgs)
IF NOT IS_ENTITY_DEAD(target)
IF IS_PED_ARMED(PLAYER_PED_ID(), WF_INCLUDE_PROJECTILE|WF_INCLUDE_GUN)
IF IS_PLAYER_FREE_AIMING_AT_ENTITY(PLAYER_ID(), target)
OR IS_PLAYER_TARGETTING_ENTITY(PLAYER_ID(), target)
IF IS_PED_FACING_PED(target, PLAYER_PED_ID(), 90)
IF GET_PLAYER_DISTANCE_FROM_ENTITY(target) < aggroArgs.fAimRange
IF aggroArgs.aimTimer = 0
aggroArgs.aimTimer = GET_GAME_TIMER()
ELIF GET_GAME_TIMER() - aggroArgs.aimTimer > aggroArgs.fAimTime
PRINTLN("CHECK_AIMING returns TRUE")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL IS_PLAYER_THROWING_STICKYBOMBS_AT_VEHICLE(VEHICLE_INDEX vehToCheck)
WEAPON_TYPE wtReturn
ENTITY_INDEX entFreeAim
IF DOES_ENTITY_EXIST(vehToCheck)
IF IS_VEHICLE_DRIVEABLE(vehToCheck)
IF GET_PED_IN_VEHICLE_SEAT(vehToCheck) != NULL //make sure there are peds inside
IF GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), wtReturn)
IF wtReturn = WEAPONTYPE_STICKYBOMB
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), vehToCheck) < 40 //player throwing range
IF GET_ENTITY_PLAYER_IS_FREE_AIMING_AT(PLAYER_ID(), entFreeAim)
IF ( IS_ENTITY_A_VEHICLE(entFreeAim) AND GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(entFreeAim) = vehToCheck )
OR ( IS_ENTITY_A_PED(entFreeAim) AND GET_PED_INDEX_FROM_ENTITY_INDEX(entFreeAim) = GET_PED_IN_VEHICLE_SEAT(vehToCheck) )
IF ( IS_PED_ON_FOOT(PLAYER_PED_ID()) AND IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_ATTACK) )
OR ( IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_ATTACK) )
PRINTLN("IS_PLAYER_THROWING_STICKYBOMBS_AT_VEHICLE - RETURNED TRUE!")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL IS_PLAYER_THROWING_STICKYBOMBS()
WEAPON_TYPE wtReturn
IF GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), wtReturn)
IF wtReturn = WEAPONTYPE_STICKYBOMB
IF IS_PLAYER_FREE_AIMING(PLAYER_ID())
IF ( IS_PED_ON_FOOT(PLAYER_PED_ID()) AND IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_ATTACK) )
OR ( IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_ATTACK) )
PRINTLN("IS_PLAYER_THROWING_STICKYBOMBS() - RETURNED TRUE!")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL CHECK_SHOT_NEAR(PED_INDEX player, ENTITY_INDEX target, AGGRO_ARGS& aggroArgs, BOOL bCheckProjectiles = TRUE)
VECTOR vTemp
VEHICLE_INDEX vehToCheck = NULL
IF NOT IS_ENTITY_DEAD(target)
vTemp = GET_ENTITY_COORDS(target)
ENDIF
//near miss
IF IS_BULLET_IN_AREA(vTemp, 4.0, TRUE)
PRINTLN("CHECK_SHOT_NEAR: Ped panicking because bullet in area!")
RETURN TRUE
ENDIF
IF HAS_BULLET_IMPACTED_IN_AREA(vTemp, TO_FLOAT(aggroArgs.iShotIRange))
PRINTLN("CHECK_SHOT_NEAR: Ped panicking because bullet hit near them")
RETURN TRUE
ENDIF
//I moved this check from CHECK_HEARD_SHOT to here since it makes more sense.(1/20/12 - MB)
IF IS_PED_ARMED(player, ENUM_TO_INT(WF_INCLUDE_PROJECTILE))
IF IS_PED_SHOOTING(player)
IF IS_ENTITY_AT_COORD(target, GET_ENTITY_COORDS(player), <<aggroArgs.iShotIRange*3, aggroArgs.iShotIRange*3, aggroArgs.iShotIRange*3>>)
IF IS_PED_FACING_PED(GET_PED_INDEX_FROM_ENTITY_INDEX(target), player, 120)
AND HAS_ENTITY_CLEAR_LOS_TO_ENTITY(target, player)
PRINTLN("CHECK_SHOT_NEAR: Ped panicking because ped saw Player throwing projectile near them")
RETURN TRUE
ENDIF
ENDIF
ELSE
IF IS_PED_IN_ANY_VEHICLE(GET_PED_INDEX_FROM_ENTITY_INDEX(target))
vehToCheck = GET_VEHICLE_PED_IS_IN(GET_PED_INDEX_FROM_ENTITY_INDEX(target))
ENDIF
IF IS_PED_PLANTING_BOMB(player)
OR IS_PLAYER_THROWING_STICKYBOMBS_AT_VEHICLE(vehToCheck)
IF IS_ENTITY_AT_COORD(target, GET_ENTITY_COORDS(player), <<aggroArgs.iShotIRange*3, aggroArgs.iShotIRange*3, aggroArgs.iShotIRange*3>>)
IF IS_PED_FACING_PED(GET_PED_INDEX_FROM_ENTITY_INDEX(target), player, 120)
AND HAS_ENTITY_CLEAR_LOS_TO_ENTITY(target, player)
PRINTLN("CHECK_SHOT_NEAR: Ped panicking because ped saw Player planting bomb near them")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IF bCheckProjectiles
//impacted near
// Made change to fix Bug # 558664 - previously this check was only looking for smoke grenades.
IF IS_PROJECTILE_IN_AREA(<<vTemp.x-aggroArgs.iShotIRange, vTemp.y-aggroArgs.iShotIRange, vTemp.z-aggroArgs.iShotIRange>>, <<vTemp.x+aggroArgs.iShotIRange, vTemp.y+aggroArgs.iShotIRange, vTemp.z+aggroArgs.iShotIRange>>)
PRINTLN("CHECK_SHOT_NEAR: Ped panicking because projectile is in area!")
RETURN TRUE
ENDIF
ENDIF
//Performance of this?
// IF IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, vTemp, aggroArgs.fExplosionRange)
// AND NOT IS_EXPLOSION_IN_SPHERE(EXP_TAG_DIR_STEAM, vTemp, aggroArgs.fExplosionRange)
// AND NOT IS_EXPLOSION_IN_SPHERE(EXP_TAG_DIR_WATER_HYDRANT, vTemp, aggroArgs.fExplosionRange)
// PRINTLN("CHECK_SHOT_NEAR: Ped panicking becuase there is an explosion near them")
// RETURN TRUE
// ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL CHECK_HEARD_SHOT(PED_INDEX player, PED_INDEX target, AGGRO_ARGS& aggroArgs)
//is shooting near
//Player is shooting near the target
IF IS_PED_ARMED(player, ENUM_TO_INT(WF_INCLUDE_GUN))
IF IS_PED_SHOOTING(player)
AND NOT IS_PED_CURRENT_WEAPON_SILENCED(player)
IF IS_ENTITY_AT_COORD(target, GET_ENTITY_COORDS(player), <<aggroArgs.iGunShotHearRange, aggroArgs.iGunShotHearRange, aggroArgs.iGunShotHearRange>>)
PRINTLN("CHECK_HEARD_SHOT: Ped panicking because player is shooting and ped heard it!")
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL CHECK_POURING_PETROL(PED_INDEX player, PED_INDEX target)
WEAPON_TYPE playersCurrentWeapon
GET_CURRENT_PED_WEAPON(player, playersCurrentWeapon)
IF playersCurrentWeapon = WEAPONTYPE_PETROLCAN
IF IS_PED_SHOOTING(player)
IF VDIST(GET_ENTITY_COORDS(player),GET_ENTITY_COORDS(target)) < 2.5
IF IS_PED_FACING_PED(player, target, 180.0)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL CHECK_ATTACKED(PED_INDEX target, VEHICLE_INDEX pedVehicle, BOOL bIncludeMinor = FALSE, BOOL bMajorAttack = FALSE,
BOOL bIncludeCarJacking = TRUE, BOOL bIncludePunching = TRUE)
IF bMajorAttack
IF NOT bSetStartHealth
iAggroStartHealth = GET_ENTITY_HEALTH(target)
PRINTLN("CHECK_ATTACKED: Ped's staring health = ", iAggroStartHealth)
bSetStartHealth = TRUE
ENDIF
iAggroCurrentHealth = GET_ENTITY_HEALTH(target)
// PRINTLN("CHECK_ATTACKED: iAggroCurrentHealth = ", iAggroCurrentHealth)
iAggroHealthDelta = iAggroStartHealth - iAggroCurrentHealth
// PRINTLN("CHECK_ATTACKED: iAggroHealthDelta = ", iAggroHealthDelta)
VEHICLE_INDEX ePlayerVehicle
ePlayerVehicle = GET_PLAYERS_LAST_VEHICLE()
IF NOT IS_ENTITY_DEAD(ePlayerVehicle)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(target, ePlayerVehicle)
IF iAggroHealthDelta > 100.0
PRINTLN("CHECK_ATTACKED: VEHICLE DAMAGE - iAggroHealthDelta = ", iAggroHealthDelta)
PRINTLN("CHECK_ATTACKED: VEHICLE DAMAGE - Ped panicking because player has majorly attacked him")
RETURN TRUE
ENDIF
ENDIF
ENDIF
IF bSetStartHealth
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(target, PLAYER_PED_ID())
IF iAggroHealthDelta > 100.0
PRINTLN("CHECK_ATTACKED: iAggroHealthDelta = ", iAggroHealthDelta)
PRINTLN("CHECK_ATTACKED: Ped panicking because player has majorly attacked him")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ELSE
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(target, PLAYER_PED_ID())
PRINTLN("CHECK_ATTACKED: Ped panicking because player has damaged him")
RETURN TRUE
ENDIF
ENDIF
IF NOT bMajorAttack
//Has my car hurt the ped?
VEHICLE_INDEX ePlayerVehicle
ePlayerVehicle = GET_PLAYERS_LAST_VEHICLE()
IF NOT IS_ENTITY_DEAD(ePlayerVehicle)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(target, ePlayerVehicle)
PRINTLN("CHECK_ATTACKED: Ped panicking because the player's vehicle caused damage to the ped")
RETURN TRUE
ENDIF
ENDIF
ENDIF
//car jacked
IF bIncludeCarJacking
IF NOT IS_ENTITY_DEAD(target)
IF IS_PED_BEING_JACKED(target)
IF GET_PEDS_JACKER(target) = PLAYER_PED_ID()
PRINTLN("CHECK_ATTACKED: Ped panicking because player is jacking their vehicle!")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
IF bIncludePunching
IF IS_PED_IN_MELEE_COMBAT(PLAYER_PED_ID())
IF IS_ENTITY_AT_COORD(target, GET_ENTITY_COORDS(PLAYER_PED_ID()), << 10, 10, 10 >>)
IF HAS_PLAYER_DAMAGED_AT_LEAST_ONE_PED(PLAYER_ID())
PRINTLN("CHECK_ATTACKED: Ped panicking because player is punching dudes around him!")
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
IF IS_PED_PERFORMING_STEALTH_KILL(PLAYER_PED_ID())
IF WAS_PED_KILLED_BY_STEALTH(target)
PRINTLN("CHECK_ATTACKED: Ped panicking because player is performing a stealth kill on them")
RETURN TRUE
ENDIF
ENDIF
IF CHECK_POURING_PETROL(PLAYER_PED_ID(), target)
PRINTLN("CHECK_ATTACKED: Ped panicking because player is pouring gas on him/her.")
RETURN TRUE
ENDIF
IF bIncludeMinor
//has player pushed the entity
IF IS_PED_RAGDOLL(target)
AND GET_PLAYER_DISTANCE_FROM_ENTITY(target) < 1.5
PRINTLN("CHECK_ATTACKED: Ped panicking because player is touching them")
RETURN TRUE
ELSE
IF IS_PED_IN_ANY_VEHICLE(target)
IF IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(), GET_VEHICLE_PED_IS_IN(target))
RETURN TRUE
ENDIF
ELSE
IF IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(), target)
RETURN TRUE
ENDIF
ENDIF
ENDIF
//Check to see if the entity has damaged the targets car weather he's in it or not
IF NOT IS_ENTITY_DEAD(pedVehicle)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(pedVehicle, PLAYER_PED_ID())
PRINTLN("CHECK_ATTACKED: Ped panicking because player has damaged their car")
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL DO_AGGRO_CHECK(PED_INDEX myPed, VEHICLE_INDEX pedVehicle, AGGRO_ARGS& aggroArgs, EAggro& aggroReason,
BOOL bStrictChecks = FALSE, BOOL bCheckProjectiles = TRUE, BOOL bMajorAttack = FALSE, BOOL bReturnTrueOnDeath = TRUE,
BOOL bIncludePunching = TRUE)
PED_INDEX playerPed = PLAYER_PED_ID()
IF NOT IS_ENTITY_DEAD(playerPed) AND NOT IS_ENTITY_DEAD(myPed)
//Check if the player is aiming at the ped
IF NOT IS_BITMASK_AS_ENUM_SET(aggroArgs.iBitFieldDontCheck, EAggro_Aiming)
IF CHECK_AIMING(myPed, aggroArgs)
aggroReason = EAggro_Aiming
RETURN TRUE
ENDIF
ENDIF
//Check if the player is Wanted
IF NOT IS_BITMASK_AS_ENUM_SET(aggroArgs.iBitFieldDontCheck, EAggro_Wanted)
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
aggroReason = EAggro_Wanted
RETURN TRUE
ENDIF
ENDIF
//Check if the player has Shot Near the ped
IF NOT IS_BITMASK_AS_ENUM_SET(aggroArgs.iBitFieldDontCheck, EAggro_ShotNear)
IF CHECK_SHOT_NEAR(playerPed, myPed, aggroArgs, bCheckProjectiles)
aggroReason = EAggro_ShotNear
RETURN TRUE
ENDIF
ENDIF
//Check if the ped heard the player shooting
IF NOT IS_BITMASK_AS_ENUM_SET(aggroArgs.iBitFieldDontCheck, EAggro_HeardShot)
IF CHECK_HEARD_SHOT(playerPed, myPed, aggroArgs)
aggroReason = EAggro_HeardShot
RETURN TRUE
ENDIF
ENDIF
BOOL bIncludeJackingCar = NOT IS_BITMASK_AS_ENUM_SET(aggroArgs.iBitFieldDontCheck, EAggro_JackingCar)
//Check to see if the player attacked the ped
IF bStrictChecks
IF CHECK_ATTACKED(myPed, pedVehicle, TRUE, bMajorAttack, bIncludeJackingCar)
aggroReason = EAggro_MinorAttacked
RETURN TRUE
ENDIF
ELSE
IF NOT IS_BITMASK_AS_ENUM_SET(aggroArgs.iBitFieldDontCheck, EAggro_Attacked)
IF CHECK_ATTACKED(myPed, pedVehicle, FALSE, bMajorAttack, bIncludeJackingCar, bIncludePunching)
aggroReason = EAggro_Attacked
RETURN TRUE
ENDIF
ENDIF
ENDIF
ELSE
IF DOES_ENTITY_EXIST(myPed)
IF bReturnTrueOnDeath
AND HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(myPed, playerPed)
PRINTLN("DO_AGGRO_CHECK: Ped panicking because player has killed them")
aggroReason = EAggro_Attacked
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//new function that steals from CHECK_ATTACK but modifies it to allow for stealth kills
FUNC BOOL CHECK_ATTACKED_ALLOW_STEALTH(PED_INDEX target, VEHICLE_INDEX pedVehicle)
IF DOES_ENTITY_EXIST(target)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(target, PLAYER_PED_ID())
AND NOT IS_ENTITY_DEAD(target)
PRINTLN("CHECK_ATTACKED: Ped panicking because player has damaged him")
RETURN TRUE
ENDIF
VEHICLE_INDEX ePlayerVehicle
ePlayerVehicle = GET_PLAYERS_LAST_VEHICLE()
IF NOT IS_ENTITY_DEAD(ePlayerVehicle)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(target, ePlayerVehicle)
PRINTLN("CHECK_ATTACKED: Ped panicking because the player's vehicle caused damage to the ped")
RETURN TRUE
ENDIF
ENDIF
//car jacked
IF NOT IS_ENTITY_DEAD(target)
IF IS_PED_BEING_JACKED(target)
IF GET_PEDS_JACKER(target) = PLAYER_PED_ID()
PRINTLN("CHECK_ATTACKED: Ped panicking because player is jacking their vehicle!")
RETURN TRUE
ENDIF
ENDIF
ENDIF
//Check to see if the entity has damaged the targets car weather he's in it or not
IF NOT IS_ENTITY_DEAD(pedVehicle)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(pedVehicle, PLAYER_PED_ID())
PRINTLN("CHECK_ATTACKED: Ped panicking because player has damaged their car")
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC