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 = <> 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 = <> 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 = <> 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 = <> 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 = <> ELIF Direction = ECOMPASS_NORTH Offset = <<-LocateSize,LocateSize , 0>> ELIF Direction = ECOMPASS_SOUTH Offset = <> ELIF Direction = ECOMPASS_WEST Offset = <<-LocateSize, -LocateSize, 0>> ENDIF BREAK CASE EACTIVEAPPROACH_FRONTRIGHT IF Direction = ECOMPASS_NORTH Offset = <> ELIF Direction = ECOMPASS_WEST Offset = <<-LocateSize,LocateSize , 0>> ELIF Direction = ECOMPASS_EAST Offset = <> ELIF Direction = ECOMPASS_SOUTH Offset = <<-LocateSize, -LocateSize, 0>> ENDIF BREAK CASE EACTIVEAPPROACH_BACKLEFT IF Direction = ECOMPASS_SOUTH Offset = <> ELIF Direction = ECOMPASS_EAST Offset = <<-LocateSize,LocateSize , 0>> ELIF Direction = ECOMPASS_WEST Offset = <> ELIF Direction = ECOMPASS_NORTH Offset = <<-LocateSize, -LocateSize, 0>> ENDIF BREAK CASE EACTIVEAPPROACH_BACKRIGHT IF Direction = ECOMPASS_WEST Offset = <> ELIF Direction = ECOMPASS_SOUTH Offset = <<-LocateSize,LocateSize , 0>> ELIF Direction = ECOMPASS_NORTH Offset = <> 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, <> ), 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, <>) 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, <> ), 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, <>) 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