994 lines
34 KiB
Scheme
Executable File
994 lines
34 KiB
Scheme
Executable File
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
//
|
|
// MISSION NAME : RC_Threat_Public.sch
|
|
// AUTHOR : Andy M / Aaron G / (Ste did some too...)
|
|
// DESCRIPTION : Threat Functions
|
|
//
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
|
|
//----------------------
|
|
// INCLUDES
|
|
//----------------------
|
|
USING "RC_Helper_Functions.sch"
|
|
|
|
//----------------------
|
|
// CONSTANTS
|
|
//----------------------
|
|
CONST_INT MAX_THREAT_SLOTS 10
|
|
CONST_FLOAT MAX_SIGHT_DIST 200.0
|
|
|
|
//----------------------
|
|
// STRUCTS
|
|
//----------------------
|
|
STRUCT THREAT_SLOT
|
|
SHAPETEST_INDEX mShapeTest = NULL
|
|
ENTITY_INDEX mSeeker = NULL
|
|
ENTITY_INDEX mTarget = NULL
|
|
INT iLastSightTime = 0
|
|
ENDSTRUCT
|
|
|
|
//----------------------
|
|
// ENUMS
|
|
//----------------------
|
|
// used to test specific body parts in the threat test
|
|
ENUM THREAT_TEST_BODY_PART_ENUM
|
|
TT_BODY_PART_PED_ROOT = 0,
|
|
TT_BODY_PART_HEAD,
|
|
TT_BODY_PART_NECK,
|
|
TT_BODY_PART_L_HAND,
|
|
TT_BODY_PART_R_HAND,
|
|
TT_BODY_PART_L_CALF,
|
|
TT_BODY_PART_R_CALF,
|
|
TT_BODY_PART_RANDOM
|
|
ENDENUM
|
|
|
|
//----------------------
|
|
// VARIABLES
|
|
//----------------------
|
|
THREAT_SLOT mThreatSlot[MAX_THREAT_SLOTS]
|
|
BOOL bDrawDebugThreat = FALSE
|
|
|
|
//----------------------
|
|
// MISC FUNCTIONS
|
|
//----------------------
|
|
|
|
/// PURPOSE:
|
|
/// Given an index return us a bone to look at
|
|
/// PARAMS:
|
|
/// mPed - Ped
|
|
/// iCheckIndex - Number
|
|
/// RETURNS:
|
|
/// Position of Bone
|
|
FUNC VECTOR GET_SIGHT_BONE_POS(PED_INDEX mPed, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
|
|
// generate a random selection for TT_BODY_PART_RANDOM
|
|
IF eBodyPart = TT_BODY_PART_RANDOM
|
|
INT iRand = GET_RANDOM_INT_IN_RANGE(0, ENUM_TO_INT(TT_BODY_PART_RANDOM))
|
|
eBodyPart = INT_TO_ENUM(THREAT_TEST_BODY_PART_ENUM, iRand)
|
|
ENDIF
|
|
|
|
IF eBodyPart = TT_BODY_PART_PED_ROOT
|
|
RETURN GET_ENTITY_COORDS(mPed)
|
|
|
|
ELIF eBodyPart = TT_BODY_PART_HEAD
|
|
RETURN GET_PED_BONE_COORDS(mPed, BONETAG_HEAD, <<0.0, 0.0, 0.0>>)
|
|
|
|
ELIF eBodyPart = TT_BODY_PART_NECK
|
|
RETURN GET_PED_BONE_COORDS(mPed, BONETAG_NECK, <<0.0, 0.0, 0.0>>)
|
|
|
|
ELIF eBodyPart = TT_BODY_PART_L_HAND
|
|
RETURN GET_PED_BONE_COORDS(mPed, BONETAG_L_HAND, <<0.0, 0.0, 0.0>>)
|
|
|
|
ELIF eBodyPart = TT_BODY_PART_R_HAND
|
|
RETURN GET_PED_BONE_COORDS(mPed, BONETAG_R_HAND, <<0.0, 0.0, 0.0>>)
|
|
|
|
ELIF eBodyPart = TT_BODY_PART_L_CALF
|
|
RETURN GET_PED_BONE_COORDS(mPed, BONETAG_L_CALF, <<0.0, 0.0, 0.0>>)
|
|
|
|
ELIF eBodyPart = TT_BODY_PART_R_CALF
|
|
RETURN GET_PED_BONE_COORDS(mPed, BONETAG_R_CALF, <<0.0, 0.0, 0.0>>)
|
|
|
|
ENDIF
|
|
|
|
RETURN GET_ENTITY_COORDS(mPed)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Gets a heading between 2 vectors
|
|
FUNC FLOAT GET_HEADING_FROM_COORDS_TO_COORDS(vector oldCoords,vector newCoords, bool invert=true)
|
|
float heading
|
|
float dX = newCoords.x - oldCoords.x
|
|
float dY = newCoords.y - oldCoords.y
|
|
if dY != 0
|
|
heading = ATAN2(dX,dY)
|
|
ELSE
|
|
if dX < 0
|
|
heading = -90
|
|
ELSE
|
|
heading = 90
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//flip because for some odd reason the coders think west is a heading of 90 degrees, so this'll match the output of commands such as GET_ENTITY_HEADING()
|
|
IF invert = TRUE
|
|
heading *= -1.0
|
|
//below not necessary but helps for debugging
|
|
IF heading < 0
|
|
heading += 360.0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN heading
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Draw the sight cone from a ped
|
|
/// PARAMS:
|
|
/// ped - ped to draw from
|
|
/// angle - the angle of the cone so 180.0 is can see in a half circle
|
|
PROC DRAW_PED_HEAD_CONE(PED_INDEX ped, FLOAT angle = 120.0)
|
|
angle /= 2.0
|
|
VECTOR head = GET_PED_BONE_COORDS(ped, BONETAG_HEAD, <<0, 0, 0>>)
|
|
FLOAT heading = GET_HEADING_FROM_COORDS_TO_COORDS(head, GET_PED_BONE_COORDS(ped, BONETAG_HEAD, <<0, 5, 0>>))
|
|
DRAW_DEBUG_LINE(head, GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(head, heading + angle, <<0, 5, 0>>))
|
|
DRAW_DEBUG_LINE(head, GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(head, heading - angle, <<0, 5, 0>>))
|
|
DRAW_DEBUG_LINE(head, GET_PED_BONE_COORDS(ped, BONETAG_HEAD, <<0, 5, 0>>), 255, 255, 255)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Tells us if a ped is within the viewcone of another ped
|
|
/// PARAMS:
|
|
/// vPedLookFor - the ped we are looking for
|
|
/// vPed - the ped who is doing the seeing
|
|
/// viewcone - viewcone of the seeing ped
|
|
/// useHead - if this is true we take into account which way the seeing ped is looking or we use his forward vector
|
|
/// RETURNS:
|
|
/// True or False
|
|
FUNC BOOL IS_PED_IN_PED_VIEW_CONE(PED_INDEX vPed, PED_INDEX vPedLookFor, FLOAT viewcone = 170.0, BOOL useHead = FALSE)
|
|
VECTOR vNormalisedVec = NORMALISE_VECTOR(GET_ENTITY_COORDS(vPedLookFor) - GET_ENTITY_COORDS(vPed))
|
|
VECTOR fwd
|
|
FLOAT fViewAngle
|
|
|
|
IF viewcone < 0.1 OR viewcone > 360
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF (useHead = FALSE)
|
|
fwd = GET_ENTITY_FORWARD_VECTOR(vPed)
|
|
ELSE
|
|
fwd = NORMALISE_VECTOR(GET_PED_BONE_COORDS(vPed, BONETAG_HEAD, <<0, 5, 0>>) - GET_PED_BONE_COORDS(vPed, BONETAG_HEAD, <<0, 0, 0>>))
|
|
ENDIF
|
|
|
|
fViewAngle = DOT_PRODUCT(fwd, vNormalisedVec)
|
|
IF fViewAngle <= COS(viewcone / 2.0)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Tells us if a ped is within the viewcone of another ped
|
|
/// PARAMS:
|
|
/// vPedLookFor - the ped we are looking for
|
|
/// vPed - the ped who is doing the seeing
|
|
/// viewcone - viewcone of the seeing ped
|
|
/// useHead - if this is true we take into account which way the seeing ped is looking or we use his forward vector
|
|
/// RETURNS:
|
|
/// True or False
|
|
FUNC BOOL IS_POSITION_IN_PED_VIEW_CONE(PED_INDEX vPed, VECTOR vPos, FLOAT viewcone = 170.0, BOOL useHead = FALSE)
|
|
VECTOR vNormalisedVec = NORMALISE_VECTOR(vPos - GET_ENTITY_COORDS(vPed))
|
|
VECTOR fwd
|
|
FLOAT fViewAngle
|
|
|
|
IF viewcone < 0.1 OR viewcone > 360
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF (useHead = FALSE)
|
|
fwd = GET_ENTITY_FORWARD_VECTOR(vPed)
|
|
ELSE
|
|
fwd = NORMALISE_VECTOR(GET_PED_BONE_COORDS(vPed, BONETAG_HEAD, <<0, 5, 0>>) - GET_PED_BONE_COORDS(vPed, BONETAG_HEAD, <<0, 0, 0>>))
|
|
ENDIF
|
|
|
|
fViewAngle = DOT_PRODUCT(fwd, vNormalisedVec)
|
|
IF fViewAngle <= COS(viewcone / 2.0)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
|
|
//----------------------
|
|
// THREAT FUNCTIONS
|
|
//----------------------
|
|
|
|
/// PURPOSE:
|
|
/// Sets all shape test variables to be null
|
|
PROC RESET_THREAT_SLOT(THREAT_SLOT &slot)
|
|
slot.mShapeTest = NULL
|
|
slot.mSeeker = NULL
|
|
slot.mTarget = NULL
|
|
slot.iLastSightTime = 0
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Sets all shape test variables to be null
|
|
PROC RESET_THREAT_SHAPETESTS()
|
|
INT i
|
|
|
|
REPEAT COUNT_OF(mThreatSlot) i
|
|
RESET_THREAT_SLOT(mThreatSlot[i])
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// For script to use for clearing a specific threat test
|
|
/// PARAMS:
|
|
/// src - source threat entity
|
|
/// tgt - target ped entity
|
|
/// RETURNS:
|
|
/// TRUE threat slot is reset if a threat test was detected with the two entities
|
|
FUNC BOOL RESET_THREAT_SLOT_FOR_ENTITIES(ENTITY_INDEX src, ENTITY_INDEX tgt)
|
|
INT i
|
|
BOOL bResetTest = FALSE
|
|
|
|
REPEAT COUNT_OF(mThreatSlot) i
|
|
IF (mThreatSlot[i].mSeeker = src) AND (mThreatSlot[i].mTarget = tgt)
|
|
RESET_THREAT_SLOT(mThreatSlot[i])
|
|
bResetTest = TRUE
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN bResetTest
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the peds already has a threat shape test associated with it
|
|
/// PARAMS:
|
|
/// src - source threat entity
|
|
/// tgt - target ped entity
|
|
/// RETURNS:
|
|
/// the number of the ped's threat shapetest, or -1 if they don't have one
|
|
FUNC INT GET_THREAT_SLOT(ENTITY_INDEX src, ENTITY_INDEX tgt)
|
|
INT i
|
|
|
|
REPEAT COUNT_OF(mThreatSlot) i
|
|
IF (mThreatSlot[i].mSeeker = src) AND (mThreatSlot[i].mTarget = tgt)
|
|
RETURN i
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN -1
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Finds a gap in the threat shape test array
|
|
/// RETURNS:
|
|
/// Returns the array number of a space for a new threat shapetest or -1 if array is full
|
|
FUNC INT GET_EMPTY_THREAT_SLOTS()
|
|
INT i
|
|
|
|
REPEAT COUNT_OF(mThreatSlot) i
|
|
IF (mThreatSlot[i].mShapeTest = NULL
|
|
AND mThreatSlot[i].mSeeker = NULL // Bug fix B*1158712 - function was stomping on existing test so needs to check there isn't already entities assigned to the slots
|
|
AND mThreatSlot[i].mTarget = NULL)
|
|
RETURN i
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN -1
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Check a direct line of sight from point to ped
|
|
/// PARAMS:
|
|
/// stest - shape test index
|
|
/// pt - point to check
|
|
/// mPedLookFor - ped to look for
|
|
/// seeTime - if we can see the point this is set to current game time
|
|
/// exclude - entity to eliminate from the search
|
|
/// eBodyPart - set specific body part to check can be seen, default picks part at random
|
|
/// RETURNS:
|
|
/// true or false
|
|
FUNC BOOL CAN_POINT_SEE_PED_SHAPETEST_RETURN_TIME(SHAPETEST_INDEX &stest, VECTOR pt, PED_INDEX mPedLookFor, INT &seeTime, ENTITY_INDEX exclude = NULL, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
|
|
INT iHits
|
|
VECTOR vec
|
|
VECTOR vNormal
|
|
ENTITY_INDEX hitEntity = NULL
|
|
|
|
// dead people can't see things - bail
|
|
IF NOT IS_ENTITY_ALIVE(mPedLookFor)
|
|
stest = NULL
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// start the shape test - if we dont have one
|
|
IF (stest = NULL)
|
|
// exclude the person we are looking for a clear line of sight is a hit
|
|
vec = GET_SIGHT_BONE_POS(mPedLookFor, eBodyPart)
|
|
stest = START_SHAPE_TEST_LOS_PROBE(pt, vec + ((vec - pt) * 0.1), SCRIPT_INCLUDE_ALL, exclude)
|
|
//CPRINTLN(DEBUG_MISSION, "[SHAPE TEST]: Created")
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// we had a shape test from before check the results
|
|
SHAPETEST_STATUS shapeStatus = GET_SHAPE_TEST_RESULT(stest, iHits, vec, vNormal, hitEntity)
|
|
|
|
// if the shape test doesn't exist - nullify and exit or if it isn't ready exit
|
|
IF (shapeStatus = SHAPETEST_STATUS_NONEXISTENT)
|
|
stest = NULL
|
|
RETURN FALSE
|
|
ELIF (shapeStatus = SHAPETEST_STATUS_RESULTS_NOTREADY)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// clear line of sight reference
|
|
stest = NULL
|
|
|
|
|
|
// check if we've hit someone and they are the person we are looking for
|
|
IF IS_ENTITY_A_PED(hitEntity)
|
|
IS_ENTITY_ALIVE(hitEntity)
|
|
IF (GET_PED_INDEX_FROM_ENTITY_INDEX(hitEntity) = mPedLookFor)
|
|
IF (bDrawDebugThreat)
|
|
DRAW_DEBUG_LINE_WITH_TWO_COLOURS(pt, GET_ENTITY_COORDS(mPedLookFor))
|
|
ENDIF
|
|
seeTime = GET_GAME_TIMER()
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF IS_ENTITY_A_VEHICLE(hitEntity)
|
|
IS_ENTITY_ALIVE(hitEntity)
|
|
IF IS_PED_IN_ANY_VEHICLE(mPedLookFor)
|
|
IF (GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(hitEntity) = GET_VEHICLE_PED_IS_IN(mPedLookFor))
|
|
IF (bDrawDebugThreat)
|
|
// CPRINTLN(DEBUG_MISSION, "Ped in car we can see him")
|
|
DRAW_DEBUG_LINE_WITH_TWO_COLOURS(pt, GET_ENTITY_COORDS(mPedLookFor))
|
|
ENDIF
|
|
seeTime = GET_GAME_TIMER()
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Does a direct line of sight check from ped to ped
|
|
/// PARAMS:
|
|
/// stest - shape test index
|
|
/// mPed - ped doing the looking
|
|
/// mPedLookFor - ped to look for
|
|
/// seeTime - if we can see the point this is set to current game time
|
|
/// viewCone - field of view set this to 0.0 if you don't care
|
|
/// useHead - take the line from the lookers head or body
|
|
/// eBodyPart - set specific body part to check can be seen, default picks part at random
|
|
/// RETURNS:
|
|
/// true or false
|
|
FUNC BOOL CAN_PED_SEE_PED_SHAPETEST_RETURN_TIME(SHAPETEST_INDEX &stest, PED_INDEX mPed, PED_INDEX mPedLookFor, INT &seeTime, FLOAT viewCone = 170.0, BOOL useHead = TRUE, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
|
|
// dead people can't see things - bail
|
|
IF NOT IS_ENTITY_ALIVE(mPed)
|
|
OR NOT IS_ENTITY_ALIVE(mPedLookFor)
|
|
stest = NULL
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// do cone check
|
|
IF NOT IS_PED_IN_PED_VIEW_CONE(mPed, mPedLookFor, viewCone, useHead)
|
|
stest = NULL
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN CAN_POINT_SEE_PED_SHAPETEST_RETURN_TIME(stest, GET_PED_BONE_COORDS(mPed, BONETAG_HEAD, <<0, 0, 0>>), mPedLookFor, seeTime, mPed, eBodyPart)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Does a direct line of sight check from heli to ped
|
|
/// PARAMS:
|
|
/// stest - shape test index
|
|
/// mHeli - heli doing the looking
|
|
/// mPedLookFor - ped to look for
|
|
/// seeTime - if we can see the point this is set to current game time
|
|
/// eBodyPart - set specific body part to check can be seen, default picks part at random
|
|
/// RETURNS:
|
|
/// true or false
|
|
FUNC BOOL CAN_HELI_SEE_PED_SHAPETEST_RETURN_TIME(SHAPETEST_INDEX &stest, VEHICLE_INDEX mHeli, PED_INDEX mPedLookFor, INT &seeTime, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
IF NOT IS_ENTITY_ALIVE(mHeli)
|
|
stest = NULL
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN CAN_POINT_SEE_PED_SHAPETEST_RETURN_TIME(stest, GET_ENTITY_COORDS(mHeli), mPedLookFor, seeTime, eBodyPart)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Does lien of sight but it gets it's own shapetest
|
|
/// PARAMS:
|
|
/// mPed - ped doing the looking
|
|
/// mPedLookFor - ped to look for
|
|
/// seeTime - if we can see the point this is set to current game time
|
|
/// viewCone - field of view set this to 0.0 if you don't care
|
|
/// useHead - take the line from the lookers head or body
|
|
/// eBodyPart - set specific body part to check can be seen, default picks part at random
|
|
/// RETURNS:
|
|
/// true or false
|
|
FUNC BOOL CAN_PED_SEE_PED_RETURN_TIME(PED_INDEX mPed, PED_INDEX mPedLookFor, INT &seeTime, FLOAT viewCone = 170.0, BOOL useHead = TRUE, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
INT iSlot = GET_THREAT_SLOT(mPed, mPedLookFor)
|
|
|
|
// dead people can't see things - bail
|
|
IF NOT IS_ENTITY_ALIVE(mPed)
|
|
OR NOT IS_ENTITY_ALIVE(mPedLookFor)
|
|
IF (iSlot <> -1)
|
|
RESET_THREAT_SLOT(mThreatSlot[iSlot])
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// do cone check
|
|
IF NOT IS_PED_IN_PED_VIEW_CONE(mPed, mPedLookFor, viewCone, useHead)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (iSlot = -1)
|
|
iSlot = GET_EMPTY_THREAT_SLOTS()
|
|
IF (iSlot = -1)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
mThreatSlot[iSlot].mSeeker = mPed
|
|
mThreatSlot[iSlot].mTarget = mPedLookFor
|
|
ENDIF
|
|
|
|
RETURN CAN_POINT_SEE_PED_SHAPETEST_RETURN_TIME(mThreatSlot[iSlot].mShapeTest, GET_PED_BONE_COORDS(mPed, BONETAG_HEAD, <<0, 0, 0>>), mPedLookFor, seeTime, mPed, eBodyPart)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Does lien of sight but it gets it's own shapetest
|
|
/// PARAMS:
|
|
/// mPed - ped doing the looking
|
|
/// mPedLookFor - ped to look for
|
|
/// viewCone - field of view set this to 0.0 if you don't care
|
|
/// useHead - take the line from the lookers head or body
|
|
/// iGrace -
|
|
/// eBodyPart - set specific body part to check can be seen, default picks part at random
|
|
/// RETURNS:
|
|
/// Returns True if test passes or test pass within 0.25 second of this check
|
|
FUNC BOOL CAN_PED_SEE_PED(PED_INDEX mPed, PED_INDEX mPedLookFor, FLOAT viewCone = 170.0, BOOL useHead = TRUE, INT iGrace = 250, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
BOOL bOK
|
|
VECTOR v
|
|
INT iSlot = GET_THREAT_SLOT(mPed, mPedLookFor)
|
|
|
|
// dead people can't see things - bail
|
|
IF NOT IS_ENTITY_ALIVE(mPed)
|
|
OR NOT IS_ENTITY_ALIVE(mPedLookFor)
|
|
IF (iSlot <> -1)
|
|
RESET_THREAT_SLOT(mThreatSlot[iSlot])
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// do cone check
|
|
IF NOT IS_PED_IN_PED_VIEW_CONE(mPed, mPedLookFor, viewCone, useHead)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (iSlot = -1)
|
|
iSlot = GET_EMPTY_THREAT_SLOTS()
|
|
IF (iSlot = -1)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
mThreatSlot[iSlot].mSeeker = mPed
|
|
mThreatSlot[iSlot].mTarget = mPedLookFor
|
|
ENDIF
|
|
|
|
v = GET_PED_BONE_COORDS(mPed, BONETAG_HEAD, <<0, 0, 0>>)
|
|
bOK = CAN_POINT_SEE_PED_SHAPETEST_RETURN_TIME(mThreatSlot[iSlot].mShapeTest, v, mPedLookFor, mThreatSlot[iSlot].iLastSightTime, mPed, eBodyPart)
|
|
RETURN (bOk) OR ((GET_GAME_TIMER() - mThreatSlot[iSlot].iLastSightTime) < iGrace)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Does lien of sight but it gets it's own shapetest
|
|
/// PARAMS:
|
|
/// mheli - heli doing the looking
|
|
/// mPedLookFor - ped to look for
|
|
/// eBodyPart - set specific body part to check can be seen, default picks part at random
|
|
/// RETURNS:
|
|
/// true or false
|
|
FUNC BOOL CAN_HELI_SEE_PED(VEHICLE_INDEX mHeli, PED_INDEX mPedLookFor, INT iGrace = 250, THREAT_TEST_BODY_PART_ENUM eBodyPart = TT_BODY_PART_RANDOM)
|
|
INT iSlot = GET_THREAT_SLOT(mHeli, mPedLookFor)
|
|
|
|
// dead people can't see things - bail
|
|
IF NOT IS_ENTITY_ALIVE(mHeli)
|
|
OR NOT IS_ENTITY_ALIVE(mPedLookFor)
|
|
IF (iSlot <> -1)
|
|
RESET_THREAT_SLOT(mThreatSlot[iSlot])
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (iSlot = -1)
|
|
iSlot = GET_EMPTY_THREAT_SLOTS()
|
|
IF (iSlot = -1)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
mThreatSlot[iSlot].mSeeker = mHeli
|
|
mThreatSlot[iSlot].mTarget = mPedLookFor
|
|
ENDIF
|
|
|
|
BOOL bOK = CAN_POINT_SEE_PED_SHAPETEST_RETURN_TIME(mThreatSlot[iSlot].mShapeTest, GET_ENTITY_COORDS(mHeli), mPedLookFor, mThreatSlot[iSlot].iLastSightTime, mHeli, eBodyPart)
|
|
RETURN (bOk) OR ((GET_GAME_TIMER() - mThreatSlot[iSlot].iLastSightTime) < iGrace)
|
|
ENDFUNC
|
|
|
|
//----------------------
|
|
// OVERLOAD FUNCTIONS
|
|
//----------------------
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped can see the player (using LOS shape test)
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// seeTime - The Game Timer when we last saw the player
|
|
/// viewCone - The Persons View Cone - Use 0.0 to not worry about viewcone
|
|
/// RETURNS:
|
|
/// true if ped can see player, false otherwise (or if test is still ongoing)
|
|
FUNC BOOL CAN_PED_SEE_PLAYER_RETURN_TIME(PED_INDEX mPed, INT &seeTime, FLOAT viewCone = 170.0)
|
|
RETURN CAN_PED_SEE_PED_RETURN_TIME(mPed, PLAYER_PED_ID(), seeTime, viewCone)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped can see the player (using LOS shape test)
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// RETURNS:
|
|
/// true if ped can see player, false otherwise (or if test is still ongoing)
|
|
FUNC BOOL CAN_PED_SEE_PLAYER(PED_INDEX mPed, FLOAT viewCone = 170.0)
|
|
RETURN CAN_PED_SEE_PED(mPed, PLAYER_PED_ID(), viewCone)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped can see the player (using LOS shape test)
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// RETURNS:
|
|
/// true if ped can see player, false otherwise (or if test is still ongoing)
|
|
FUNC BOOL CAN_HELI_SEE_PLAYER(VEHICLE_INDEX mHeli)
|
|
RETURN CAN_HELI_SEE_PED(mHeli, PLAYER_PED_ID())
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped can see the player (using LOS shape test)
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// RETURNS:
|
|
/// true if ped can see player, false otherwise (or if test is still ongoing)
|
|
FUNC BOOL CAN_HELI_PILOT_SEE_PLAYER(PED_INDEX ped)
|
|
RETURN CAN_HELI_SEE_PED(GET_VEHICLE_PED_IS_IN(ped), PLAYER_PED_ID())
|
|
ENDFUNC
|
|
|
|
//----------------------
|
|
// CHECK FUNCTIONS
|
|
//----------------------
|
|
|
|
|
|
FUNC BOOL CAN_PED_SEE_PROJECTILE(PED_INDEX mPed, FLOAT fRange)
|
|
ENTITY_INDEX ent
|
|
VECTOR vPos
|
|
|
|
IF GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(mPed, WEAPONTYPE_GRENADE, fRange, vPos, ent)
|
|
OR GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(mPed, WEAPONTYPE_SMOKEGRENADE, fRange, vPos, ent)
|
|
OR GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(mPed, WEAPONTYPE_BZGAS, fRange, vPos, ent)
|
|
OR GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(mPed, WEAPONTYPE_STICKYBOMB, fRange, vPos, ent)
|
|
OR GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(mPed, WEAPONTYPE_MOLOTOV, fRange, vPos, ent)
|
|
IF IS_POSITION_IN_PED_VIEW_CONE(mPed, vPos, 90)
|
|
CPRINTLN(DEBUG_MISSION, "ped Can see projectile - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a projectile is in an area around a ped
|
|
/// Created to maintain readablity in IS_PLAYER_SHOOTING_NEAR_PED
|
|
/// with the addition of the extra flag to that function bCheckSilencedWep
|
|
/// PARAMS:
|
|
/// mPed -
|
|
/// fRange -
|
|
/// bIgnoreStickyBomb - toggles ignoring a sticky bomb unless it is in a 5 meter radius of the ped
|
|
/// RETURNS:
|
|
/// True if a projectile is in the area around the ped
|
|
FUNC BOOL CHECK_PROJECTILE_IN_RANGE(PED_INDEX mPed, FLOAT fRange, BOOL bIgnoreStickyBomb = FALSE, BOOL bCheckCanSeeProjectile = FALSE)
|
|
VECTOR vMin, vMax // is one of the player's projectiles nearby?
|
|
vMin = GET_ENTITY_COORDS(mPed)
|
|
vMax = vMin
|
|
vMin.x= vMin.x - fRange
|
|
vMin.y = vMin.y -fRange
|
|
vMin.z = vMin.z - fRange
|
|
vMax.x = vMax.x + fRange
|
|
vMax.y = vMax.y + fRange
|
|
vMax.z = vMax.z + fRange
|
|
|
|
IF bIgnoreStickyBomb
|
|
|
|
IF IS_PROJECTILE_TYPE_WITHIN_DISTANCE(GET_ENTITY_COORDS(mPed), WEAPONTYPE_GRENADE, fRange, TRUE)
|
|
OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE(GET_ENTITY_COORDS(mPed), WEAPONTYPE_MOLOTOV, fRange, TRUE)
|
|
OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE(GET_ENTITY_COORDS(mPed), WEAPONTYPE_SMOKEGRENADE, fRange, TRUE)
|
|
OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE(GET_ENTITY_COORDS(mPed), WEAPONTYPE_STICKYBOMB, 5, TRUE)
|
|
IF bCheckCanSeeProjectile
|
|
IF CAN_PED_SEE_PROJECTILE(mPed, fRange)
|
|
RETURN TRUE
|
|
ELSE
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
CPRINTLN(DEBUG_MISSION, "projectile is in distance of ped (ignore stickys) - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
IF bCheckCanSeeProjectile
|
|
IF CAN_PED_SEE_PROJECTILE(mPed, fRange)
|
|
RETURN TRUE
|
|
ELSE
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_PROJECTILE_IN_AREA(vMin, vMax, TRUE)
|
|
CPRINTLN(DEBUG_MISSION, "projectile is in distance of ped - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Checks to see if the player is shooting in range if the ped scares
|
|
/// easily
|
|
///
|
|
/// Created to maintain readablity in IS_PLAYER_SHOOTING_NEAR_PED
|
|
/// with the addition of the extra flag to that function bCheckSilencedWep
|
|
/// PARAMS:
|
|
/// bIsEasilyScared -
|
|
/// fRangeRad -
|
|
/// fRangeArea -
|
|
/// RETURNS:
|
|
///
|
|
FUNC BOOL CHECK_BULLET_SHOOTING_IN_AREA(PED_INDEX mPed, BOOL bIsEasilyScared, FLOAT fRangeRad, FLOAT fRangeArea)
|
|
IF bIsEasilyScared
|
|
IF IS_PED_SHOOTING(PLAYER_PED_ID()) // is player shooting nearby?
|
|
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), mPed, <<fRangeArea,fRangeArea,fRangeArea>>)
|
|
CPRINTLN(DEBUG_MISSION, "Player shooting near ped - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_BULLET_IN_AREA(GET_ENTITY_COORDS(mPed), fRangeRad, TRUE) // is one of the player's bullets nearby?
|
|
CPRINTLN(DEBUG_MISSION, "Player Bullet near ped - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player is shooting near the RC ped
|
|
/// This is used to stop the RC missions triggering if the player spooks the RC ped.
|
|
/// Also used to fail non-violent RC missions.
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// bCheckSilencedWep - If true the player weapon is checked for a silencer
|
|
/// and the player has to fire past the ped at a very close range to trigger
|
|
/// a reaction
|
|
/// RETURNS:
|
|
/// true if the player is shooting near the ped
|
|
FUNC BOOL IS_PLAYER_SHOOTING_NEAR_PED(PED_INDEX mPed, BOOL bIsEasilyScared = TRUE, BOOL bCheckSilencedWep = FALSE, BOOL bIgnoreStickyBomb = FALSE, BOOL bCheckCanSeeProjectile = FALSE)
|
|
|
|
FLOAT BULLET_AREA_RADIUS = 8.0
|
|
FLOAT PROJECTILE_AREA_RADIUS = 15.0
|
|
|
|
IF bIsEasilyScared = FALSE
|
|
BULLET_AREA_RADIUS = 1.86
|
|
PROJECTILE_AREA_RADIUS = 1.86
|
|
ENDIF
|
|
|
|
IF bCheckSilencedWep
|
|
BULLET_AREA_RADIUS = 2
|
|
ENDIF
|
|
|
|
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
|
|
AND IS_ENTITY_ALIVE(mPed)
|
|
|
|
WEAPON_TYPE current_player_weapon
|
|
GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), current_player_weapon)
|
|
IF current_player_weapon = WEAPONTYPE_PETROLCAN // See B*887171
|
|
BULLET_AREA_RADIUS = 3
|
|
PROJECTILE_AREA_RADIUS = 3
|
|
ENDIF
|
|
|
|
IF NOT bCheckSilencedWep
|
|
IF CHECK_BULLET_SHOOTING_IN_AREA(mPed, bIsEasilyScared, BULLET_AREA_RADIUS, PROJECTILE_AREA_RADIUS)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF CHECK_PROJECTILE_IN_RANGE(mPed, PROJECTILE_AREA_RADIUS, bIgnoreStickyBomb, bCheckCanSeeProjectile)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
//New addition
|
|
IF IS_PED_CURRENT_WEAPON_SILENCED(PLAYER_PED_ID())
|
|
IF IS_PED_SHOOTING(PLAYER_PED_ID()) // is player shooting nearby?
|
|
IF IS_BULLET_IN_AREA( GET_ENTITY_COORDS(mPed), BULLET_AREA_RADIUS)
|
|
CPRINTLN(DEBUG_MISSION, "Bullet in area of ped (silenced) - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF bIsEasilyScared
|
|
BULLET_AREA_RADIUS = 1.86
|
|
PROJECTILE_AREA_RADIUS = 1.86
|
|
ENDIF
|
|
|
|
IF CHECK_BULLET_SHOOTING_IN_AREA(mPed, bIsEasilyScared, BULLET_AREA_RADIUS, PROJECTILE_AREA_RADIUS) // is one of the player's bullets nearby?
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF CHECK_PROJECTILE_IN_RANGE(mPed, PROJECTILE_AREA_RADIUS, bIgnoreStickyBomb, bCheckCanSeeProjectile)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if anyone is shooting near the RC ped
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// RETURNS:
|
|
/// true if anyone is shooting near the ped
|
|
FUNC BOOL IS_ANYONE_SHOOTING_NEAR_PED(PED_INDEX mPed, FLOAT BULLET_AREA_RADIUS = 8.0, FLOAT PROJECTILE_AREA_RADIUS = 15.0)
|
|
IF IS_ENTITY_ALIVE(mPed)
|
|
IF IS_BULLET_IN_AREA(GET_ENTITY_COORDS(mPed), BULLET_AREA_RADIUS, FALSE) // are anyone's bullets nearby?
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF CHECK_PROJECTILE_IN_RANGE(mPed,PROJECTILE_AREA_RADIUS)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player is armed and aiming a weapon at a ped.
|
|
/// Needed because IS_PLAYER_FREE_AIMING_AT_ENTITY will return true even if the player is unarmed and pressing L2 near a ped in their group - Causing bugs like 1293303.
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
FUNC BOOL IS_PLAYER_FREE_AIMING_WEAPON_AT_PED(PED_INDEX mPed)
|
|
|
|
IF IS_PLAYER_FREE_AIMING_AT_ENTITY(PLAYER_ID(), mPed)
|
|
AND IS_PED_ARMED(PLAYER_PED_ID(), WF_INCLUDE_GUN|WF_INCLUDE_PROJECTILE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped can see that the player is aiming a weapon at them
|
|
/// PARAMS:
|
|
/// mPed - the ped we are checking
|
|
/// fViewCone - angle that player has to be targetting in before this fails
|
|
/// RETURNS:
|
|
/// True if the player is targetting the ped, and the ped can see them
|
|
FUNC BOOL IS_PLAYER_VISIBLY_TARGETTING_PED(PED_INDEX mPed, FLOAT fViewCone = 170.0)
|
|
|
|
FLOAT fTargettingDist
|
|
|
|
if IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(mPed)
|
|
IF IS_PLAYER_FREE_AIMING_WEAPON_AT_PED(mPed)
|
|
OR IS_PLAYER_TARGETTING_ENTITY(PLAYER_ID(), mPed)
|
|
|
|
// player is targetting ped, set targetting dist based on whether he is using melee or ranged attack
|
|
IF IS_PED_ARMED(PLAYER_PED_ID(), WF_INCLUDE_GUN|WF_INCLUDE_PROJECTILE)
|
|
fTargettingDist = 40.0 // ranged distance
|
|
ELSE
|
|
fTargettingDist = 3.0 // melee distance
|
|
ENDIF
|
|
|
|
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), mPed, <<fTargettingDist, fTargettingDist, fTargettingDist>>, FALSE) // player is nearby
|
|
IF CAN_PED_SEE_PLAYER(mPed, fViewCone) // player can be seen by other ped
|
|
CPRINTLN(DEBUG_MISSION, "Player targeting ped - ", GET_THIS_SCRIPT_NAME())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player has threatened a ped by shooting near them, damaging them or targetting them.
|
|
/// PARAMS:
|
|
/// mPed - the ped that the player might have threatened
|
|
/// bIsEasilyScared - if this is true we worry about scaredness
|
|
/// fMeleeAngle - angle that players has to be meleeing in before this fails
|
|
/// fViewCone - angle that player has to be targetting in before this fails
|
|
/// bIgnoreAiming - This ped doesn't mind you aiming at them if set to TRUE
|
|
/// bCheckSilencedWep - If true the player weapon is checked for a silencer
|
|
/// and the player has to fire past the ped at a very close range to trigger
|
|
/// a reaction
|
|
/// RETURNS:
|
|
/// true if the player has scared the ped, false otherwise
|
|
FUNC BOOL HAS_PLAYER_THREATENED_PED(PED_INDEX mPed, BOOL bIsEasilyScared = TRUE, FLOAT fMeleeAngle = 70.0, FLOAT fViewCone = 170.0, BOOL bIgnoreAiming = FALSE, BOOL bCheckSilencedWep = FALSE, BOOL bIgnoreStickyBomb = FALSE, BOOL bCheckCanSeeProjectile = FALSE)
|
|
VECTOR v
|
|
|
|
IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(mPed)
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(mPed, PLAYER_PED_ID())
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF IS_PLAYER_SHOOTING_NEAR_PED(mPed, bIsEasilyScared, bCheckSilencedWep, bIgnoreStickyBomb, bCheckCanSeeProjectile)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF NOT IS_PED_ARMED(PLAYER_PED_ID(), WF_INCLUDE_GUN|WF_INCLUDE_PROJECTILE)
|
|
IF IS_PED_IN_MELEE_COMBAT(PLAYER_PED_ID())
|
|
|
|
// get the squared distance between the player and the ped (2.5^2 is roughly 5)
|
|
v = GET_ENTITY_COORDS(PLAYER_PED_ID()) - GET_ENTITY_COORDS(mPed)
|
|
IF ((v.x * v.x + v.y * v.y + v.z * v.z) <= 5.0)
|
|
RETURN IS_ENTITY_IN_ARC_2D(PLAYER_PED_ID(), mPed, fMeleeAngle)
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF bIgnoreAiming
|
|
RETURN FALSE
|
|
ELIF IS_PLAYER_VISIBLY_TARGETTING_PED(mPed, fViewCone)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped is in a vehicle and has bumped into a specific ped
|
|
/// PARAMS:
|
|
/// hPedInVehicle - ped index of the ped who may have driven into other peds
|
|
/// hPossiblyBumpedPed - ped index of the ped who may have been driven into
|
|
/// bTestRagdolling - do we need to test if hPossiblyBumpedPed is ragdolling or not
|
|
/// RETURNS:
|
|
/// TRUE if hPedInVehicle has bumped into hPossiblyBumpedPed with a vehicle
|
|
/// if bTestRagdolling is true, it returns TRUE if hPedInVehicle has bumped into hPossiblyBumpedPed with a vehicle and hPossiblyBumpedPed is ragdolling
|
|
FUNC BOOL HAS_PED_BUMPED_PED_WITH_VEHICLE(PED_INDEX hPedInVehicle, PED_INDEX hPossiblyBumpedPed, BOOL bTestRagdolling = TRUE)
|
|
|
|
IF IS_PED_UNINJURED(hPedInVehicle) AND IS_PED_IN_ANY_VEHICLE(hPedInVehicle)
|
|
|
|
IF IS_PED_UNINJURED(hPossiblyBumpedPed)
|
|
IF IS_ENTITY_TOUCHING_ENTITY(hPossiblyBumpedPed, hPedInVehicle)
|
|
IF bTestRagdolling
|
|
IF IS_PED_RAGDOLL(hPossiblyBumpedPed)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a ped is in a vehicle and has knocked any other peds of balance by bumping it into them
|
|
/// PARAMS:
|
|
/// hPedInVehicle - ped index of the ped who may have driven into other peds
|
|
/// RETURNS:
|
|
/// TRUE if hPedInVehicle has bumped into another ped with a vehicle
|
|
/// if bTestRagdolling is true, it returns TRUE if hPedInVehicle has bumped into another ped with a vehicle and that ped is ragdolling
|
|
FUNC BOOL HAS_PED_BUMPED_ANY_PED_WITH_VEHICLE(PED_INDEX hPedInVehicle, BOOL bTestRagdolling = TRUE)
|
|
|
|
IF IS_PED_IN_ANY_VEHICLE(hPedInVehicle)
|
|
PED_INDEX pedsNearPlayer[16]
|
|
GET_PED_NEARBY_PEDS(hPedInVehicle, pedsNearPlayer)
|
|
|
|
INT i
|
|
FOR i = 0 TO ( COUNT_OF(pedsNearPlayer) - 1 )
|
|
|
|
IF IS_PED_UNINJURED(pedsNearPlayer[i])
|
|
IF IS_ENTITY_TOUCHING_ENTITY(pedsNearPlayer[i], hPedInVehicle)
|
|
IF bTestRagdolling
|
|
IF IS_PED_RAGDOLL(pedsNearPlayer[i])
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDFOR
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Initialises the external variables used by HAS_PLAYER_RAMMED_ENEMY_ENOUGH
|
|
/// PARAMS:
|
|
/// bRammedLastFrame - Keeps track of whether or not the player was touching the enemy vehicle in the previous frame, initialised to FALSE
|
|
/// iRamTimer - Triggers the ramming check every 500ms, initialised to zero
|
|
/// iRammedCount - Keeps track of how many times the player has rammed the enemy vehicle, initialised to zero
|
|
/// fClosingSpeedLastFrame - Keeps track of the relative velocity of the player and enemy in the previous frame, initialised to zero
|
|
PROC INIT_HAS_PLAYER_RAMMED_ENEMY_ENOUGH(BOOL & bRammedLastFrame, INT & iRamTimer, INT & iRammedCount, FLOAT & fClosingSpeedLastFrame)
|
|
bRammedLastFrame = FALSE
|
|
iRamTimer = 0
|
|
iRammedCount = 0
|
|
fClosingSpeedLastFrame = 0.0
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Keeps track of how many times the player has rammed another vehicle
|
|
/// PARAMS:
|
|
/// viEnemy - The vehicle we're testing if the player has rammed
|
|
/// bRammedLastFrame - Keeps track of whether or not the player was touching the enemy vehicle in the previous frame
|
|
/// iRamTimer - Triggers the ramming check every 500ms
|
|
/// iRammedCount - Keeps track of how many times the player has rammed the enemy vehicle
|
|
/// fClosingSpeedLastFrame - Keeps track of the relative velocity of the player and enemy in the previous frame
|
|
/// MAX_NUM_RAMS - The number of times the player must ram the enemy vehicle
|
|
/// MIN_CLOSING_SPEED - The player must be travelling faster than this, relative to the enemy vehicle, for the collision to count. Reduce this value to make it easier
|
|
/// RETURNS:
|
|
/// TRUE when the player has rammed the enemy vehicle enough times
|
|
FUNC BOOL HAS_PLAYER_RAMMED_ENEMY_ENOUGH(VEHICLE_INDEX viEnemy, BOOL & bRammedLastFrame, INT & iRamTimer, INT & iRammedCount, FLOAT & fClosingSpeedLastFrame, INT MAX_NUM_RAMS = 6, FLOAT MIN_CLOSING_SPEED = 4.0)
|
|
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
// Count number of times the van has been rammed with enough force
|
|
VEHICLE_INDEX vehPlayer = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
|
|
IF IS_ENTITY_TOUCHING_ENTITY(vehPlayer, viEnemy)
|
|
IF NOT bRammedLastFrame
|
|
AND GET_GAME_TIMER() - iRamTimer > 500
|
|
AND fClosingSpeedLastFrame >= MIN_CLOSING_SPEED // check the closing speed was high enough the prev frame to register a collision (using the last frame due to the velocities already having been resolved by the physics engine)
|
|
bRammedLastFrame = TRUE
|
|
iRammedCount++
|
|
|
|
IF iRammedCount >= MAX_NUM_RAMS
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF bRammedLastFrame
|
|
iRamTimer = GET_GAME_TIMER()
|
|
bRammedLastFrame = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Calculate closing velocity for this frame
|
|
VECTOR vContactNormal = NORMALISE_VECTOR(GET_ENTITY_COORDS(vehPlayer) - GET_ENTITY_COORDS(viEnemy))
|
|
VECTOR vVelBMinusVelA = GET_ENTITY_VELOCITY(viEnemy) - GET_ENTITY_VELOCITY(vehPlayer)
|
|
fClosingSpeedLastFrame = DOT_PRODUCT(vVelBMinusVelA, vContactNormal)
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|