////////////////////////////////////////////////////////////////////////////////////////// // // // 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), <>) 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), <>) 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(<>, <>) 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), <>) 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