1464 lines
57 KiB
Scheme
Executable File
1464 lines
57 KiB
Scheme
Executable File
|
|
|
|
USING "commands_debug.sch"
|
|
USING "commands_object.sch"
|
|
USING "commands_ped.sch"
|
|
USING "commands_task.sch"
|
|
USING "Script_player.sch"
|
|
USING "commands_interiors.sch"
|
|
USING "commands_path.sch"
|
|
USING "commands_camera.sch"
|
|
USING "commands_streaming.sch"
|
|
//USING "Minigame_private.sch"
|
|
|
|
|
|
ENUM ECOMPASS
|
|
ECOMPASS_NORTH = 0,
|
|
ECOMPASS_EAST,
|
|
ECOMPASS_WEST,
|
|
ECOMPASS_SOUTH
|
|
ENDENUM
|
|
|
|
ENUM ESIDESHIFT
|
|
ESIDESHIFT_LEFT = 0,
|
|
ESIDESHIFT_RIGHT,
|
|
ESIDESHIFT_NONE
|
|
ENDENUM
|
|
|
|
ENUM EACTIVESIDE
|
|
EACTIVESIDE_ONEWAY = 0,
|
|
EACTIVESIDE_OPPOSITES,
|
|
EACTIVESIDE_FOURCORNERS
|
|
ENDENUM
|
|
|
|
ENUM EACTIVEAPPROACH
|
|
EACTIVEAPPROACH_FRONT = 0,
|
|
EACTIVEAPPROACH_BACK,
|
|
EACTIVEAPPROACH_LEFT,
|
|
EACTIVEAPPROACH_RIGHT,
|
|
EACTIVEAPPROACH_ALLDIAGONALS,
|
|
EACTIVEAPPROACH_FRONTLEFT,
|
|
EACTIVEAPPROACH_FRONTRIGHT,
|
|
EACTIVEAPPROACH_BACKLEFT,
|
|
EACTIVEAPPROACH_BACKRIGHT
|
|
ENDENUM
|
|
|
|
ENUM EACTIVATIONEASE
|
|
EACTIVATIONEASE_HARD =0,
|
|
EACTIVATIONEASE_MEDIUM,
|
|
EACTIVATIONEASE_EASY
|
|
ENDENUM
|
|
|
|
PROC DrawDebug(ENTITY_INDEX anEntity, BOOL GreenLine, ESIDESHIFT ShiftDirection = ESIDESHIFT_NONE)
|
|
IF ShiftDirection = ESIDESHIFT_NONE ENDIF
|
|
IF GreenLine ENDIF
|
|
|
|
IF DOES_ENTITY_EXIST(anEntity)
|
|
#IF IS_DEBUG_BUILD
|
|
VECTOR PlayerPosition = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
VECTOR anObjectPosition = GET_ENTITY_COORDS(anEntity)
|
|
//// FLOAT PlayerHeading = GET_ENTITY_HEADING(PLAYER_PED_ID())
|
|
//// FLOAT anObjectHeading = GET_ENTITY_HEADING(anEntity)
|
|
|
|
IF ShiftDirection = ESIDESHIFT_LEFT
|
|
anObjectPosition = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(anEntity, <<-0.5, 0, 0>>)
|
|
ELIF ShiftDirection = ESIDESHIFT_RIGHT
|
|
anObjectPosition = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(anEntity, <<0.5, 0, 0>>)
|
|
ENDIF
|
|
|
|
INTERIOR_INSTANCE_INDEX ObjectInterior = GET_INTERIOR_FROM_ENTITY(anEntity)
|
|
INTERIOR_INSTANCE_INDEX PlayerInterior = GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID())
|
|
|
|
IF ObjectInterior = PlayerInterior
|
|
IF IS_ENTITY_AT_ENTITY(anEntity, PLAYER_PED_ID(), <<7.0, 7.0, 7.0>>)
|
|
IF GreenLine = TRUE
|
|
DRAW_DEBUG_LINE(PlayerPosition, anObjectPosition, 0, 255, 0, 255) //Green Line
|
|
ELSE
|
|
DRAW_DEBUG_LINE(PlayerPosition, anObjectPosition, 255, 0, 0, 255) //Red Line
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
#ENDIF
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
|
|
PROC DrawDebugPed(PED_INDEX Ped, BOOL GreenLine)
|
|
IF GreenLine ENDIF
|
|
IF NOT IS_ENTITY_DEAD(Ped)
|
|
#IF IS_DEBUG_BUILD
|
|
VECTOR PlayerPosition = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
VECTOR PedPosition = GET_ENTITY_COORDS(Ped)
|
|
//// FLOAT PlayerHeading = GET_ENTITY_HEADING(PLAYER_PED_ID())
|
|
//// FLOAT PedHeading = GET_ENTITY_HEADING(Ped)
|
|
|
|
INTERIOR_INSTANCE_INDEX PedInterior = GET_INTERIOR_FROM_ENTITY(Ped)
|
|
INTERIOR_INSTANCE_INDEX PlayerInterior = GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID())
|
|
|
|
IF PedInterior = PlayerInterior
|
|
IF IS_ENTITY_AT_ENTITY(Ped, PLAYER_PED_ID(), <<7.0, 7.0, 7.0>>)
|
|
IF GreenLine = TRUE
|
|
DRAW_DEBUG_LINE(PlayerPosition, PedPosition, 0, 255, 0, 255) //Green Line
|
|
ELSE
|
|
DRAW_DEBUG_LINE(PlayerPosition, PedPosition, 255, 0, 0, 255) //Red Line
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
#ENDIF
|
|
ELSE
|
|
#IF IS_DEBUG_BUILD
|
|
// Display_Minigame_Assert_Message_Header()
|
|
SCRIPT_ASSERT("DrawDebugPed is using a dead ped - See Brenda")
|
|
// Display_Minigame_Assert_Message_Footer()
|
|
#ENDIF
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
FUNC BOOL priv_PlayerMoveStateAcceptable(BOOL playerCanBeStill)
|
|
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
|
|
IF playerCanBeStill
|
|
|
|
IF (GET_PED_DESIRED_MOVE_BLEND_RATIO(PLAYER_PED_ID()) = PEDMOVEBLENDRATIO_WALK) OR (GET_PED_DESIRED_MOVE_BLEND_RATIO(PLAYER_PED_ID()) = PEDMOVEBLENDRATIO_STILL)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
IF (GET_PED_DESIRED_MOVE_BLEND_RATIO(PLAYER_PED_ID()) = PEDMOVEBLENDRATIO_WALK)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL priv_ObjectActivationCriteriaMet(OBJECT_INDEX activeObject, VECTOR activationOffset, FLOAT activationAngle, FLOAT locateSize, BOOL CareIfUpright, BOOL playerCanBeStill)
|
|
FLOAT locateZ
|
|
IF locateSize < 1
|
|
locateZ = 1+0.5
|
|
ELSE
|
|
locateZ = locateSize+0.5
|
|
ENDIF
|
|
VECTOR vLocateSize = <<(locateSize+0.2), (locateSize+0.2), locateZ>>
|
|
IF NOT IS_ENTITY_DEAD(activeObject)
|
|
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(activeObject, activationOffset), vLocateSize, FALSE, TRUE)
|
|
AND IS_PED_HEADING_TOWARDS_POSITION(PLAYER_PED_ID(), GET_ENTITY_COORDS(activeObject), activationAngle)
|
|
AND priv_PlayerMoveStateAcceptable(playerCanBeStill)
|
|
AND IS_PED_ON_FOOT(PLAYER_PED_ID())
|
|
IF CareIfUpright
|
|
IF IS_ENTITY_UPRIGHT(activeObject, 60)
|
|
DrawDebug(activeObject, TRUE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
DrawDebug(activeObject, TRUE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
ELSE
|
|
DrawDebug(activeObject, FALSE)
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
SCRIPT_ASSERT("priv_ObjectActivationCriteriaMet: is using an object that doesn't exist")
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Gets Heading given 2 coords
|
|
/// PARAMS:
|
|
/// oldCoords - source point
|
|
/// newCoords - target point
|
|
/// invert - this is true (just keep it as true)
|
|
/// RETURNS:
|
|
/// Heading
|
|
FUNC FLOAT GET_HEADING_FROM_COORDS_LA(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:
|
|
/// Gets Heading from 1 entity to another
|
|
/// PARAMS:
|
|
/// oldEnd - source entity
|
|
/// newEnd - target entity
|
|
/// invert - this is true (just keep it as true)
|
|
/// RETURNS:
|
|
/// Heading
|
|
FUNC FLOAT GET_HEADING_FROM_ENTITIES_LA(entity_index oldEnd, entity_index newEnt, bool invert=true)
|
|
vector v1,v2
|
|
v1 = GET_ENTITY_COORDS(oldEnd,FALSE)
|
|
v2 = GET_ENTITY_COORDS(newEnt,FALSE)
|
|
RETURN GET_HEADING_FROM_COORDS_LA(v1,v2, invert)
|
|
ENDFUNC
|
|
|
|
FUNC BOOL priv_EntityActivationCriteriaMet(ENTITY_INDEX activeEntity, VECTOR activationOffset, FLOAT activationAngle, FLOAT locateSize, BOOL CareIfUpright, BOOL playerCanBeStill)
|
|
FLOAT locateZ
|
|
IF locateSize < 1
|
|
locateZ = 1+0.5
|
|
ELSE
|
|
locateZ = locateSize+0.5
|
|
ENDIF
|
|
VECTOR vLocateSize = <<(locateSize+0.2), (locateSize+0.2), locateZ>>
|
|
IF NOT IS_ENTITY_DEAD(activeEntity)
|
|
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(activeEntity, activationOffset), vLocateSize, FALSE, TRUE)
|
|
AND IS_PED_HEADING_TOWARDS_POSITION(PLAYER_PED_ID(), GET_ENTITY_COORDS(activeEntity), activationAngle)
|
|
AND priv_PlayerMoveStateAcceptable(playerCanBeStill)
|
|
AND IS_PED_ON_FOOT(PLAYER_PED_ID())
|
|
IF CareIfUpright
|
|
IF IS_ENTITY_UPRIGHT(activeEntity, 60)
|
|
DrawDebug(activeEntity, TRUE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
DrawDebug(activeEntity, TRUE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
ELSE
|
|
DrawDebug(activeEntity, FALSE)
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
SCRIPT_ASSERT("priv_ObjectActivationCriteriaMet: is using an object that doesn't exist")
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC VECTOR APPROACH_OFFSET(ECOMPASS direction, EACTIVEAPPROACH approach, FLOAT locateSize)
|
|
VECTOR offset
|
|
SWITCH approach
|
|
CASE EACTIVEAPPROACH_FRONT
|
|
IF Direction = ECOMPASS_NORTH
|
|
Offset = <<0, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_EAST
|
|
Offset = <<LocateSize,0 , 0>>
|
|
ELIF Direction = ECOMPASS_SOUTH
|
|
Offset = <<0, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_WEST
|
|
Offset = <<-LocateSize, 0, 0>>
|
|
ENDIF
|
|
BREAK
|
|
CASE EACTIVEAPPROACH_BACK
|
|
IF Direction = ECOMPASS_SOUTH
|
|
Offset = <<0, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_WEST
|
|
Offset = <<LocateSize,0 , 0>>
|
|
ELIF Direction = ECOMPASS_NORTH
|
|
Offset = <<0, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_EAST
|
|
Offset = <<-LocateSize, 0, 0>>
|
|
ENDIF
|
|
BREAK
|
|
CASE EACTIVEAPPROACH_LEFT
|
|
IF Direction = ECOMPASS_WEST
|
|
Offset = <<0, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_SOUTH
|
|
Offset = <<LocateSize,0 , 0>>
|
|
ELIF Direction = ECOMPASS_EAST
|
|
Offset = <<0, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_NORTH
|
|
Offset = <<-LocateSize, 0, 0>>
|
|
ENDIF
|
|
BREAK
|
|
CASE EACTIVEAPPROACH_RIGHT
|
|
IF Direction = ECOMPASS_EAST
|
|
Offset = <<0, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_NORTH
|
|
Offset = <<LocateSize,0 , 0>>
|
|
ELIF Direction = ECOMPASS_WEST
|
|
Offset = <<0, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_SOUTH
|
|
Offset = <<-LocateSize, 0, 0>>
|
|
ENDIF
|
|
BREAK
|
|
|
|
//Diagonal approaches
|
|
CASE EACTIVEAPPROACH_FRONTLEFT
|
|
IF Direction = ECOMPASS_EAST
|
|
Offset = <<LocateSize, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_NORTH
|
|
Offset = <<-LocateSize,LocateSize , 0>>
|
|
ELIF Direction = ECOMPASS_SOUTH
|
|
Offset = <<LocateSize, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_WEST
|
|
Offset = <<-LocateSize, -LocateSize, 0>>
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE EACTIVEAPPROACH_FRONTRIGHT
|
|
IF Direction = ECOMPASS_NORTH
|
|
Offset = <<LocateSize, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_WEST
|
|
Offset = <<-LocateSize,LocateSize , 0>>
|
|
ELIF Direction = ECOMPASS_EAST
|
|
Offset = <<LocateSize, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_SOUTH
|
|
Offset = <<-LocateSize, -LocateSize, 0>>
|
|
ENDIF
|
|
|
|
BREAK
|
|
|
|
CASE EACTIVEAPPROACH_BACKLEFT
|
|
IF Direction = ECOMPASS_SOUTH
|
|
Offset = <<LocateSize, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_EAST
|
|
Offset = <<-LocateSize,LocateSize , 0>>
|
|
ELIF Direction = ECOMPASS_WEST
|
|
Offset = <<LocateSize, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_NORTH
|
|
Offset = <<-LocateSize, -LocateSize, 0>>
|
|
ENDIF
|
|
|
|
BREAK
|
|
|
|
CASE EACTIVEAPPROACH_BACKRIGHT
|
|
IF Direction = ECOMPASS_WEST
|
|
Offset = <<LocateSize, LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_SOUTH
|
|
Offset = <<-LocateSize,LocateSize , 0>>
|
|
ELIF Direction = ECOMPASS_NORTH
|
|
Offset = <<LocateSize, -LocateSize, 0>>
|
|
ELIF Direction = ECOMPASS_EAST
|
|
Offset = <<-LocateSize, -LocateSize, 0>>
|
|
ENDIF
|
|
|
|
BREAK
|
|
|
|
ENDSWITCH
|
|
IF LocateSize < 0
|
|
LocateSize *=-1
|
|
ENDIF
|
|
RETURN offset
|
|
ENDFUNC
|
|
|
|
|
|
//// PURPOSE:
|
|
/// Is player activating an object by approaching it
|
|
/// PARAMS:
|
|
/// anObject - The object the player will be interacting with
|
|
/// RETURNS:
|
|
/// Returns true if the player is activating an object
|
|
FUNC BOOL IS_PLAYER_ACTIVATING_OBJECT(OBJECT_INDEX anObject, ECOMPASS Direction = ECOMPASS_SOUTH, FLOAT LocateSize = 0.4, BOOL CareIfUpright = TRUE, EACTIVESIDE activeSide = EACTIVESIDE_ONEWAY, EACTIVATIONEASE Ease_of_activation = EACTIVATIONEASE_HARD, BOOL Check_Stationary = FALSE)
|
|
|
|
// VECTOR Offset
|
|
|
|
FLOAT EaseOfActivation
|
|
IF Ease_of_activation = EACTIVATIONEASE_EASY
|
|
EaseOfActivation = 150.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_MEDIUM
|
|
EaseOfActivation = 100.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_HARD
|
|
EaseOfActivation = 40.0
|
|
ENDIF
|
|
|
|
// Checks will fallthru to the default activation side, EACTIVESIDE_ONEWAY
|
|
SWITCH activeSide
|
|
CASE EACTIVESIDE_FOURCORNERS
|
|
///Left Corner
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_LEFT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Right Corner
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_RIGHT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//front left Diagonals Corner
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTLEFT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//front right Diagonals Corner
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTRIGHT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back left Diagonals Corner
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKLEFT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back right Diagonals Corner
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKRIGHT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_OPPOSITES
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACK, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_ONEWAY
|
|
IF priv_ObjectActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
//// PURPOSE:
|
|
/// Is player activating an object by approaching it
|
|
/// PARAMS:
|
|
/// anObject - The object the player will be interacting with
|
|
/// RETURNS:
|
|
/// Returns true if the player is activating an object
|
|
FUNC BOOL IS_PLAYER_ACTIVATING_ENTITY(ENTITY_INDEX anEntity, ECOMPASS Direction = ECOMPASS_SOUTH, FLOAT LocateSize = 0.4, BOOL CareIfUpright = TRUE, EACTIVESIDE activeSide = EACTIVESIDE_ONEWAY, EACTIVATIONEASE Ease_of_activation = EACTIVATIONEASE_HARD, BOOL Check_Stationary = FALSE)
|
|
|
|
// VECTOR Offset
|
|
|
|
FLOAT EaseOfActivation
|
|
IF Ease_of_activation = EACTIVATIONEASE_EASY
|
|
EaseOfActivation = 150.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_MEDIUM
|
|
EaseOfActivation = 100.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_HARD
|
|
EaseOfActivation = 40.0
|
|
ENDIF
|
|
|
|
// Checks will fallthru to the default activation side, EACTIVESIDE_ONEWAY
|
|
SWITCH activeSide
|
|
CASE EACTIVESIDE_FOURCORNERS
|
|
///Left Corner
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_LEFT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Right Corner
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_RIGHT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Front left diagonal corner
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTLEFT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Front right diagonal corner
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTRIGHT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back left diagonal corner
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKLEFT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back right diagonal corner
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKRIGHT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_OPPOSITES
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACK, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_ONEWAY
|
|
IF priv_EntityActivationCriteriaMet(anEntity, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONT, locateSize), EaseOfActivation, LocateSize, CareIfUpright, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL priv_PedActivationCriteriaMet(PED_INDEX activePed, VECTOR activationOffset, FLOAT activationAngle, FLOAT locateSize, BOOL playerCanBeStill)
|
|
FLOAT locateZ
|
|
IF locateSize < 1
|
|
locateZ = 1+0.5
|
|
ELSE
|
|
locateZ = locateSize+0.5
|
|
ENDIF
|
|
VECTOR vLocateSize = <<(locateSize+0.2), (locateSize+0.2), locateZ>>
|
|
|
|
IF NOT IS_PED_INJURED(activePed)
|
|
// Is player close enough to ped to be activated
|
|
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(activePed, activationOffset), vLocateSize, FALSE, TRUE)
|
|
|
|
// Is player facing towards active ped's position
|
|
AND IS_PED_HEADING_TOWARDS_POSITION(PLAYER_PED_ID(), GET_ENTITY_COORDS(activePed), activationAngle)
|
|
|
|
// Is the player's move state acceptable for this activation
|
|
AND priv_PlayerMoveStateAcceptable(playerCanBeStill)
|
|
|
|
// Other checks
|
|
AND NOT IS_PED_RAGDOLL(activePed)
|
|
AND NOT IS_PED_GETTING_UP(activePed)
|
|
DrawDebugPed(activePed, TRUE)
|
|
RETURN TRUE
|
|
ELSE
|
|
DrawDebugPed(activePed, FALSE)
|
|
ENDIF
|
|
ELSE
|
|
SCRIPT_ASSERT("priv_PedActivationCriteriaMet: is using a ped that's dead")
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Is player activating a ped by approaching it
|
|
/// PARAMS:
|
|
/// aPed - The ped the player will be interacting with
|
|
/// RETURNS:
|
|
/// Returns true if the player is interacting with a ped
|
|
FUNC BOOL IS_PLAYER_ACTIVATING_PED(PED_INDEX aPed, ECOMPASS Direction = ECOMPASS_NORTH, FLOAT LocateSize = 0.5, EACTIVESIDE activeSide = EACTIVESIDE_ONEWAY, EACTIVATIONEASE Ease_of_activation = EACTIVATIONEASE_HARD, BOOL Check_stationary = FALSE)
|
|
|
|
// VECTOR Offset
|
|
|
|
FLOAT EaseOfActivation
|
|
|
|
IF Ease_of_activation = EACTIVATIONEASE_EASY
|
|
EaseOfActivation = 150.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_MEDIUM
|
|
EaseOfActivation = 100.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_HARD
|
|
EaseOfActivation = 40.0
|
|
ENDIF
|
|
|
|
// Checks will fallthru to the default activation side, EACTIVESIDE_ONEWAY
|
|
SWITCH activeSide
|
|
CASE EACTIVESIDE_FOURCORNERS
|
|
///Left Corner
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_LEFT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Right Corner
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_RIGHT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Front left diagonal corner
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTLEFT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Front right diagonal corner
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTRIGHT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back left diagonal corner
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKLEFT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back right diagonal corner
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKRIGHT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_OPPOSITES
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACK, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_ONEWAY
|
|
IF priv_PedActivationCriteriaMet(aPed, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC VECTOR GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(VECTOR vPosition, FLOAT fCoordHeading, VECTOR vOffset)
|
|
|
|
VECTOR vOffsetRotated
|
|
FLOAT fHeading = fCoordHeading
|
|
|
|
FLOAT CosHead = COS(fHeading)
|
|
FLOAT SinHead = SIN(fHeading)
|
|
|
|
vOffsetRotated.x = (vOffset.x*CosHead) + (vOffset.y*SinHead)
|
|
vOffsetRotated.y = (vOffset.y*CosHead) - (vOffset.x*SinHead)
|
|
|
|
VECTOR vFinalPos = vPosition + vOffsetRotated
|
|
|
|
RETURN vFinalPos
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL priv_CoordActivationCriteriaMet(VECTOR activeCoord, FLOAT activeHeading, VECTOR activationOffset, FLOAT activationAngle, FLOAT locateSize, BOOL playerCanBeStill)
|
|
FLOAT locateZ
|
|
IF locateSize < 1
|
|
locateZ = 1+0.5
|
|
ELSE
|
|
locateZ = locateSize+0.5
|
|
ENDIF
|
|
VECTOR vLocate = <<(locateSize+0.2), (locateSize+0.2), locateZ>>
|
|
|
|
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(activeCoord, activeHeading, activationOffset), vLocate, FALSE, TRUE)
|
|
AND IS_PED_HEADING_TOWARDS_POSITION(PLAYER_PED_ID(), activeCoord, activationAngle)
|
|
AND priv_PlayerMoveStateAcceptable(playerCanBeStill)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
//// PURPOSE:
|
|
/// Is player activating an object by approaching it
|
|
/// PARAMS:
|
|
/// anObject - The object the player will be interacting with
|
|
/// RETURNS:
|
|
/// Returns true if the player is activating an object
|
|
FUNC BOOL IS_PLAYER_ACTIVATING_COORD(VECTOR Coord, FLOAT CoordHeading, ECOMPASS Direction = ECOMPASS_NORTH, FLOAT LocateSize = 0.4, EACTIVESIDE activeSide = EACTIVESIDE_ONEWAY, EACTIVATIONEASE Ease_of_activation = EACTIVATIONEASE_HARD, BOOL Check_stationary = FALSE)
|
|
|
|
FLOAT EaseOfActivation
|
|
IF Ease_of_activation = EACTIVATIONEASE_EASY
|
|
EaseOfActivation = 150.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_MEDIUM
|
|
EaseOfActivation = 100.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_HARD
|
|
EaseOfActivation = 40.0
|
|
ENDIF
|
|
|
|
// Checks will fallthru to the default activation side, EACTIVESIDE_ONEWAY
|
|
SWITCH activeSide
|
|
CASE EACTIVESIDE_FOURCORNERS
|
|
///Left Corner
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_LEFT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Right Corner
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_RIGHT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Front left diagonal corner
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTLEFT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//Front right diagonal corner
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONTRIGHT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back left diagonal corner
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKLEFT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
//back right diagonal corner
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACKRIGHT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_OPPOSITES
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACK, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_ONEWAY
|
|
IF priv_CoordActivationCriteriaMet(Coord, CoordHeading, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONT, locateSize), EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL priv_DoorActivationCriteriaMet(OBJECT_INDEX activeObject, VECTOR activationOffset, ESIDESHIFT ShiftDirection, FLOAT activationAngle, FLOAT locateSize, BOOL playerCanBeStill)
|
|
VECTOR shiftOffset
|
|
FLOAT locateZ
|
|
IF locateSize < 1
|
|
locateZ = 1+0.5
|
|
ELSE
|
|
locateZ = locateSize+0.5
|
|
ENDIF
|
|
VECTOR vLocate = <<(locateSize+0.2), (locateSize+0.2), locateZ>>
|
|
IF DOES_ENTITY_EXIST(activeObject)
|
|
|
|
IF ShiftDirection = ESIDESHIFT_LEFT
|
|
shiftOffset = <<-0.5, 0, 0>>
|
|
ELIF ShiftDirection = ESIDESHIFT_RIGHT
|
|
shiftOffset = <<0.5, 0, 0>>
|
|
ENDIF
|
|
|
|
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(activeObject, shiftOffset), GET_ENTITY_HEADING(activeObject), activationOffset), vLocate, FALSE, TRUE)
|
|
AND IS_PED_HEADING_TOWARDS_POSITION(PLAYER_PED_ID(), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(activeObject, shiftOffset), activationAngle)
|
|
AND priv_PlayerMoveStateAcceptable(playerCanBeStill)
|
|
DrawDebug(activeObject, TRUE, ShiftDirection)
|
|
RETURN TRUE
|
|
ELSE
|
|
DrawDebug(activeObject, FALSE, ShiftDirection)
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Is the player activiating a door
|
|
/// PARAMS:
|
|
/// anObject - The door object
|
|
/// Direction - Which compass point is the door situated, defaulted to NORTH
|
|
/// ShiftDirection - Does the door open to the left or to the right. The origin of the door is placed at the hinges
|
|
/// activeSide - Will this function return true if player approaches door from both sides or just one
|
|
/// LocateSize - The locate size for the door activation.
|
|
/// RETURNS:
|
|
/// True if the player is wanting to interact with the door
|
|
FUNC BOOL IS_PLAYER_ACTIVATING_DOOR(OBJECT_INDEX anObject, ECOMPASS Direction = ECOMPASS_NORTH, ESIDESHIFT ShiftDirection = ESIDESHIFT_LEFT, EACTIVESIDE activeSide = EACTIVESIDE_ONEWAY, FLOAT LocateSize = 0.4, EACTIVATIONEASE Ease_of_activation = EACTIVATIONEASE_HARD, BOOL Check_Stationary = FALSE )
|
|
|
|
FLOAT EaseOfActivation
|
|
IF Ease_of_activation = EACTIVATIONEASE_EASY
|
|
EaseOfActivation = 150.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_MEDIUM
|
|
EaseOfActivation = 100.0
|
|
ELIF Ease_of_activation = EACTIVATIONEASE_HARD
|
|
EaseOfActivation = 40.0
|
|
ENDIF
|
|
|
|
|
|
// Checks will fallthru to the default activation side, EACTIVESIDE_ONEWAY
|
|
SWITCH activeSide
|
|
CASE EACTIVESIDE_FOURCORNERS
|
|
SCRIPT_ASSERT("IS_PLAYER_ACTIVATING_DOOR - EACTIVESIDE_FOURCORNERS is an unsupported activation type. Use EACTIVESIDE_OPPOSITES or EACTIVESIDE_ONEWAY instead.")
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_OPPOSITES
|
|
IF priv_DoorActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_BACK, locateSize), ShiftDirection, EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
FALLTHRU
|
|
|
|
CASE EACTIVESIDE_ONEWAY
|
|
IF priv_DoorActivationCriteriaMet(anObject, APPROACH_OFFSET(direction, EACTIVEAPPROACH_FRONT, locateSize), ShiftDirection, EaseOfActivation, LocateSize, Check_stationary)
|
|
RETURN TRUE
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL IS_HEADING_ACCEPTABLE(FLOAT fHeading, FLOAT fIdealHeading, FLOAT fLeeway #IF IS_DEBUG_BUILD, BOOL bDebugPrints = FALSE #ENDIF)
|
|
FLOAT fUpperH
|
|
FLOAT fLowerH
|
|
|
|
fLowerH = fIdealHeading - fLeeway
|
|
IF fLowerH < 0.0
|
|
fLowerH += 360.0
|
|
ENDIF
|
|
fUpperH = fIdealHeading + fLeeway
|
|
IF fUpperH >= 360.0
|
|
fUpperH -= 360.0
|
|
ENDIF
|
|
IF fUpperH > fLowerH
|
|
IF fHeading < fUpperH
|
|
AND fHeading > fLowerH
|
|
#IF IS_DEBUG_BUILD
|
|
IF bDebugPrints
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> IS_HEADING_ACCEPTABLE, fHeading = ", fHeading, ", fIdealHeading = ", fIdealHeading, ", RETURN TRUE")
|
|
ENDIF
|
|
#ENDIF
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
IF fHeading < fUpperH
|
|
OR fHeading > fLowerH
|
|
#IF IS_DEBUG_BUILD
|
|
IF bDebugPrints
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> IS_HEADING_ACCEPTABLE, fHeading = ", fHeading, ", fIdealHeading = ", fIdealHeading, ", RETURN TRUE")
|
|
ENDIF
|
|
#ENDIF
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
IF bDebugPrints
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> IS_HEADING_ACCEPTABLE, fHeading = ", fHeading, ", fIdealHeading = ", fIdealHeading, ", RETURN FALSE")
|
|
ENDIF
|
|
#ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL IS_HEADING_ACCEPTABLE_CORRECTED(FLOAT fHeading, FLOAT fIdealHeading, FLOAT fLeeway #IF IS_DEBUG_BUILD, BOOL bDebugPrints = FALSE #ENDIF)
|
|
FLOAT fUpperH
|
|
FLOAT fLowerH
|
|
|
|
fLowerH = fIdealHeading - fLeeway
|
|
IF fLowerH < 0.0
|
|
fLowerH += 360.0
|
|
ENDIF
|
|
fUpperH = fIdealHeading + fLeeway
|
|
IF fUpperH >= 360.0
|
|
fUpperH -= 360.0
|
|
ENDIF
|
|
IF fUpperH < 0.0
|
|
fUpperH += 360.0
|
|
ENDIF
|
|
IF fUpperH > fLowerH
|
|
IF fHeading < fUpperH
|
|
AND fHeading > fLowerH
|
|
#IF IS_DEBUG_BUILD
|
|
IF bDebugPrints
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> IS_HEADING_ACCEPTABLE, fHeading = ", fHeading, ", fIdealHeading = ", fIdealHeading, ", RETURN TRUE")
|
|
ENDIF
|
|
#ENDIF
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
IF fHeading < fUpperH
|
|
OR fHeading > fLowerH
|
|
#IF IS_DEBUG_BUILD
|
|
IF bDebugPrints
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> IS_HEADING_ACCEPTABLE, fHeading = ", fHeading, ", fIdealHeading = ", fIdealHeading, ", RETURN TRUE")
|
|
ENDIF
|
|
#ENDIF
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
IF bDebugPrints
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> IS_HEADING_ACCEPTABLE, fHeading = ", fHeading, ", fIdealHeading = ", fIdealHeading, ", RETURN FALSE")
|
|
ENDIF
|
|
#ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
PROC GET_POSITION_FOR_WALLET_SCENE(PED_INDEX ped, VECTOR &returnPos, VECTOR &returnRot, STRING sHandoverDict, STRING sHandoverPed)
|
|
|
|
INT iStage = 0
|
|
INT iAttempts = 0
|
|
INT CounterRotate = 1
|
|
FLOAT originalHeading
|
|
FLOAT newHeading
|
|
SHAPETEST_INDEX HandoverShapetest
|
|
INT bHitResult
|
|
VECTOR vRetNormal
|
|
VECTOR vRetPos
|
|
VECTOR vTemp
|
|
VECTOR vDistance
|
|
ENTITY_INDEX hitEntity
|
|
|
|
// METHOD 1 - Use the player's position when triggered for the animation, and make the heading of the anim the heading between the player and victim ped
|
|
// This ALMOST works, but there are loads of edge cases where it fucks up - building corners for example (convenience store in ATM Robbery 16),
|
|
// where the anim offset is gets embedded in a building and the shapetest never returns true
|
|
|
|
returnPos = GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE)
|
|
returnRot.z = GET_HEADING_FROM_ENTITIES_LA(ped, PLAYER_PED_ID())
|
|
originalHeading = GET_HEADING_FROM_ENTITIES_LA(ped, PLAYER_PED_ID())
|
|
newHeading = GET_HEADING_FROM_ENTITIES_LA(ped, PLAYER_PED_ID())
|
|
vDistance = GET_ENTITY_COORDS(ped, FALSE) - GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE)
|
|
|
|
// METHOD 2 - Try and get the victim ped's position, and then get an offset using the heading between the player's position and theirs to place the animation
|
|
// This is returning weird results - returnPos isn't where I keep thinking it'll be or the debug isn't showing the right positions; I've probably fucked something up?
|
|
// This might be better than the first method though because it should guarantee that the anim offset is where the ped is and is never embedded in the wall
|
|
// The player would warp a little bit, but they're offscreen, so who cares
|
|
|
|
// returnRot.z = GET_HEADING_FROM_ENTITIES_LA(ped, PLAYER_PED_ID())
|
|
// newHeading = GET_HEADING_FROM_ENTITIES_LA(ped, PLAYER_PED_ID())
|
|
// vDistance = GET_ENTITY_COORDS(ped, FALSE) - GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE)
|
|
// vTemp = GET_ENTITY_COORDS(ped, FALSE)
|
|
// CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE: ped coords: ", vTemp, ". returnRot.z: ", newHeading, ". vDistance: ", vDistance)
|
|
|
|
IF HAS_ANIM_DICT_LOADED(sHandoverDict)
|
|
vTemp = GET_ANIM_INITIAL_OFFSET_POSITION(sHandoverDict, sHandoverPed, returnPos, returnRot)
|
|
|
|
ELSE
|
|
SCRIPT_ASSERT("GET_POSITION_FOR_WALLET_SCENE() - Passed an animation dictionary to this function that isn't loaded! Attempting to salvage but will probably screw up badstyle...")
|
|
vTemp = returnPos+<<5,5,0>>
|
|
ENDIF
|
|
|
|
WHILE iStage < 2
|
|
SWITCH iStage
|
|
CASE 0
|
|
// Start the shape test
|
|
#IF IS_DEBUG_BUILD
|
|
DRAW_DEBUG_SPHERE(returnPos, 0.5, 255, 0, 0, 128)
|
|
DRAW_DEBUG_SPHERE(vTemp+<<0,0,-1.0>>, 0.5, 0, 0, 255, 128)
|
|
#ENDIF
|
|
IF iAttempts > 20
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, had more than 20 attempts at this... breaking out")
|
|
returnRot.z = GET_HEADING_FROM_COORDS_LA(GET_ENTITY_COORDS(ped, FALSE), returnPos) // Re-grab the heading so it's less terrible
|
|
returnPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(GET_ENTITY_COORDS(ped, FALSE), returnRot.z, vDistance)
|
|
iStage = 2
|
|
ELSE
|
|
HandoverShapetest = START_SHAPE_TEST_CAPSULE(returnPos, vTemp+<<0,0,-1.0>>, 0.5, SCRIPT_INCLUDE_MOVER|SCRIPT_INCLUDE_OBJECT)
|
|
iStage++
|
|
ENDIF
|
|
BREAK
|
|
CASE 1
|
|
#IF IS_DEBUG_BUILD
|
|
DRAW_DEBUG_SPHERE(returnPos, 0.5, 255, 0, 0, 128)
|
|
DRAW_DEBUG_SPHERE(vTemp+<<0,0,-1.0>>, 0.5, 0, 0, 255, 128)
|
|
#ENDIF
|
|
IF GET_SHAPE_TEST_RESULT(HandoverShapetest, bHitResult, vRetPos, vRetNormal, hitEntity) = SHAPETEST_STATUS_RESULTS_READY
|
|
IF bHitResult != 0
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, bHitResult = ", bHitResult, " - trying again (current attempt: ", iAttempts)
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, vRetPos = ", vRetPos, ", vRetNormal = ", vRetNormal)
|
|
// If we've hit something but the Z of that hit is >10m of the return pos, we'll assume it's just hit the world container and do this anyway
|
|
IF vRetPos.z > (returnPos.z+8.5)
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, vRetPos.z is > returnPos.z+8.5 - fuck it, let's use it anyway...")
|
|
iStage++
|
|
ELSE
|
|
// Something is blocking the area we want to play the anim - rotate the animation
|
|
// Change the heading from the victim to the player by x degrees, so we'll rotate the player's position by roughly that much
|
|
IF iAttempts <= 3 // For the first n attempts go around counter-clockwise, +x degrees
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, newHeading old = ", newHeading)
|
|
newHeading+=7.5//(x)
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, newHeading + 7.5 = ", newHeading)
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, newHeading old = ", newHeading)
|
|
// Past n attempts, get the original heading and then -x it each time
|
|
newHeading = originalHeading - (7.5*CounterRotate)
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, newHeading - 7.5 *",CounterRotate," = ", newHeading)
|
|
CounterRotate++
|
|
ENDIF
|
|
// Now get a new offset to move the player to so we can retest it
|
|
returnPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), newHeading, vDistance)
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, new returnPos = ", returnPos)
|
|
iAttempts++ // Increase the number of attempts
|
|
iStage = 0 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, shape test okay!")
|
|
// Re-get the heading if it's changed after multiple shapetests
|
|
IF iAttempts > 0
|
|
returnRot.z = GET_HEADING_FROM_COORDS_LA(vTemp+<<0,0,-0.75>>, returnPos)
|
|
ENDIF
|
|
iStage++
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, final returnPos = ", returnPos, ", returnRot.z = ", returnRot.z)
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_WALLET_SCENE, still waiting for shapetest results...")
|
|
ENDIF
|
|
BREAK
|
|
CASE 2
|
|
// Do nothing, While will break out here
|
|
BREAK
|
|
ENDSWITCH
|
|
WAIT(0)
|
|
ENDWHILE
|
|
ENDPROC
|
|
|
|
PROC GET_POSITION_FOR_HANDOOVER_SCENE(PED_INDEX ped, VECTOR &returnPos, FLOAT &returnHeading)
|
|
INT iNodeNumber, iNoOfLanes, iLanesSouth, iLanesNorth
|
|
VECTOR vSouth, vNorth, vTemp
|
|
FLOAT centralReservationWidth, fHeadingToVictim, fFlippedNodeHeading, fNodeHeading, offsetToKerb
|
|
FLOAT ROAD_LANE_OFFSET = 5.0
|
|
|
|
iNodeNumber = 1
|
|
INT iStage = 0
|
|
SHAPETEST_INDEX HandoverShapetest
|
|
INT bHitResult
|
|
VECTOR vRetNormal
|
|
VECTOR vRetPos
|
|
ENTITY_INDEX hitEntity
|
|
|
|
WHILE iStage < 2
|
|
SWITCH iStage
|
|
CASE 0
|
|
// Get the closest vehicle node
|
|
GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(GET_ENTITY_COORDS(PLAYER_PED_ID()), iNodeNumber, returnPos, fNodeHeading, iNoOfLanes, NF_INCLUDE_SWITCHED_OFF_NODES|NF_IGNORE_SLIPLANES) // Is returning slip nodes.
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING, iNodeNumber, ", iNodeNumber, ", returnPos = ", returnPos, ", fNodeHeading = ", fNodeHeading, ", iNoOfLanes = ", iNoOfLanes)
|
|
GET_CLOSEST_ROAD(returnPos, 1, 1, vSouth, vNorth, iLanesSouth, iLanesNorth, centralReservationWidth, FALSE)
|
|
|
|
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), <<-3044.66, 596.43, 6.58>>) < 25
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, we're at ATM Robbery 3, canning the returnPos in case the player enters from the beach")
|
|
returnPos = <<-3031.38, 605.32, 6.86>>
|
|
ENDIF
|
|
|
|
// Work out scene heading
|
|
// Get heading from player to victim
|
|
vTemp = GET_ENTITY_COORDS(PLAYER_PED_ID()) - GET_ENTITY_COORDS(ped)
|
|
fHeadingToVictim = GET_HEADING_FROM_VECTOR_2D(vTemp.x, vTemp.y)
|
|
|
|
// Get flipped node heading
|
|
fFlippedNodeHeading = fNodeHeading+180
|
|
IF fFlippedNodeHeading > 360
|
|
fFlippedNodeHeading -= 360
|
|
ENDIF
|
|
|
|
// Decide which heading works
|
|
IF IS_HEADING_ACCEPTABLE(fHeadingToVictim, fNodeHeading, 90)
|
|
returnHeading = fNodeHeading
|
|
ELSE
|
|
returnHeading = fFlippedNodeHeading
|
|
ENDIF
|
|
|
|
// Work out the scene position
|
|
// Get distance to kerb
|
|
IF centralReservationWidth < 0
|
|
offsetToKerb = 0
|
|
ELSE
|
|
IF GET_VEHICLE_NODE_IS_SWITCHED_OFF(GET_NTH_CLOSEST_VEHICLE_NODE_ID(returnPos, 1))
|
|
offsetToKerb = 0
|
|
ELSE
|
|
offsetToKerb = (ROAD_LANE_OFFSET*(TO_FLOAT(iNoOfLanes/2)))
|
|
IF offsetToKerb = 0
|
|
offsetToKerb += ROAD_LANE_OFFSET
|
|
ENDIF
|
|
|
|
IF iNoOfLanes = 5
|
|
offsetToKerb += ROAD_LANE_OFFSET
|
|
ENDIF
|
|
// Add half of kerb
|
|
// If we're near ATM Robbery 8 or 18, add an extra metre to the kerb offset to stop the victim walking through a tree/bus shelter
|
|
// This is a bit hacky and I don't like it, but I'm at a loss of what else to do
|
|
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), <<294, -895, 28>>) < 25
|
|
OR GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), <<-713.01, -819.64, 22.63>>) < 25
|
|
offsetToKerb += 5.0
|
|
ELSE
|
|
offsetToKerb += 3.75
|
|
ENDIF
|
|
offsetToKerb += (centralReservationWidth/2)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Get offset direction
|
|
IF (VDIST(GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(returnPos, returnHeading, <<offsetToKerb,0,0>> ), GET_ENTITY_COORDS(PLAYER_PED_ID())) >
|
|
VDIST(GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(returnPos, returnHeading, <<-offsetToKerb,0,0>> ), GET_ENTITY_COORDS(PLAYER_PED_ID())))
|
|
offsetToKerb = -offsetToKerb
|
|
ENDIF
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, offsetToKerb = ", offsetToKerb)
|
|
// Return the position
|
|
returnPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(returnPos, returnHeading, <<offsetToKerb,0,0>>)
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, returnPos = ", returnPos, ", returnHeading = ", returnHeading)
|
|
// Start the shape test
|
|
HandoverShapetest = START_SHAPE_TEST_CAPSULE(returnPos+(returnPos.z+4.5), returnPos+<<0.5,0.5,4.5>>, 2.5)
|
|
iStage++
|
|
BREAK
|
|
CASE 1
|
|
IF iNodeNumber <= 2
|
|
IF GET_SHAPE_TEST_RESULT(HandoverShapetest, bHitResult, vRetPos, vRetNormal, hitEntity) = SHAPETEST_STATUS_RESULTS_READY
|
|
IF bHitResult != 0
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, bHitResult = ", bHitResult, " - increasing rode node number and trying again")
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, vRetPos = ", vRetPos, ", vRetNormal = ", vRetNormal)
|
|
// If we've hit something but the Z of that hit is >10m of the return pos, we'll assume it's just hit the world container and do this anyway
|
|
IF vRetPos.z > (returnPos.z+8.5)
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, vRetPos.z is > returnPos.z+8.5 - fuck it, let's use it anyway...")
|
|
iStage++
|
|
ELSE
|
|
iNodeNumber++ // This node has building shit around it, check the next node
|
|
iStage = 0 // Go back to the previous stage and try again
|
|
|
|
ENDIF
|
|
ELSE
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, shape test okay!")
|
|
iStage++
|
|
ENDIF
|
|
ELSE
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, still waiting for shapetest results...")
|
|
ENDIF
|
|
ELSE
|
|
PRINTLN("<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_HANDOOVER_SCENE, previous 2 nodes have failed shape test - fuck it, just use node 3")
|
|
iStage++
|
|
ENDIF
|
|
BREAK
|
|
CASE 2
|
|
// Do nothing, While will break out here
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDWHILE
|
|
|
|
ENDPROC
|
|
|
|
INT iPlayerCarNodeNumber = 3
|
|
FUNC BOOL GET_POSITION_FOR_PLAYERS_CAR(VECTOR vCutPos, VECTOR &returnPos, FLOAT &returnHeading)
|
|
INT iNoOfLanes, iLanesSouth, iLanesNorth
|
|
VECTOR vSouth, vNorth, vTemp
|
|
FLOAT centralReservationWidth, fHeadingToCutscene, fFlippedNodeHeading, fNodeHeading, offsetToKerb
|
|
FLOAT ROAD_LANE_OFFSET = 4.2
|
|
|
|
GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(GET_ENTITY_COORDS(PLAYER_PED_ID()), iPlayerCarNodeNumber, returnPos, fNodeHeading, iNoOfLanes, NF_INCLUDE_SWITCHED_OFF_NODES) // Is returning slip nodes.
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING, returnPos = ", returnPos, ", fNodeHeading = ", fNodeHeading, ", iNoOfLanes = ", iNoOfLanes)
|
|
GET_CLOSEST_ROAD(returnPos, 1, 1, vSouth, vNorth, iLanesSouth, iLanesNorth, centralReservationWidth, FALSE)
|
|
|
|
// Work out scene heading
|
|
// Get heading from player to victim
|
|
vTemp = vCutPos - returnPos
|
|
fHeadingToCutscene = GET_HEADING_FROM_VECTOR_2D(vTemp.x, vTemp.y)
|
|
|
|
// Get flipped node heading
|
|
fFlippedNodeHeading = fNodeHeading+180
|
|
IF fFlippedNodeHeading > 360
|
|
fFlippedNodeHeading -= 360
|
|
ENDIF
|
|
|
|
// Decide which heading works
|
|
IF IS_HEADING_ACCEPTABLE(fHeadingToCutscene, fNodeHeading, 90)
|
|
returnHeading = fNodeHeading
|
|
ELSE
|
|
returnHeading = fFlippedNodeHeading
|
|
ENDIF
|
|
|
|
// Work out the scene position
|
|
// Get distance to kerb
|
|
IF centralReservationWidth < 0
|
|
offsetToKerb = 0
|
|
ELSE
|
|
IF GET_VEHICLE_NODE_IS_SWITCHED_OFF(GET_NTH_CLOSEST_VEHICLE_NODE_ID(returnPos, 1))
|
|
offsetToKerb = 0
|
|
ELSE
|
|
offsetToKerb = (ROAD_LANE_OFFSET*(TO_FLOAT(iNoOfLanes/2)))
|
|
IF offsetToKerb = 0
|
|
offsetToKerb += ROAD_LANE_OFFSET
|
|
ENDIF
|
|
|
|
// Add half of kerb
|
|
offsetToKerb += (centralReservationWidth/2)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Get offset direction
|
|
IF (VDIST(GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(returnPos, returnHeading, <<offsetToKerb,0,0>> ), GET_ENTITY_COORDS(PLAYER_PED_ID())) >
|
|
VDIST(GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(returnPos, returnHeading, <<-offsetToKerb,0,0>> ), GET_ENTITY_COORDS(PLAYER_PED_ID())))
|
|
offsetToKerb = -offsetToKerb
|
|
ENDIF
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_PLAYERS_CAR, offsetToKerb = ", offsetToKerb)
|
|
// Return the position
|
|
returnPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(returnPos, returnHeading, <<offsetToKerb,0,0>>)
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_POSITION_FOR_PLAYERS_CAR, returnPos = ", returnPos, ", returnHeading = ", returnHeading)
|
|
IF NOT IS_POINT_OBSCURED_BY_A_MISSION_ENTITY(returnPos, <<4,4,4>>)
|
|
RETURN TRUE
|
|
ELSE
|
|
iPlayerCarNodeNumber++
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDFUNC
|
|
|
|
FUNC VECTOR GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR(VECTOR vScenePosition, VECTOR vVictimPosition)
|
|
VEHICLE_INDEX tempCar
|
|
VECTOR vReturn, vNode, vMin, vMax
|
|
|
|
INT iStage = 0
|
|
INT iIncrement = 1
|
|
INT bHitResult
|
|
VECTOR vRetNormal
|
|
VECTOR vRetPos
|
|
VECTOR vFront
|
|
VECTOR vBack
|
|
ENTITY_INDEX hitEntity
|
|
|
|
#if IS_DEBUG_BUILD
|
|
VECTOR vTemp
|
|
#ENDIF
|
|
|
|
tempCar = GET_PLAYERS_LAST_VEHICLE()
|
|
IF NOT IS_ENTITY_A_MISSION_ENTITY(tempCar)
|
|
SET_ENTITY_AS_MISSION_ENTITY(tempCar)
|
|
ENDIF
|
|
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(tempCar), vMin, vMax)
|
|
GET_NTH_CLOSEST_VEHICLE_NODE(vScenePosition, 3, vNode) // Get the SECOND closest node to the scene - we don't want to spawn the car that close to the player...
|
|
|
|
#if IS_DEBUG_BUILD
|
|
vTemp = GET_ENTITY_COORDS(tempCar)
|
|
#ENDIF
|
|
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, the 2nd closest node is at ", vNode)
|
|
|
|
#if IS_DEBUG_BUILD
|
|
IF DOES_ENTITY_EXIST(tempCar)
|
|
IF NOT IS_ENTITY_DEAD(tempCar)
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, the player's car is at ", vTemp)
|
|
ENDIF
|
|
ENDIF
|
|
#ENDIF
|
|
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, vMin is ", vMin)
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, vMax is ", vMax)
|
|
SHAPETEST_INDEX VehicleShapetest
|
|
|
|
IF VDIST(vScenePosition, <<-3039.6548, 602.4346, 6.5719>>) <=25 // If we're less than 25m away from ATM Robbery 3, move the vehicle specifically
|
|
vReturn = <<-3045.49, 604.46, 7.02>>
|
|
iStage = 8 // Skip the while loop and shapetest checks
|
|
ELIF VDIST(vScenePosition, <<288.06, -1257.10, 28.44>>) <=25 // If we're less than 25m away from ATM Robbery 2, move the vehicle specifically
|
|
vReturn = <<278.97, -1255.06, 28.88>>
|
|
iStage = 8 // Skip the while loop and shapetest checks
|
|
ENDIF
|
|
|
|
WHILE iStage < 8
|
|
SWITCH iStage
|
|
CASE 0
|
|
IF VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, (vMax.y+iIncrement), 0>>)) < VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, -((vMax.y+iIncrement)), 0>>))
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, (vMax.y+iIncrement), 0>>)
|
|
ELSE
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, -((vMax.y+iIncrement)), 0>>)
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(tempCar)
|
|
IF NOT IS_ENTITY_DEAD(tempCar)
|
|
vFront = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMax)
|
|
vBack = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMin)
|
|
VehicleShapetest = START_SHAPE_TEST_LOS_PROBE(vFront, vBack, SCRIPT_INCLUDE_ALL, tempCar, SCRIPT_SHAPETEST_OPTION_DEFAULT)
|
|
iStage++
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
BREAK
|
|
CASE 1
|
|
IF GET_SHAPE_TEST_RESULT(VehicleShapetest, bHitResult, vRetPos, vRetNormal, hitEntity) = SHAPETEST_STATUS_RESULTS_READY
|
|
IF bHitResult != 0
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, bHitResult = ", bHitResult, " - increasing rode node number and trying again")
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, vRetPos = ", vRetPos, ", vRetNormal = ", vRetNormal)
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 2
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 0 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vReturn, vScenePosition) <= 5.0
|
|
OR GET_DISTANCE_BETWEEN_COORDS(vReturn, vVictimPosition) <= 5.0
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, found an unoccupied space, but too close to vScenePosition or vVictimPosition!")
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 2
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 0 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, this position should be clear = ", vReturn)
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, y+iIncrement of = ", iIncrement)
|
|
iStage = 8
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, still waiting for shapetest results...")
|
|
ENDIF
|
|
BREAK
|
|
CASE 2 // -Y
|
|
IF VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, (vMax.y-iIncrement), 0>>)) < VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, -((vMax.y-iIncrement)), 0>>))
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, (vMax.y-iIncrement), 0>>)
|
|
ELSE
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<0, -((vMax.y-iIncrement)), 0>>)
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(tempCar)
|
|
IF NOT IS_ENTITY_DEAD(tempCar)
|
|
vFront = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMax)
|
|
vBack = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMin)
|
|
VehicleShapetest = START_SHAPE_TEST_LOS_PROBE(vFront, vBack, SCRIPT_INCLUDE_ALL, tempCar, SCRIPT_SHAPETEST_OPTION_DEFAULT)
|
|
iStage++
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
BREAK
|
|
CASE 3 // Check results for -Y
|
|
IF GET_SHAPE_TEST_RESULT(VehicleShapetest, bHitResult, vRetPos, vRetNormal, hitEntity) = SHAPETEST_STATUS_RESULTS_READY
|
|
IF bHitResult != 0
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, bHitResult = ", bHitResult, " - increasing rode node number and trying again")
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, vRetPos = ", vRetPos, ", vRetNormal = ", vRetNormal)
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 4
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 2 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vReturn, vScenePosition) <= 5.0
|
|
OR GET_DISTANCE_BETWEEN_COORDS(vReturn, vVictimPosition) <= 5.0
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, found an unoccupied space, but too close to vScenePosition or vVictimPosition!")
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 4
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 2 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, this position should be clear = ", vReturn)
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, y-iIncrement of = ", iIncrement)
|
|
iStage = 8
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, still waiting for shapetest results...")
|
|
ENDIF
|
|
BREAK
|
|
CASE 4 // +X
|
|
IF VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<(vMax.x+iIncrement), 0, 0>>)) < VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<-((vMax.x+iIncrement)), 0, 0>>))
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<(vMax.x+iIncrement), 0, 0>>)
|
|
ELSE
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<-((vMax.x+iIncrement)), 0, 0>>)
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(tempCar)
|
|
IF NOT IS_ENTITY_DEAD(tempCar)
|
|
vFront = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMax)
|
|
vBack = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMin)
|
|
VehicleShapetest = START_SHAPE_TEST_LOS_PROBE(vFront, vBack, SCRIPT_INCLUDE_ALL, tempCar, SCRIPT_SHAPETEST_OPTION_DEFAULT)
|
|
iStage++
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
BREAK
|
|
CASE 5 // Check results for +X
|
|
IF GET_SHAPE_TEST_RESULT(VehicleShapetest, bHitResult, vRetPos, vRetNormal, hitEntity) = SHAPETEST_STATUS_RESULTS_READY
|
|
IF bHitResult != 0
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, bHitResult = ", bHitResult, " - increasing rode node number and trying again")
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, vRetPos = ", vRetPos, ", vRetNormal = ", vRetNormal)
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 6
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 4 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vReturn, vScenePosition) <= 5.0
|
|
OR GET_DISTANCE_BETWEEN_COORDS(vReturn, vVictimPosition) <= 5.0
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, found an unoccupied space, but too close to vScenePosition or vVictimPosition!")
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 6
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 4 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, this position should be clear = ", vReturn)
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, x+iIncrement of = ", iIncrement)
|
|
iStage = 8
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, still waiting for shapetest results...")
|
|
ENDIF
|
|
BREAK
|
|
CASE 6 // -X
|
|
IF VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<(vMax.x-iIncrement), 0, 0>>)) < VDIST(vNode, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<-((vMax.x-iIncrement)), 0, 0>>))
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<(vMax.x-iIncrement), 0, 0>>)
|
|
ELSE
|
|
vReturn = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(tempCar, <<-((vMax.x-iIncrement)), 0, 0>>)
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(tempCar)
|
|
IF NOT IS_ENTITY_DEAD(tempCar)
|
|
vFront = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMax)
|
|
vBack = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vReturn, 0, vMin)
|
|
VehicleShapetest = START_SHAPE_TEST_LOS_PROBE(vFront, vBack, SCRIPT_INCLUDE_ALL, tempCar, SCRIPT_SHAPETEST_OPTION_DEFAULT)
|
|
iStage++
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
ELSE
|
|
iStage = 8
|
|
ENDIF
|
|
BREAK
|
|
CASE 7 // Check results for -X
|
|
IF GET_SHAPE_TEST_RESULT(VehicleShapetest, bHitResult, vRetPos, vRetNormal, hitEntity) = SHAPETEST_STATUS_RESULTS_READY
|
|
IF bHitResult != 0
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, bHitResult = ", bHitResult, " - increasing rode node number and trying again")
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, vRetPos = ", vRetPos, ", vRetNormal = ", vRetNormal)
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 8
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, failed to find clear position, returning = ", vReturn)
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 6 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vReturn, vScenePosition) <= 5.0
|
|
OR GET_DISTANCE_BETWEEN_COORDS(vReturn, vVictimPosition) <= 5.0
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, found an unoccupied space, but too close to vScenePosition or vVictimPosition!")
|
|
IF iIncrement >= 3
|
|
iIncrement = 1
|
|
iStage = 8
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, couldn't find any unoccupied spaces...")
|
|
ELSE
|
|
iIncrement++
|
|
iStage = 6 // Go back to the previous stage and try again
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,GET_THIS_SCRIPT_NAME(), " - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, this position should be clear = ", vReturn)
|
|
iStage = 8
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AMBIENT,"<", GET_THIS_SCRIPT_NAME(), "> - GET_UNOCCUPIED_POSITION_FOR_PLAYERS_CAR, still waiting for shapetest results...")
|
|
ENDIF
|
|
BREAK
|
|
CASE 8
|
|
// Do nothing, break out
|
|
BREAK
|
|
ENDSWITCH
|
|
#IF IS_DEBUG_BUILD
|
|
DRAW_DEBUG_SPHERE(vFront, 0.5, 255, 255, 0, 128)
|
|
DRAW_DEBUG_SPHERE(vBack, 0.5, 0, 255, 255, 128)
|
|
#ENDIF
|
|
WAIT(0)
|
|
ENDWHILE
|
|
|
|
RETURN vReturn
|
|
ENDFUNC
|
|
|
|
|
|
PROC SET_CAMERA_OVER_THE_SHOULDER_FOR_CATCH_UP()
|
|
CAMERA_INDEX camCatchup = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER_PED_ID(), <<0.5,-1,0.5>>), <<0,0,GET_ENTITY_HEADING(PLAYER_PED_ID())>>, DEFAULT, TRUE)
|
|
SET_CAM_ACTIVE(camCatchup, TRUE)
|
|
ENDPROC
|
|
|
|
|
|
|
|
|
|
|
|
|