4377 lines
166 KiB
XML
Executable File
4377 lines
166 KiB
XML
Executable File
//Includes
|
|
USING "rage_builtins.sch"
|
|
USING "globals.sch"
|
|
USING "cutscene_public.sch"
|
|
USING "commands_brains.sch"
|
|
USING "commands_cutscene.sch"
|
|
USING "commands_entity.sch"
|
|
USING "commands_script.sch"
|
|
USING "common_Races.sch"
|
|
USING "flow_help_public.sch"
|
|
USING "minigames_helpers.sch"
|
|
USING "net_mission.sch"
|
|
USING "script_heist.sch"
|
|
USING "shared_hud_displays.sch"
|
|
USING "track_Data.sch"
|
|
USING "rgeneral_include.sch"
|
|
USING "RC_Helper_Functions.sch"
|
|
USING "RC_Threat_Public.sch"
|
|
USING "Race_Results.sch"
|
|
USING "net_common_functions.sch"
|
|
USING "commands_misc.sch"
|
|
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
//
|
|
// SCRIPT NAME : Race_Control.sch
|
|
// AUTHOR : Joe Binks
|
|
// DESCRIPTION : All the functions for running city and sea races
|
|
//
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
|
|
|
|
// ===========================================================================================================
|
|
// Enums and Structs
|
|
// ===========================================================================================================
|
|
ENUM FAIL_REASON
|
|
FAIL_DEFAULT,
|
|
FAIL_RIVAL_ATTACKED,
|
|
FAIL_RIVAL_DEAD,
|
|
FAIL_WRECKED,
|
|
FAIL_ABANDONED_RACE,
|
|
FAIL_MISSED_CHECKPOINT,
|
|
FAIL_ALERTED_COPS
|
|
ENDENUM
|
|
|
|
ENUM RACE_STATE
|
|
RACE_STATE_LINEUP,
|
|
RACE_STATE_COUNTDOWN,
|
|
RACE_STATE_ACTIVE,
|
|
RACE_STATE_END,
|
|
RACE_STATE_REWARD,
|
|
RACE_STATE_FAIL
|
|
ENDENUM
|
|
|
|
ENUM RACE_SUBSTATE
|
|
RACE_SUBSTATE_SETUP,
|
|
RACE_SUBSTATE_RUNNING,
|
|
RACE_SUBSTATE_CLEANUP
|
|
ENDENUM
|
|
|
|
ENUM AI_RACE_STATE
|
|
AI_RACER_INIT,
|
|
AI_RACER_WAIT_FOR_BURNOUT_FINISHED,
|
|
AI_RACER_ACTIVE,
|
|
AI_RACER_FINISHED_RACE
|
|
ENDENUM
|
|
|
|
ENUM AI_DRIVING_SPEED
|
|
AI_DRIVING_SPEED_SLOW,
|
|
AI_DRIVING_SPEED_MEDIUM,
|
|
AI_DRIVING_SPEED_FAST
|
|
ENDENUM
|
|
|
|
ENUM RACES_RESPAWN_STATE
|
|
RACES_RESPAWN_SET,
|
|
RACES_RESPAWN_INIT,
|
|
RACES_RESPAWN_CHECK,
|
|
RACES_RESPAWN_ACTIVE,
|
|
RACES_RESPAWN_WAIT
|
|
ENDENUM
|
|
|
|
ENUM LAP_TEXT_STATE
|
|
LTS_READY,
|
|
LTS_LOAD,
|
|
LTS_INIT,
|
|
LTS_DISPLAY,
|
|
LTS_CLEANUP
|
|
ENDENUM
|
|
|
|
ENUM BOOST_STATE
|
|
BS_READY,
|
|
BS_ACTIVE,
|
|
BS_FINISHED
|
|
ENDENUM
|
|
|
|
ENUM AI_WARP_STATE
|
|
AWS_READY,
|
|
AWS_WARPING,
|
|
AWS_FINISHED
|
|
ENDENUM
|
|
|
|
// AI Racer
|
|
STRUCT AI_RACER
|
|
AI_RACE_STATE stateAI = AI_RACER_INIT
|
|
AI_DRIVING_SPEED drivingSpeed = AI_DRIVING_SPEED_MEDIUM
|
|
FLOAT fLastSpeed
|
|
PED_INDEX piDriver
|
|
MODEL_NAMES modelPed
|
|
MODEL_NAMES modelCar
|
|
VEHICLE_INDEX viCar
|
|
BLIP_INDEX biBlip
|
|
INT iCurrentPoint = 0
|
|
INT iCurrentLap = 1
|
|
BOOL gGivenGetOnVehTask = FALSE
|
|
//BOOL bWarping = FALSE
|
|
BOOST_STATE eBoostState = BS_READY
|
|
INT iBoostTimer
|
|
BOOL bReadyToLook = TRUE
|
|
INT iLookAtTimer
|
|
AI_WARP_STATE eWarpState = AWS_READY
|
|
INT iWarpWaypoint = 0
|
|
INT iWarpTimer = 0
|
|
ENDSTRUCT
|
|
|
|
STRUCT RACE_HUD
|
|
COUNTDOWN_UI uiCountdown
|
|
INT iStartTime = 0
|
|
INT iCurrentCheckPoint = 0
|
|
INT iMaxCheckpoints = 0
|
|
INT iCurrentLap = 0
|
|
INT iCurrentTime = 0
|
|
INT iBestTime = -1
|
|
INT iPlayerPosition = 0
|
|
ENDSTRUCT
|
|
|
|
// ===========================================================================================================
|
|
// Race Cleanup
|
|
// ===========================================================================================================
|
|
FAIL_REASON failReason = FAIL_DEFAULT
|
|
RACE_STATE eRaceState
|
|
RACE_SUBSTATE eRaceSubState
|
|
RACES_RESPAWN_STATE racesRespawnState
|
|
|
|
BOOST_STATE eBoostState = BS_READY
|
|
INT iBoostTimer = -1
|
|
CONST_INT BOOST_START_WINDOW 500
|
|
CONST_INT BOOST_TIME 2000
|
|
|
|
CONST_FLOAT WARP_DISTANCE 40.0
|
|
CONST_FLOAT STOP_WARP_DISTANCE 30.0
|
|
|
|
INT iReplayRecordWarpTimer //Fix for bug 2226208
|
|
|
|
RACE_DATA sRaceData // Race information
|
|
RACE_HUD sRaceHUD
|
|
TRACK_DATA sTrackData
|
|
AI_RACER sRacer[MAX_AI_RACERS] // AI Racers
|
|
BOOL bRacersReleased // Handles if the racers have been allowed to start driving off
|
|
CONST_INT BURNOUT_SPREAD_TIME 100 // The AI racers due a burnout at the start, to help spread the grid at the start each racer does a successively longer burnout by this time
|
|
BOOL bLoopWaypointRecording
|
|
|
|
//structPedsForConversation conversationStruct
|
|
INT iPreviousPosition
|
|
INT iPositionConvTimer
|
|
CONST_INT POSITION_CONV_TIME 7500
|
|
|
|
// Deals with playing the stopped sound effect
|
|
INT iStoppedTimer = -1
|
|
INT iStoppedSound = -1
|
|
|
|
BLIP_INDEX biCurrentCheckPoint // Race markers
|
|
BLIP_INDEX biNextCheckPoint
|
|
CHECKPOINT_INDEX ciCurrentCheckPoint
|
|
CHECKPOINT_INDEX ciPreviousCheckPoint
|
|
INT iPrevAlpha
|
|
FLOAT fNextCheckpointDistance
|
|
|
|
INT iPrevClosestRacer = -1
|
|
INT iRaceMixTimer = 0
|
|
|
|
VEHICLE_INDEX viPlayerMain
|
|
|
|
CAMERA_INDEX gridCamera[8] // Camera panning shot
|
|
VECTOR vStartPos
|
|
VECTOR vStartRot
|
|
VECTOR vEndPos
|
|
VECTOR vEndRot
|
|
VECTOR vStartPos2
|
|
VECTOR vStartRot2
|
|
VECTOR vEndPos2
|
|
VECTOR vEndRot2
|
|
VECTOR vStartPos3
|
|
VECTOR vStartRot3
|
|
VECTOR vEndPos3
|
|
VECTOR vEndRot3
|
|
VECTOR vStartPos4
|
|
VECTOR vStartRot4
|
|
VECTOR vEndPos4
|
|
VECTOR vEndRot4
|
|
VECTOR vMidPos
|
|
VECTOR vMidRot
|
|
|
|
BOOL bPlayedIntroSound
|
|
INT iIntroSound = GET_SOUND_ID()
|
|
|
|
LAP_TEXT_STATE eLapTextState = LTS_READY
|
|
SCALEFORM_INDEX siLapText
|
|
CONST_INT LAP_TEXT_TIME (BIG_MESSAGE_DISPLAY_TIME)// + 3000)
|
|
INT iLapTextTimer
|
|
|
|
//SCENARIO_BLOCKING_INDEX scenarioBlockArea // World setup
|
|
|
|
RACE_RESULTS_STRUCT sRaceResults // struct used only by the race results screen
|
|
//MEGA_PLACEMENT_TOOLS mptRaceResultPlacement // Placement info for race results
|
|
SCALEFORM_INDEX uiLeaderboard[2]
|
|
INT iFinalRaceTime
|
|
CONST_INT END_SCREEN_TIME 30000 // how long to show the end camera and screen for
|
|
//INT iEndScreenTimer
|
|
CONST_INT QUIT_BUTTON_DELAY 2000
|
|
INT iQuitDelayTimer
|
|
//INT iSecondPlaceID = -1 // the ID of the second place AI racer, only used if the player wins
|
|
|
|
CONST_INT DPAD_DOWN_TIME 10000
|
|
//INT iDpadDownTimer = 0
|
|
|
|
INT iStuckHelpTimer
|
|
CONST_INT STUCK_HELP_TIME 1000
|
|
|
|
CONST_INT WARP_DIST_FROM_PLAYER 1//2 // How many checkpoints back from the player's current checkpoint should we warp them to
|
|
|
|
// Commenting out until the correct animations are available
|
|
PED_INDEX piGridGirlOne
|
|
PED_INDEX piGridGirlTwo
|
|
PED_INDEX piGridGirlThree
|
|
STRING sAnimDict = "random@street_race"
|
|
VECTOR vGridGirlOnePos
|
|
VECTOR vGridGirlTwoPos
|
|
VECTOR vGridGirlThreePos
|
|
FLOAT fGridGirlHeading
|
|
VECTOR vGridGirlTarget
|
|
//VECTOR vGridGirlCountPos
|
|
BOOL bGridGirlOneConvReady = TRUE
|
|
BOOL bGridGirlThreeConvReady = TRUE
|
|
|
|
// Variables for the end scene of the race
|
|
PED_INDEX piRewardPed
|
|
VECTOR vWinningCarPos
|
|
FLOAT fWinningCarHeading
|
|
// Commenting out for now in case this is needed again
|
|
/*VECTOR vAltCarPos
|
|
FLOAT fAltCarHeading*/
|
|
VECTOR vRewardPedPos
|
|
FLOAT fRewardPedHeading
|
|
|
|
INT iSpeedophileOutOfWaterTimer = -1
|
|
|
|
INT iCamTimer
|
|
|
|
/*CONST_INT END_SCENE_TIME 10000
|
|
INT iEndSceneTimer = 0*/
|
|
|
|
STRING sRaceWaypointRecording
|
|
|
|
SEQUENCE_INDEX seqGetInVehicle
|
|
|
|
// Disable road nodes near the race start
|
|
VECTOR vRaceRoadPos1 = <<0,0,0>>
|
|
VECTOR vRaceRoadPos2 = <<0,0,0>>
|
|
FLOAT fRaceRoadWidth = 0
|
|
SCENARIO_BLOCKING_INDEX sbiRaceStart
|
|
|
|
// Commenting out for now in case this is needed again
|
|
//BOOL bDeleteSecondPlace // Used in the cleanup to decide if the second place vehicle should be deleted or kept
|
|
|
|
BOOL bPlayerVehicleNeedsRecovering
|
|
INT iPlayerWantsToRecoverVehicleTimer
|
|
|
|
structPedsForConversation pedConvStruct
|
|
//BOOL bConversationStarted = FALSE
|
|
//INT iConvFailTimer = -1
|
|
|
|
INT iNumWaypoints
|
|
|
|
|
|
PROC AllowCompiling()
|
|
uiLeaderboard = uiLeaderboard
|
|
iQuitDelayTimer = iQuitDelayTimer
|
|
//vRewardDest = vRewardDest
|
|
//iEndScreenTimer = iEndScreenTimer
|
|
//bConversationStarted = bConversationStarted
|
|
eRaceSubState = eRaceSubState
|
|
iFinalRaceTime = iFinalRaceTime
|
|
//mptRaceResultPlacement = mptRaceResultPlacement
|
|
eRaceState = eRaceState
|
|
failReason = failReason
|
|
//iConvFailTimer = iConvFailTimer
|
|
vStartPos2 = vStartPos2
|
|
vStartRot2 = vStartRot2
|
|
vEndPos2 = vEndPos2
|
|
vEndRot2 = vEndRot2
|
|
vStartPos3 = vStartPos3
|
|
vStartRot3 = vStartRot3
|
|
vEndPos3 = vEndPos3
|
|
vEndRot3 = vEndRot3
|
|
vStartPos4 = vStartPos4
|
|
vStartRot4 = vStartRot4
|
|
vEndPos4 = vEndPos4
|
|
vEndRot4 = vEndRot4
|
|
vMidPos = vMidPos
|
|
vMidRot = vMidRot
|
|
ENDPROC
|
|
// ===========================================================================================================
|
|
// Race Cleanup
|
|
// ===========================================================================================================
|
|
/// PURPOSE: Remove street racers and their vehicles
|
|
PROC CLEANUP_RACERS(BOOL b_delete_racers)//, BOOL b_delete_second_place = TRUE)
|
|
INT i_index
|
|
SEQUENCE_INDEX siLeave
|
|
FOR i_index = 0 TO MAX_AI_RACERS-1
|
|
|
|
IF i_index < sTrackData.iNumAIRacers
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(sRacer[i_index].modelCar, FALSE)
|
|
ENDIF
|
|
IF b_delete_racers = TRUE
|
|
//IF b_delete_second_place OR i_index <> iSecondPlaceID
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].piDriver)
|
|
DELETE_PED(sRacer[i_index].piDriver)
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
DELETE_VEHICLE(sRacer[i_index].viCar)
|
|
ENDIF
|
|
//ENDIF
|
|
ELSE
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].piDriver)
|
|
IF NOT IS_ENTITY_DEAD(sRacer[i_index].piDriver)
|
|
SET_PED_KEEP_TASK(sRacer[i_index].piDriver, TRUE)
|
|
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
AND NOT IS_ENTITY_DEAD(sRacer[i_index].viCar)
|
|
SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(sRacer[i_index].piDriver, FALSE)
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(sRacer[i_index].viCar, FALSE)
|
|
IF sRaceData.eRaceTrack = SEA_RACE_04
|
|
OPEN_SEQUENCE_TASK(siLeave)
|
|
//TASK_VEHICLE_DRIVE_TO_COORD(NULL, sRacer[i_index].viCar, <<418.8445, -2819.7339, 2.3325>>, 20, DRIVINGSTYLE_NORMAL, GET_ENTITY_MODEL(sRacer[i_index].viCar), DRIVINGMODE_STOPFORCARS, 10, 5)
|
|
TASK_VEHICLE_DRIVE_TO_COORD(NULL, sRacer[i_index].viCar, <<380.1007, -3498.0776, -29.3627>>, 20, DRIVINGSTYLE_NORMAL, GET_ENTITY_MODEL(sRacer[i_index].viCar), DRIVINGMODE_STOPFORCARS, 10, 5)
|
|
TASK_VEHICLE_DRIVE_WANDER(NULL, sRacer[i_index].viCar, 20, DRIVINGMODE_STOPFORCARS)
|
|
CLOSE_SEQUENCE_TASK(siLeave)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, siLeave)
|
|
ELSE
|
|
TASK_VEHICLE_DRIVE_WANDER(sRacer[i_index].piDriver, sRacer[i_index].viCar, 20, DRIVINGMODE_STOPFORCARS)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SAFE_RELEASE_PED(sRacer[i_index].piDriver)
|
|
ENDIF
|
|
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
IF NOT IS_ENTITY_DEAD(sRacer[i_index].viCar)
|
|
SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(sRacer[i_index].viCar, FALSE)
|
|
SET_VEHICLE_STRONG(sRacer[i_index].viCar, FALSE)
|
|
SET_VEHICLE_HAS_STRONG_AXLES(sRacer[i_index].viCar, FALSE)
|
|
SET_VEHICLE_TYRES_CAN_BURST(sRacer[i_index].viCar, TRUE)
|
|
//SET_VEHICLE_CAN_DEFORM_WHEELS(sRacer[i_index].viCar, TRUE)
|
|
ENDIF
|
|
SET_VEHICLE_AS_NO_LONGER_NEEDED(sRacer[i_index].viCar)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDFOR
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Removes all the AI racers' blips
|
|
PROC CLEANUP_RACER_BLIPS()
|
|
INT i_index
|
|
FOR i_index = 0 TO MAX_AI_RACERS-1
|
|
SAFE_REMOVE_BLIP(sRacer[i_index].biBlip)
|
|
ENDFOR
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Removes the race checkpoints
|
|
PROC CLEANUP_RACE_CHECKPOINTS()
|
|
IF DOES_BLIP_EXIST(biCurrentCheckPoint)
|
|
REMOVE_BLIP(biCurrentCheckPoint)
|
|
ENDIF
|
|
|
|
IF DOES_BLIP_EXIST(biNextCheckPoint)
|
|
REMOVE_BLIP(biNextCheckPoint)
|
|
ENDIF
|
|
|
|
// Remove checkpoint
|
|
IF ciCurrentCheckPoint != NULL
|
|
DELETE_CHECKPOINT(ciCurrentCheckPoint)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Removes blips and checkpoints
|
|
PROC CLEANUP_CHECKPOINTS(BOOL b_delete_player_vehicle_blip = TRUE)
|
|
|
|
// Remove all blips
|
|
CLEANUP_RACE_CHECKPOINTS()
|
|
|
|
IF b_delete_player_vehicle_blip = TRUE
|
|
AND DOES_BLIP_EXIST(sPlayerVehicle.biPlayerVehicle)
|
|
REMOVE_BLIP(sPlayerVehicle.biPlayerVehicle)
|
|
ENDIF
|
|
|
|
INT i_index = 0
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers-1
|
|
SAFE_REMOVE_BLIP(sRacer[i_index].biBlip)
|
|
ENDFOR
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Updates the next race track
|
|
PROC CHECK_FOR_TRACK_UNLOCK()
|
|
|
|
BOOL bUnlockedNewTrack = FALSE
|
|
CC_CommID eTextMessageID = COMM_NONE
|
|
|
|
SWITCH sRaceData.eRaceTrack
|
|
|
|
CASE STREET_RACE_01
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Completed STREET_RACE_LOS_SANTOS")
|
|
|
|
// Currently this should never get called as both Street Race 1 and 2
|
|
// are unlocked upon completion of RC Hao 1
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Unlocked STREET_RACE_CITY_CIRCUIT")
|
|
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
|
|
bUnlockedNewTrack = TRUE
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_02
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Completed STREET_RACE_CITY_CIRCUIT")
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_AIRPORT))
|
|
AND g_savedGlobals.sStreetRaceData.eRaceToUnlock <> STREET_RACE_AIRPORT
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Preparing unlock text for STREET_RACE_AIRPORT")
|
|
g_savedGlobals.sStreetRaceData.eRaceToUnlock = STREET_RACE_AIRPORT
|
|
eTextMessageID = TEXT_STREET_RACE_AIRPORT
|
|
bUnlockedNewTrack = TRUE
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_04
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Completed STREET_RACE_AIRPORT")
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_FREEWAY))
|
|
AND g_savedGlobals.sStreetRaceData.eRaceToUnlock <> STREET_RACE_FREEWAY
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Preparing unlock text for STREET_RACE_FREEWAY")
|
|
g_savedGlobals.sStreetRaceData.eRaceToUnlock = STREET_RACE_FREEWAY
|
|
eTextMessageID = TEXT_STREET_RACE_FREEWAY
|
|
bUnlockedNewTrack = TRUE
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_05
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Completed STREET_RACE_FREEWAY")
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_VESPUCCI_CANALS))
|
|
AND g_savedGlobals.sStreetRaceData.eRaceToUnlock <> STREET_RACE_VESPUCCI_CANALS
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Preparing unlock text for STREET_RACE_VESPUCCI_CANALS")
|
|
g_savedGlobals.sStreetRaceData.eRaceToUnlock = STREET_RACE_VESPUCCI_CANALS
|
|
eTextMessageID = TEXT_STREET_RACE_CANALS
|
|
bUnlockedNewTrack = TRUE
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_06
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Completed STREET_RACE_VESPUCCI_CANALS")
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
// Send text message and autosave when unlocking new track
|
|
IF bUnlockedNewTrack
|
|
IF eTextMessageID != COMM_NONE
|
|
CPRINTLN(DEBUG_MISSION, "Adding text to queue: ", GET_COMM_ID_DEBUG_STRING(eTextMessageID))
|
|
REGISTER_TEXT_MESSAGE_FROM_CHARACTER_TO_PLAYER(eTextMessageID, CT_FLOW, BIT_FRANKLIN, CHAR_HAO, 2880000, 10000, VID_BLANK, CID_UNLOCK_NEXT_STREET_RACE)
|
|
ENDIF
|
|
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Check whether to make the race blip "gold"
|
|
PROC CHECK_FOR_MAP_BLIP_UPDATE()
|
|
|
|
SWITCH sRaceData.eRaceTrack
|
|
|
|
// Sea Races
|
|
CASE SEA_RACE_01
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_EAST))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_SEA_RACE1, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_SEA_RACE1, TRUE)
|
|
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_EAST))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE SEA_RACE_02
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_NORTH))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_SEA_RACE2, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_SEA_RACE2, TRUE)
|
|
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_NORTH))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE SEA_RACE_03
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_CANYON))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_SEA_RACE3, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_SEA_RACE3, TRUE)
|
|
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_CANYON))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE SEA_RACE_04
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_CITY))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_SEA_RACE4, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_SEA_RACE4, TRUE)
|
|
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceWon, ENUM_TO_INT(SEA_RACE_CITY))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
// Street Races
|
|
CASE STREET_RACE_01
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_LOS_SANTOS))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_STREET_RACE1, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_STREET_RACE1, TRUE)
|
|
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_LOS_SANTOS))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_02
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_STREET_RACE2, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_STREET_RACE2, TRUE)
|
|
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_04
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_AIRPORT))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_STREET_RACE4, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_STREET_RACE4, TRUE)
|
|
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_AIRPORT))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_05
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_FREEWAY))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_STREET_RACE5, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_STREET_RACE5, TRUE)
|
|
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_FREEWAY))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STREET_RACE_06
|
|
IF NOT IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_VESPUCCI_CANALS))
|
|
//SET_STATIC_BLIP_COLOUR(STATIC_BLIP_MINIGAME_STREET_RACE6, ENUM_TO_INT(BLIP_COLOUR_YELLOW))
|
|
SET_STATIC_BLIP_HAS_CHECKMARK(STATIC_BLIP_MINIGAME_STREET_RACE6, TRUE)
|
|
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceWon, ENUM_TO_INT(STREET_RACE_VESPUCCI_CANALS))
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Handles loading/unloading rival ped and vehicle models
|
|
PROC LOAD_RIVAL_MODELS(BOOL b_load_models)
|
|
|
|
/*IF b_load_models = TRUE
|
|
AND IS_ENTITY_ALIVE(sPlayerVehicle.vehPlayerVehicle)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player car max speed ", GET_VEHICLE_ESTIMATED_MAX_SPEED(sPlayerVehicle.vehPlayerVehicle))
|
|
ENDIF*/
|
|
|
|
INT i_index
|
|
IF b_load_models = TRUE
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
IF sRacer[i_index].modelPed = DUMMY_MODEL_FOR_SCRIPT
|
|
OR sRacer[i_index].modelPed = DUMMY_MODEL_FOR_SCRIPT
|
|
SCRIPT_ASSERT("Replay in progress: Models haven't been specified for all rivals")
|
|
ENDIF
|
|
REQUEST_MODEL(sRacer[i_index].modelPed)
|
|
REQUEST_MODEL(sRacer[i_index].modelCar)
|
|
//CPRINTLN(DEBUG_MISSION, "Mission Race: Model ", i_index, " Max speed ", GET_VEHICLE_MODEL_ESTIMATED_MAX_SPEED(sRacer[i_index].modelCar))
|
|
ENDFOR
|
|
ELSE
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
SET_MODEL_AS_NO_LONGER_NEEDED(sRacer[i_index].modelPed)
|
|
SET_MODEL_AS_NO_LONGER_NEEDED(sRacer[i_index].modelCar)
|
|
ENDFOR
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Starts the race mixer and adds the AI racers to it
|
|
PROC START_RACE_MIXER()
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
START_AUDIO_SCENE("SEA_RACE_DURING_RACE")
|
|
ELSE
|
|
START_AUDIO_SCENE("STREET_RACE_DURING_RACE")
|
|
ENDIF
|
|
INT i_index
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRacer[i_index].viCar,"SEA_RACE_DURING_RACE_NPC_GENERAL")
|
|
ELSE
|
|
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRacer[i_index].viCar,"STREET_RACE_NPC_GENERAL")
|
|
ENDIF
|
|
ENDIF
|
|
ENDFOR
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Adds the closest racer to the audio mixer and removes the previous closest
|
|
PROC ADD_CLOSEST_RACER_TO_MIX()
|
|
IF GET_GAME_TIMER() > iRaceMixTimer
|
|
FLOAT fDist
|
|
FLOAT fClosestDist = 9999999.9
|
|
INT iClosestRacer
|
|
INT i_index
|
|
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
fDist = GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRacer[i_index].viCar)
|
|
IF fDist < fClosestDist
|
|
fDist = fClosestDist
|
|
iClosestRacer = i_index
|
|
ENDIF
|
|
ENDIF
|
|
ENDFOR
|
|
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
IF iPrevClosestRacer > -1 AND IS_VEHICLE_OK(sRacer[iPrevClosestRacer].viCar)
|
|
REMOVE_ENTITY_FROM_AUDIO_MIX_GROUP(sRacer[iPrevClosestRacer].viCar)
|
|
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRacer[iPrevClosestRacer].viCar,"SEA_RACE_DURING_RACE_NPC_GENERAL")
|
|
ENDIF
|
|
IF IS_VEHICLE_OK(sRacer[iClosestRacer].viCar)
|
|
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRacer[iClosestRacer].viCar,"SEA_RACE_DURING_RACE_COLSEST_NPC")
|
|
ENDIF
|
|
ELSE
|
|
IF iPrevClosestRacer > -1 AND IS_VEHICLE_OK(sRacer[iPrevClosestRacer].viCar)
|
|
REMOVE_ENTITY_FROM_AUDIO_MIX_GROUP(sRacer[iPrevClosestRacer].viCar)
|
|
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRacer[iPrevClosestRacer].viCar,"STREET_RACE_NPC_GENERAL")
|
|
ENDIF
|
|
IF IS_VEHICLE_OK(sRacer[iClosestRacer].viCar)
|
|
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRacer[iClosestRacer].viCar,"STREET_RACE_NPC_CLOSEST")
|
|
ENDIF
|
|
ENDIF
|
|
|
|
iPrevClosestRacer = iClosestRacer
|
|
iRaceMixTimer = GET_GAME_TIMER() + 2000
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Cleanup and terminate script
|
|
PROC RACE_CLEANUP(BOOL b_delete_racers)
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: SCRIPT_CLEANUP")
|
|
|
|
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
|
|
|
|
Stop_Finish_Cam(sRaceResults)
|
|
|
|
SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_NONE)
|
|
|
|
// Unlock new track?
|
|
IF sRaceHUD.iPlayerPosition = 1 OR sRaceHUD.iPlayerPosition = 2 OR sRaceHUD.iPlayerPosition = 3
|
|
CHECK_FOR_TRACK_UNLOCK()
|
|
ENDIF
|
|
|
|
// Update map blip if required
|
|
IF sRaceHUD.iPlayerPosition = 1
|
|
CHECK_FOR_MAP_BLIP_UPDATE()
|
|
ENDIF
|
|
|
|
// Allow player to fly through windscreen
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_WillFlyThroughWindscreen, TRUE)
|
|
ENDIF
|
|
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
SET_PED_HELMET(PLAYER_PED_ID(), TRUE)
|
|
ENDIF
|
|
|
|
// Restore peds
|
|
SET_REDUCE_PED_MODEL_BUDGET(FALSE)
|
|
SET_PED_POPULATION_BUDGET(3)
|
|
|
|
// Traffic and cops
|
|
SET_REDUCE_VEHICLE_MODEL_BUDGET(FALSE)
|
|
SET_VEHICLE_POPULATION_BUDGET(3)
|
|
SET_DISPATCH_COPS_FOR_PLAYER(PLAYER_ID(), TRUE)
|
|
SET_CREATE_RANDOM_COPS(TRUE)
|
|
SET_WANTED_LEVEL_MULTIPLIER(1)
|
|
SET_RANDOM_TRAINS(TRUE)
|
|
|
|
// Restore scenarios and vehicle gens
|
|
//REMOVE_SCENARIO_BLOCKING_AREA(scenarioBlockArea)
|
|
SET_SCENARIO_TYPE_ENABLED("DRIVE", TRUE)
|
|
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 100.0>>, TRUE)
|
|
|
|
// Remove checkpoints and street racers
|
|
CLEANUP_CHECKPOINTS()
|
|
CLEANUP_RACERS(b_delete_racers)
|
|
|
|
// Commenting out for now in case this is needed again
|
|
// CLEANUP_RACERS(FALSE)
|
|
|
|
// Unload all required rival models
|
|
// LOAD_RIVAL_MODELS(FALSE)
|
|
|
|
// Only try to remove the waypoint recording is it's been set
|
|
IF NOT IS_STRING_NULL_OR_EMPTY(sRaceWaypointRecording)
|
|
REMOVE_WAYPOINT_RECORDING(sRaceWaypointRecording)
|
|
ENDIF
|
|
|
|
// Remove the reward ped
|
|
SAFE_RELEASE_PED(piRewardPed)
|
|
|
|
SAFE_RELEASE_PED(piGridGirlOne)
|
|
SAFE_RELEASE_PED(piGridGirlTwo)
|
|
SAFE_RELEASE_PED(piGridGirlThree)
|
|
|
|
// Release stored player vehicle handle
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
IF NOT IS_ENTITY_DEAD(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_VEHICLE_STRONG(sPlayerVehicle.vehPlayerVehicle, FALSE)
|
|
SET_VEHICLE_HAS_STRONG_AXLES(sPlayerVehicle.vehPlayerVehicle, FALSE)
|
|
|
|
// In bike races set rivals as hard to knock off their bikes
|
|
//IF (sRaceData.eRaceType = RACETYPE_BIKE OR sRaceData.eRaceType = RACETYPE_SEA) AND IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PLAYER_PLAYING(PLAYER_ID())
|
|
IF sRaceData.eRaceType = RACETYPE_SEA AND IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PLAYER_PLAYING(PLAYER_ID())
|
|
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(PLAYER_PED_ID(), KNOCKOFFVEHICLE_DEFAULT)
|
|
ENDIF
|
|
ENDIF
|
|
SAFE_RELEASE_VEHICLE(sPlayerVehicle.vehPlayerVehicle)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Released vehPlayerVehicle")
|
|
ENDIF
|
|
|
|
// Turn off the slipstream effect
|
|
SET_ENABLE_VEHICLE_SLIPSTREAMING(FALSE)
|
|
|
|
// Reset the show laps when pressing Dpad variable
|
|
g_Show_Lap_Dpad = FALSE
|
|
|
|
// Release audio banks loaded for the intro sound
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
STOP_SOUND(iIntroSound)
|
|
RELEASE_SCRIPT_AUDIO_BANK()
|
|
ELSE
|
|
STOP_STREAM()
|
|
ENDIF
|
|
|
|
// Stop music
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
TRIGGER_MUSIC_EVENT("MGSR_STOP")
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
// ===========================================================================================================
|
|
// Helper Functions
|
|
// ===========================================================================================================
|
|
/// PURPOSE:
|
|
/// Checks if the player is in a suitable vehicle for the race
|
|
/// RETURNS:
|
|
/// TRUE if the player is in a suitable car
|
|
FUNC BOOL IS_PLAYER_IN_SUITABLE_RACE_CAR()
|
|
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
//VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE()
|
|
viPlayerMain = GET_PLAYERS_LAST_VEHICLE()
|
|
|
|
//IF IS_VEHICLE_OK(viPlayer)
|
|
IF IS_VEHICLE_OK(viPlayerMain)
|
|
//MODEL_NAMES mnPlayer = GET_ENTITY_MODEL(viPlayer)
|
|
MODEL_NAMES mnPlayer = GET_ENTITY_MODEL(viPlayerMain)
|
|
|
|
// General checks
|
|
IF IS_MODEL_POLICE_VEHICLE(mnPlayer)
|
|
//CPRINTLN(DEBUG_MISSION, "Player in police vehicle")
|
|
RETURN FALSE
|
|
ENDIF
|
|
// these vehicles aren't covered by the IS_MODEL_POLICE_VEHICLE function
|
|
IF mnPlayer = POLICE4
|
|
OR mnPlayer = POLICEOLD1
|
|
OR mnPlayer = POLICEOLD2
|
|
OR mnPlayer = FBI
|
|
OR mnPlayer = FBI2
|
|
OR mnPlayer = LGUARD
|
|
OR mnPlayer = SHERIFF
|
|
OR mnPlayer = SHERIFF2
|
|
//CPRINTLN(DEBUG_MISSION, "Player in police vehicle")
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF IS_THIS_MODEL_A_BIKE(mnPlayer)
|
|
OR IS_THIS_MODEL_A_BOAT(mnPlayer)
|
|
OR IS_THIS_MODEL_A_HELI(mnPlayer)
|
|
OR IS_THIS_MODEL_A_PLANE(mnPlayer)
|
|
//CPRINTLN(DEBUG_MISSION, "Player not in car")
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// Race blacklist
|
|
INT iIndex
|
|
MODEL_NAMES mBlacklist[89]
|
|
|
|
mBlacklist[0] = AMBULANCE
|
|
mBlacklist[1] = BENSON
|
|
mBlacklist[2] = BIFF
|
|
mBlacklist[3] = BUS
|
|
mBlacklist[4] = FIRETRUK
|
|
mBlacklist[5] = FORKLIFT
|
|
mBlacklist[6] = MULE
|
|
mBlacklist[7] = MULE2
|
|
mBlacklist[8] = PACKER
|
|
mBlacklist[9] = PHANTOM
|
|
mBlacklist[10] = MOWER
|
|
mBlacklist[11] = STOCKADE
|
|
mBlacklist[12] = SQUALO
|
|
mBlacklist[13] = MAVERICK
|
|
mBlacklist[14] = POLMAV
|
|
mBlacklist[15] = AIRTUG
|
|
mBlacklist[16] = PRANGER
|
|
mBlacklist[17] = ANNIHILATOR
|
|
mBlacklist[18] = DINGHY
|
|
mBlacklist[19] = POLICE
|
|
mBlacklist[20] = RIPLEY
|
|
mBlacklist[21] = TRASH
|
|
mBlacklist[22] = BURRITO
|
|
mBlacklist[23] = PONY
|
|
mBlacklist[24] = SPEEDO
|
|
mBlacklist[25] = MARQUIS
|
|
mBlacklist[26] = SANCHEZ
|
|
mBlacklist[27] = AIRTUG
|
|
mBlacklist[28] = TACO
|
|
mBlacklist[29] = BARRACKS
|
|
mBlacklist[30] = ROMERO
|
|
mBlacklist[31] = BLAZER
|
|
mBlacklist[32] = BLAZER2
|
|
mBlacklist[33] = BODHI2
|
|
mBlacklist[34] = BOXVILLE2
|
|
mBlacklist[35] = BULLDOZER
|
|
mBlacklist[36] = CADDY
|
|
mBlacklist[37] = CADDY2
|
|
mBlacklist[38] = CAMPER
|
|
mBlacklist[39] = TIPTRUCK
|
|
mBlacklist[40] = TOURBUS
|
|
mBlacklist[41] = TOWTRUCK
|
|
mBlacklist[42] = TOWTRUCK2
|
|
mBlacklist[43] = TRACTOR
|
|
mBlacklist[44] = TRACTOR2
|
|
mBlacklist[45] = UTILLITRUCK
|
|
mBlacklist[46] = UTILLITRUCK2
|
|
mBlacklist[47] = UTILLITRUCK3
|
|
mBlacklist[48] = RATLOADER
|
|
mBlacklist[49] = DLOADER
|
|
mBlacklist[50] = DOCKTUG
|
|
mBlacklist[51] = DUMP
|
|
mBlacklist[52] = GBURRITO
|
|
mBlacklist[53] = HANDLER
|
|
mBlacklist[54] = HAULER
|
|
mBlacklist[55] = JOURNEY
|
|
mBlacklist[56] = RENTALBUS
|
|
mBlacklist[57] = MIXER
|
|
mBlacklist[58] = RHINO
|
|
mBlacklist[59] = CUTTER
|
|
mBlacklist[60] = POUNDER
|
|
mBlacklist[61] = TIPTRUCK2
|
|
mBlacklist[62] = MIXER2
|
|
mBlacklist[63] = RUBBLE
|
|
mBlacklist[64] = SCRAP
|
|
mBlacklist[65] = ARMYTANKER
|
|
mBlacklist[66] = BARRACKS2
|
|
mBlacklist[67] = AIRBUS
|
|
mBlacklist[68] = COACH
|
|
mBlacklist[69] = PBUS
|
|
mBlacklist[70] = RIOT
|
|
mBlacklist[71] = BOXVILLE3
|
|
mBlacklist[72] = STOCKADE3
|
|
mBlacklist[73] = FLATBED
|
|
mBlacklist[74] = BOXVILLE
|
|
mBlacklist[75] = BURRITO2
|
|
mBlacklist[76] = BURRITO3
|
|
mBlacklist[77] = BURRITO4
|
|
mBlacklist[78] = RUMPO
|
|
mBlacklist[79] = SPEEDO2
|
|
mBlacklist[80] = BLIMP
|
|
mBlacklist[81] = BLIMP2
|
|
mBlacklist[82] = SUBMERSIBLE
|
|
mBlacklist[83] = SUBMERSIBLE2
|
|
mBlacklist[84] = BLAZER3
|
|
mBlacklist[85] = PONY2
|
|
mBlacklist[86] = RUMPO2
|
|
mBlacklist[87] = TAXI
|
|
mBlacklist[88] = DUMMY_MODEL_FOR_SCRIPT
|
|
|
|
REPEAT COUNT_OF(mBlacklist) iIndex
|
|
IF mnPlayer = mBlacklist[iIndex]
|
|
//CPRINTLN(DEBUG_MISSION, "Player in unsuitable car")
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
//CPRINTLN(DEBUG_MISSION, "Player in OK car")
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//CPRINTLN(DEBUG_MISSION, "Player not in vehicle")
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Is the player on a motorbike (not bicycle or quad bike)
|
|
FUNC BOOL IS_PLAYER_ON_SUITABLE_BIKE()
|
|
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
viPlayerMain = GET_PLAYERS_LAST_VEHICLE()
|
|
|
|
IF IS_VEHICLE_OK(viPlayerMain)
|
|
MODEL_NAMES model = GET_ENTITY_MODEL(viPlayerMain)
|
|
IF IS_THIS_MODEL_A_BIKE(model)
|
|
AND NOT IS_THIS_MODEL_A_BICYCLE(model)
|
|
AND NOT IS_MODEL_POLICE_VEHICLE(model)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Is the player in a race suitable sea vehicle
|
|
FUNC BOOL IS_PLAYER_IN_SUITABLE_SEA_VEHICLE()
|
|
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
viPlayerMain = GET_PLAYERS_LAST_VEHICLE()
|
|
|
|
IF IS_VEHICLE_OK(viPlayerMain)
|
|
MODEL_NAMES model = GET_ENTITY_MODEL(viPlayerMain)
|
|
IF model = SEASHARK
|
|
OR model = SEASHARK2
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Fade out for the Races
|
|
PROC SAFE_RACE_FADE_OUT(INT iTime = 500, BOOL bWaitForFade = TRUE)
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: SAFE_RACE_FADE_OUT")
|
|
IF IS_SCREEN_FADED_IN()
|
|
IF NOT IS_SCREEN_FADING_OUT()
|
|
DO_SCREEN_FADE_OUT(iTime)
|
|
IF bWaitForFade
|
|
WHILE NOT IS_SCREEN_FADED_OUT()
|
|
WAIT(0)
|
|
ENDWHILE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Fade in for the Races
|
|
PROC SAFE_RACE_FADE_IN(INT iTime = 500, BOOL bWaitForFade = TRUE)
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: SAFE_RACE_FADE_IN")
|
|
IF IS_SCREEN_FADED_OUT()
|
|
IF NOT IS_SCREEN_FADING_IN()
|
|
DO_SCREEN_FADE_IN(iTime)
|
|
IF bWaitForFade
|
|
WHILE NOT IS_SCREEN_FADED_IN()
|
|
WAIT(0)
|
|
ENDWHILE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC SetupGridGirlPositions()
|
|
SWITCH sRaceData.eRaceTrack
|
|
|
|
// South Los Santos
|
|
CASE STREET_RACE_01
|
|
vGridGirlOnePos = <<-155.646805,-1566.948730,33.993595>>
|
|
vGridGirlTwoPos = <<-153.63, -1563.70, 34.95>>
|
|
vGridGirlThreePos = <<-148.09, -1557.66, 34.75>>
|
|
fGridGirlHeading = -30.86
|
|
vGridGirlTarget = <<-141.65, -1550.75, 33.46>>
|
|
//vGridGirlCountPos = <<-163.53, -1564.02, 35.19>>
|
|
BREAK
|
|
|
|
// City Circuit
|
|
CASE STREET_RACE_02
|
|
vGridGirlOnePos = <<367.616058,312.457153,102.586121>>
|
|
vGridGirlTwoPos = <<368.454742,312.210846,102.567795>>//<<369.88, 312.04, 103.54>>
|
|
vGridGirlThreePos = <<375.17, 310.64, 103.44>>
|
|
fGridGirlHeading = -103.75
|
|
vGridGirlTarget = <<386.63, 307.77, 102.20>>
|
|
//vGridGirlCountPos = <<367.43, 320.07, 103.59>>
|
|
BREAK
|
|
|
|
// Airport
|
|
CASE STREET_RACE_04
|
|
vGridGirlOnePos = <<-813.803345,-2546.800781,12.800132>>
|
|
vGridGirlTwoPos = <<-814.429321,-2547.747559,12.800570>>//<<-814.614685,-2547.981445,12.800852>>//<<-814.88, -2549.98, 13.79>>
|
|
vGridGirlThreePos = <<-816.56, -2554.45, 13.77>>
|
|
fGridGirlHeading = 157.75
|
|
vGridGirlTarget = <<-819.68, -2562.68, 12.75>>
|
|
//vGridGirlCountPos = <<-805.14, -2545.79, 13.76>>
|
|
BREAK
|
|
|
|
// Freeway
|
|
CASE STREET_RACE_05
|
|
vGridGirlOnePos = <<777.396179,-1148.09,28.059130>>
|
|
vGridGirlTwoPos = <<778.631165,-1148.070068,28.008192>>//<<781.51, -1148.08, 28.93>>
|
|
vGridGirlThreePos = <<787.00, -1148.06, 28.92>>
|
|
fGridGirlHeading = -89.30
|
|
vGridGirlTarget = <<795.30, -1147.23, 27.98>>
|
|
//vGridGirlCountPos = <<779.19, -1139.34, 28.93>>
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
PROC SETUP_GRID_GIRLS()
|
|
IF sRaceData.eRaceType = RACETYPE_CAR
|
|
REQUEST_MODEL(A_F_Y_Genhot_01)
|
|
REQUEST_ANIM_DICT(sAnimDict)
|
|
SetupGridGirlPositions()
|
|
|
|
WHILE NOT HAS_MODEL_LOADED(A_F_Y_Genhot_01)
|
|
WAIT(0)
|
|
ENDWHILE
|
|
WHILE NOT HAS_ANIM_DICT_LOADED(sAnimDict)
|
|
WAIT(0)
|
|
ENDWHILE
|
|
|
|
piGridGirlOne = CREATE_PED(PEDTYPE_SPECIAL, A_F_Y_Genhot_01, vGridGirlOnePos, fGridGirlHeading)
|
|
SET_ENTITY_HEADING_FACE_COORDS(piGridGirlOne, vGridGirlTarget)
|
|
piGridGirlTwo = CREATE_PED(PEDTYPE_SPECIAL, A_F_Y_Genhot_01, vGridGirlTwoPos, fGridGirlHeading)
|
|
SET_ENTITY_HEADING_FACE_COORDS(piGridGirlTwo, vGridGirlTarget)
|
|
piGridGirlThree = CREATE_PED(PEDTYPE_SPECIAL, A_F_Y_Genhot_01, vGridGirlThreePos, fGridGirlHeading)
|
|
SET_ENTITY_HEADING_FACE_COORDS(piGridGirlThree, vGridGirlTarget)
|
|
|
|
SEQUENCE_INDEX siGridGirl
|
|
|
|
TASK_PAUSE(piGridGirlOne, -1)
|
|
ADD_PED_FOR_DIALOGUE(pedConvStruct, 3, piGridGirlOne, "GIRL1")
|
|
bGridGirlOneConvReady = TRUE
|
|
|
|
VECTOR vDestination
|
|
|
|
vDestination = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(piGridGirlTwo, <<0,20,0>>)
|
|
OPEN_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PLAY_ANIM(NULL, sAnimDict, "grid_girl_a", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE | AF_LOOPING)
|
|
TASK_GO_STRAIGHT_TO_COORD(NULL, vDestination, PEDMOVE_WALK)
|
|
TASK_WANDER_STANDARD(NULL)
|
|
CLOSE_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PERFORM_SEQUENCE(piGridGirlTwo, siGridGirl)
|
|
CLEAR_SEQUENCE_TASK(siGridGirl)
|
|
|
|
vDestination = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(piGridGirlThree, <<0,15,0>>)
|
|
OPEN_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PLAY_ANIM(NULL, sAnimDict, "grid_girl_b", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE | AF_LOOPING)
|
|
TASK_GO_STRAIGHT_TO_COORD(NULL, vDestination, PEDMOVE_WALK)
|
|
TASK_WANDER_STANDARD(NULL)
|
|
CLOSE_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PERFORM_SEQUENCE(piGridGirlThree, siGridGirl)
|
|
CLEAR_SEQUENCE_TASK(siGridGirl)
|
|
ADD_PED_FOR_DIALOGUE(pedConvStruct, 4, piGridGirlThree, "GIRL2")
|
|
bGridGirlThreeConvReady = TRUE
|
|
|
|
SET_MODEL_AS_NO_LONGER_NEEDED(A_F_Y_Genhot_01)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC SET_GRID_GIRLS_FOR_COUNTDOWN(FLOAT fStartPhase)
|
|
IF sRaceData.eRaceType = RACETYPE_CAR
|
|
IF IS_PED_UNINJURED(piGridGirlOne)
|
|
/*SET_ENTITY_COORDS_GROUNDED(piGridGirlOne, vGridGirlOnePos) //vGridGirlCountPos)
|
|
SET_ENTITY_HEADING(piGridGirlOne, fGridGirlHeading)*/
|
|
SEQUENCE_INDEX siGridGirl
|
|
OPEN_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PLAY_ANIM(NULL, sAnimDict, "grid_girl_race_start", SLOW_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE, fStartPhase)
|
|
TASK_GO_STRAIGHT_TO_COORD(NULL, vGridGirlTarget, PEDMOVE_WALK)
|
|
TASK_WANDER_STANDARD(NULL)
|
|
CLOSE_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PERFORM_SEQUENCE(piGridGirlOne, siGridGirl)
|
|
CLEAR_SEQUENCE_TASK(siGridGirl)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC CLEANUP_GRID_GIRLS()
|
|
IF sRaceData.eRaceType = RACETYPE_CAR
|
|
SEQUENCE_INDEX siGridGirl
|
|
VECTOR vDestination
|
|
|
|
IF IS_PED_UNINJURED(piGridGirlTwo)
|
|
vDestination = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(piGridGirlTwo, <<0,20,0>>)
|
|
OPEN_SEQUENCE_TASK(siGridGirl)
|
|
TASK_GO_STRAIGHT_TO_COORD(NULL, vDestination, PEDMOVE_WALK)
|
|
TASK_WANDER_STANDARD(NULL)
|
|
CLOSE_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PERFORM_SEQUENCE(piGridGirlTwo, siGridGirl)
|
|
CLEAR_SEQUENCE_TASK(siGridGirl)
|
|
ENDIF
|
|
|
|
IF IS_PED_UNINJURED(piGridGirlThree)
|
|
vDestination = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(piGridGirlThree, <<0,15,0>>)
|
|
OPEN_SEQUENCE_TASK(siGridGirl)
|
|
TASK_GO_STRAIGHT_TO_COORD(NULL, vDestination, PEDMOVE_WALK)
|
|
TASK_WANDER_STANDARD(NULL)
|
|
CLOSE_SEQUENCE_TASK(siGridGirl)
|
|
TASK_PERFORM_SEQUENCE(piGridGirlThree, siGridGirl)
|
|
CLEAR_SEQUENCE_TASK(siGridGirl)
|
|
ENDIF
|
|
|
|
SAFE_RELEASE_PED(piGridGirlOne)
|
|
SAFE_RELEASE_PED(piGridGirlTwo)
|
|
SAFE_RELEASE_PED(piGridGirlThree)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC SETUP_SEA_RACERS_AT_END()
|
|
INT i_index
|
|
VECTOR vNewPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
FLOAT fNewHead
|
|
SWITCH sRaceData.eRaceTrack
|
|
CASE SEA_RACE_01
|
|
fNewHead = 180.8171
|
|
BREAK
|
|
CASE SEA_RACE_02
|
|
fNewHead = 49.2605
|
|
BREAK
|
|
CASE SEA_RACE_03
|
|
fNewHead = 69.4601
|
|
BREAK
|
|
CASE SEA_RACE_04
|
|
fNewHead = 191.0019
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
IF IS_PED_UNINJURED(sRacer[i_index].piDriver) AND IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
CLEAR_PED_TASKS(sRacer[i_index].piDriver)
|
|
SET_ENTITY_HEADING(sRacer[i_index].piDriver, fNewHead)
|
|
SWITCH i_index
|
|
CASE 0
|
|
IF sRaceData.eRaceTrack = SEA_RACE_04
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vNewPos+<<10,-10,0>>)
|
|
ELSE
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vNewPos+<<10,0,0>>)
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE 1
|
|
IF sRaceData.eRaceTrack = SEA_RACE_04
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vNewPos+<<0,-10,0>>)
|
|
ELSE
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vNewPos+<<0,10,0>>)
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE 2
|
|
IF sRaceData.eRaceTrack = SEA_RACE_04
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vNewPos+<<-10,-12,0>>)
|
|
ELSE
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vNewPos+<<10,10,0>>)
|
|
ENDIF
|
|
BREAK
|
|
|
|
DEFAULT
|
|
SAFE_DELETE_PED(sRacer[i_index].piDriver)
|
|
SAFE_DELETE_VEHICLE(sRacer[i_index].viCar)
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDIF
|
|
ENDFOR
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Common setup when triggering the race cutscene
|
|
PROC START_RACE_CUTSCENE()
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: START_RACE_CUTSCENE")
|
|
|
|
// Disable player control
|
|
PLAYER_INDEX pId = GET_PLAYER_INDEX()
|
|
|
|
IF IS_PLAYER_PLAYING(pId)
|
|
|
|
// Stop player control
|
|
SET_PLAYER_CONTROL(pId, FALSE, SPC_REMOVE_EXPLOSIONS)
|
|
SET_PLAYER_CONTROL(pId, FALSE, SPC_REMOVE_PROJECTILES)
|
|
|
|
// Reset wanted level
|
|
SET_PLAYER_WANTED_LEVEL(pId,0)
|
|
SET_PLAYER_WANTED_LEVEL_NOW(pId)
|
|
|
|
// Stop anyone from attacking the player
|
|
SET_EVERYONE_IGNORE_PLAYER(pId, TRUE)
|
|
|
|
// Make player invisible as will be repositioned from cloud data
|
|
/*SET_ENTITY_VISIBLE(PLAYER_PED_ID(), FALSE)
|
|
|
|
// Get vehicle reference
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_ENTITY_VISIBLE(sPlayerVehicle.vehPlayerVehicle, FALSE)
|
|
ENDIF*/
|
|
ENDIF
|
|
|
|
// Setup systems for scripted cutscene
|
|
SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE,DEFAULT,FALSE)
|
|
|
|
// Clear area around race location
|
|
CLEAR_AREA(GET_PLAYER_COORDS(pId), 50.0, TRUE)
|
|
CLEAR_AREA_OF_VEHICLES(GET_PLAYER_COORDS(pId), 500.0) // use a big area since ambient vehicles get turned off anyway
|
|
CLEAR_AREA_OF_PEDS(GET_PLAYER_COORDS(pId), 500.0)
|
|
|
|
SET_RANDOM_TRAINS(FALSE)
|
|
DELETE_ALL_TRAINS()
|
|
|
|
// Remove radar and HUD
|
|
DISPLAY_RADAR(FALSE)
|
|
DISPLAY_HUD(FALSE)
|
|
|
|
// Clear objective and help text
|
|
CLEAR_PRINTS()
|
|
CLEAR_HELP()
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Restore player control and script systems
|
|
PROC END_RACE_CUTSCENE()
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: END_RACE_CUTSCENE")
|
|
PLAYER_INDEX pId = GET_PLAYER_INDEX()
|
|
|
|
SAFE_RELEASE_PED(piGridGirlOne)
|
|
SAFE_RELEASE_PED(piGridGirlTwo)
|
|
SAFE_RELEASE_PED(piGridGirlThree)
|
|
|
|
IF IS_PLAYER_PLAYING(pId)
|
|
SET_EVERYONE_IGNORE_PLAYER(pId, FALSE)
|
|
SET_PLAYER_CONTROL(pId, TRUE)
|
|
ENDIF
|
|
|
|
IF sRaceData.eRaceType = RACETYPE_BIKE OR sRaceData.eRaceType = RACETYPE_CAR
|
|
REMOVE_SCENARIO_BLOCKING_AREA(sbiRaceStart)
|
|
SET_ROADS_BACK_TO_ORIGINAL_IN_ANGLED_AREA(vRaceRoadPos1, vRaceRoadPos2, fRaceRoadWidth)
|
|
ENDIF
|
|
|
|
SET_SCRIPTS_SAFE_FOR_CUTSCENE(FALSE,DEFAULT,FALSE)
|
|
|
|
DISPLAY_RADAR(TRUE)
|
|
DISPLAY_HUD(TRUE)
|
|
CLEAR_HELP()
|
|
ENDPROC
|
|
|
|
PROC CHECK_PLAYER_SHOOTING_IN_COUNTDOWN()
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_SHOOTING(PLAYER_PED_ID())
|
|
AND IS_PED_ARMED(PLAYER_PED_ID(), WF_INCLUDE_GUN|WF_INCLUDE_PROJECTILE)
|
|
failReason = FAIL_RIVAL_ATTACKED
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
|
|
IF IS_PED_UNINJURED(piGridGirlOne)
|
|
TASK_SMART_FLEE_PED(piGridGirlOne, PLAYER_PED_ID(), 500, -1)
|
|
SET_PED_KEEP_TASK(piGridGirlOne, TRUE)
|
|
ENDIF
|
|
IF IS_PED_UNINJURED(piGridGirlTwo)
|
|
TASK_SMART_FLEE_PED(piGridGirlTwo, PLAYER_PED_ID(), 500, -1)
|
|
SET_PED_KEEP_TASK(piGridGirlTwo, TRUE)
|
|
ENDIF
|
|
IF IS_PED_UNINJURED(piGridGirlThree)
|
|
TASK_SMART_FLEE_PED(piGridGirlThree, PLAYER_PED_ID(), 500, -1)
|
|
SET_PED_KEEP_TASK(piGridGirlThree, TRUE)
|
|
ENDIF
|
|
|
|
SEQUENCE_INDEX siLeave
|
|
INT i_index = 0
|
|
REPEAT sTrackData.iNumAIRacers i_index
|
|
IF IS_PED_UNINJURED(sRacer[i_index].piDriver)
|
|
OPEN_SEQUENCE_TASK(siLeave)
|
|
TASK_PAUSE(NULL, i_index*60)
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
AND IS_PED_IN_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar)
|
|
TASK_VEHICLE_DRIVE_WANDER(NULL, sRacer[i_index].viCar, 50, DRIVINGMODE_AVOIDCARS_RECKLESS)
|
|
ELSE
|
|
TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 500, -1)
|
|
ENDIF
|
|
CLOSE_SEQUENCE_TASK(siLeave)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, siLeave)
|
|
CLEAR_SEQUENCE_TASK(siLeave)
|
|
SET_PED_KEEP_TASK(sRacer[i_index].piDriver, TRUE)
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
SET_BOAT_ANCHOR(sPlayerVehicle.vehPlayerVehicle, FALSE)
|
|
ELSE
|
|
SET_VEHICLE_HANDBRAKE(sPlayerVehicle.vehPlayerVehicle, FALSE)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
END_RACE_CUTSCENE()
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_RACER_OK(INT i_index)
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].piDriver)
|
|
IF IS_ENTITY_DEAD(sRacer[i_index].piDriver)
|
|
failReason = FAIL_RIVAL_DEAD
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ELIF IS_PED_INJURED(sRacer[i_index].piDriver)
|
|
failReason = FAIL_RIVAL_DEAD
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ELIF IS_PLAYER_SHOOTING_NEAR_PED(sRacer[i_index].piDriver)
|
|
failReason = FAIL_RIVAL_ATTACKED
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ENDIF
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
IF IS_ENTITY_DEAD(sRacer[i_index].viCar)
|
|
failReason = FAIL_RIVAL_DEAD
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(sRacer[i_index].viCar, PLAYER_PED_ID(), FALSE)
|
|
failReason = FAIL_RIVAL_ATTACKED
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ENDIF
|
|
ENDIF
|
|
IF IS_ENTITY_ALIVE(sRacer[i_index].piDriver)
|
|
AND IS_ENTITY_ALIVE(sRacer[i_index].viCar)
|
|
RETURN TRUE
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
PROC SUPPRESS_LARGE_VEHICLES(BOOL bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(AIRBUS, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(BENSON, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(BIFF, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(COACH, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(FIRETRUK, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(FLATBED, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(MULE, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(MULE2, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(PACKER, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(POUNDER, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(RUBBLE, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(TIPTRUCK, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(TIPTRUCK2, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(TOURBUS, bSuppress)
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(TRASH, bSuppress)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player is driving a large vehicle
|
|
/// RETURNS:
|
|
/// true if the player is driving a large vehicle
|
|
FUNC BOOL PLAYERS_CAR_IS_BIG()
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
MODEL_NAMES mnCar = GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle)
|
|
|
|
IF mnCar = BALLER
|
|
OR mnCar = BALLER2
|
|
OR mnCar = BISON
|
|
OR mnCar = BISON2
|
|
OR mnCar = BISON3
|
|
OR mnCar = BOBCATXL
|
|
OR mnCar = CAVALCADE
|
|
OR mnCar = CAVALCADE2
|
|
OR mnCar = CRUSADER
|
|
OR mnCar = DUBSTA
|
|
OR mnCar = DUBSTA2
|
|
OR mnCar = FQ2
|
|
OR mnCar = GRANGER
|
|
OR mnCar = GRESLEY
|
|
OR mnCar = LANDSTALKER
|
|
OR mnCar = MESA
|
|
OR mnCar = MESA2
|
|
OR mnCar = MESA3
|
|
OR mnCar = PATRIOT
|
|
OR mnCar = RADI
|
|
OR mnCar = RANCHERXL
|
|
OR mnCar = RANCHERXL2
|
|
OR mnCar = REBEL
|
|
OR mnCar = ROCOTO
|
|
OR mnCar = SADLER
|
|
OR mnCar = SADLER2
|
|
OR mnCar = SANDKING
|
|
OR mnCar = SANDKING2
|
|
OR mnCar = SEMINOLE
|
|
OR mnCar = SUPERD
|
|
OR mnCar = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("huntley"))
|
|
OR mnCar = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("DUBSTA3"))
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player is driving a very large vehicle
|
|
/// RETURNS:
|
|
/// TRUE if the player is driving a very large vehicle
|
|
FUNC BOOL PLAYERS_CAR_IS_VERY_BIG()
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
MODEL_NAMES mnCar = GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle)
|
|
|
|
IF mnCar = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("MONSTER"))
|
|
OR mnCar = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("MARSHALL"))
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
// ===========================================================================================================
|
|
// Mission Functions
|
|
// ===========================================================================================================
|
|
/// PURPOSE: Setup camera shots for race lineup
|
|
PROC SETUP_RACE_CAMERAS()
|
|
|
|
IF sRaceData.eRaceType = RACETYPE_CAR
|
|
// Need to use different cameras based on what car the player is driving
|
|
IF PLAYERS_CAR_IS_BIG()
|
|
vStartPos = <<-0.7054, 6.3148, 2.0821>>
|
|
vStartRot = <<0.9495, 3.9011, 2.7419>>
|
|
vEndPos = <<-0.5670, 2.6724, 1.0077>>
|
|
vEndRot = <<0.0940, -0.2423, 0.7483>>
|
|
ELIF PLAYERS_CAR_IS_VERY_BIG()
|
|
vStartPos = <<-1.6831, 6.0271, 4.2228>>
|
|
vStartRot = <<-0.0245, 3.5705, 4.6855>>
|
|
vEndPos = <<-1.0281, 4.6872, 0.9868>>
|
|
vEndRot = <<-0.1850, 1.8112, 1.1221>>
|
|
ELSE
|
|
vStartPos = <<-1.5802, 5.8398, 2.2274>>
|
|
vStartRot = <<0.1970, 3.5006, 2.8356>>
|
|
vEndPos = <<-0.6678, 1.9740, 0.6876>>
|
|
vEndRot = <<0.1440, -0.9013, 0.4170>>
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//Setup our cameras for the intro.
|
|
SWITCH sRaceData.eRaceTrack
|
|
|
|
// South Los Santos
|
|
CASE STREET_RACE_01
|
|
vStartPos2 = <<-159.215897,-1564.124756,34.616402>>
|
|
vStartRot2 = <<-0.073293,0.055000,-119.273537>>
|
|
vEndPos2 = <<-158.811478,-1563.368530,34.617287>>
|
|
vEndRot2 = <<-0.073293,0.055000,-123.730537>>
|
|
|
|
vStartPos3 = <<-156.860825,-1565.342407,35.709652>>
|
|
vStartRot3 = <<-8.040299,-0.000500,-49.006474>>
|
|
vEndPos3 = <<-155.176834,-1567.141479,35.709652>>
|
|
vEndRot3 = <<-8.040299,-0.000500,-41.346287>>
|
|
|
|
vStartPos4 = <<-142.312408,-1550.573608,34.580471>>
|
|
vStartRot4 = <<-2.928405,-0.000499,142.620285>>
|
|
vEndPos4 = <<-141.3225, -1546.8904, 34.7891>>
|
|
vEndRot4 = <<-2.8368, -0.0000, 139.8128>>
|
|
BREAK
|
|
|
|
// City Circuit
|
|
CASE STREET_RACE_02
|
|
vStartPos2 = <<368.3612, 317.4821, 102.8912>>
|
|
vStartRot2 = <<4.9194, 0.0225, -176.9747>>
|
|
vEndPos2 = <<369.0639, 317.4726, 102.8941>>
|
|
vEndRot2 = <<5.0420, 0.0225, 178.1396>>
|
|
|
|
vStartPos3 = <<367.0291, 314.8014, 104.3700>>
|
|
vStartRot3 = <<-7.4995, 0.0233, -111.5294>>
|
|
vEndPos3 = <<366.4452, 312.9081, 104.3692>>
|
|
vEndRot3 = <<-7.4995, 0.0233, -100.7122>>
|
|
|
|
vStartPos4 = <<386.8919, 308.6107, 103.2039>>
|
|
vStartRot4 = <<0.3447, 0.0472, 82.1591>>
|
|
vEndPos4 = <<390.2213, 309.4721, 103.7617>>//<<390.0258, 309.9036, 103.8237>>
|
|
vEndRot4 = <<-4.3057, 0.0299, 76.2809>>//<<-9.7627, 0.0472, 75.7797>>
|
|
BREAK
|
|
|
|
// Airport
|
|
CASE STREET_RACE_04
|
|
vStartPos2 = <<-809.5582, -2548.8481, 13.2619>>
|
|
vStartRot2 = <<6.3036, 0.0031, 78.7380>>
|
|
vEndPos2 = <<-809.6061, -2549.2407, 13.2619>>
|
|
vEndRot2 = <<3.5967, 0.0031, 75.5951>>
|
|
|
|
vStartPos3 = <<-811.1327, -2544.3936, 14.5064>>
|
|
vStartRot3 = <<-5.1571, 0.0031, 151.0646>>
|
|
vEndPos3 = <<-812.3164, -2543.7571, 14.5063>>
|
|
vEndRot3 = <<-5.1571, 0.0031, 154.2332>>
|
|
|
|
vStartPos4 = <<-819.8916, -2564.1191, 13.8366>>
|
|
vStartRot4 = <<-3.7349, 0.0039, -21.4233>>
|
|
vEndPos4 = <<-819.4815, -2566.3877, 14.1387>>
|
|
vEndRot4 = <<-5.6248, 0.0039, -24.2558>>
|
|
BREAK
|
|
|
|
// Freeway
|
|
CASE STREET_RACE_05
|
|
vStartPos2 = <<776.7724, -1143.7301, 28.3016>>
|
|
vStartRot2 = <<11.6472, -0.0085, -162.2849>>
|
|
vEndPos2 = <<778.1360, -1143.3521, 28.3014>>
|
|
vEndRot2 = <<10.4548, -0.0085, -170.7270>>
|
|
|
|
vStartPos3 = <<775.2812, -1146.7396, 29.6806>>
|
|
vStartRot3 = <<-6.3919, -0.0085, -92.6672>>
|
|
vEndPos3 = <<775.3398, -1148.5911, 29.6808>>
|
|
vEndRot3 = <<-6.3919, -0.0085, -84.5603>>
|
|
|
|
vStartPos4 = <<795.9290, -1146.4519, 29.5086>>
|
|
vStartRot4 = <<-2.9460, -0.0103, 96.9974>>
|
|
vEndPos4 = <<799.1780, -1144.6638, 29.6776>>
|
|
vEndRot4 = <<-3.7454, -0.0103, 96.6498>>
|
|
BREAK
|
|
|
|
// Vespucci Canals
|
|
CASE STREET_RACE_06
|
|
vStartPos = <<-1081.7926, -1162.1034, 6.1895>>//<<-1089.3351, -1169.4821, 5.6114>>//<<-0.7720, 4.3825, 3.2025>>//<<-2.8850, 7.6435, 0.1487>>
|
|
vStartRot = <<9.5571, 0.0247, 143.3313>>//<<7.2179, 0.0136, 150.2166>>//<<0.7560, 1.8015, 3.2625>>//<<-1.2368, 5.2159, 0.7739>>
|
|
vEndPos = <<-0.2995, 1.6679, 0.9952>>//<<-0.740853,1.714846,0.995416>>//<<-0.7403, 1.4276, 0.3739>>
|
|
vEndRot = <<0.7073, -1.1228, 0.5493>>//<<-0.0425, -1.4900, 0.3528>>
|
|
|
|
vStartPos2 = <<-1059.430298,-1154.966675,1.585626>>//<<-1060.2167, -1154.1942, 1.6801>>//<<-1061.4971, -1154.3755, 1.5735>>
|
|
vStartRot2 = <<5.101318,0.220638,46.046375>>//<<4.2472, 0.1153, 54.0298>>//<<7.5848, 0.0002, 49.8066>>
|
|
vEndPos2 = <<-1060.098877,-1155.653564,1.589301>>//<<-1061.1595, -1155.4127, 1.6868>>//<<-1062.5969, -1156.5006, 1.5319>>
|
|
vEndRot2 = <<5.101318,0.220639,55.210567>>//<<4.2472, 0.1153, 50.3485>>//<<7.6255, 0.0002, 46.0695>>
|
|
|
|
vStartPos3 = <<-1057.832642,-1153.639648,2.157057>>//<<-1058.7335, -1151.7834, 2.0384>>
|
|
vStartRot3 = <<-1.541381,0.155416,92.089836>>//<<4.6126, 0.1930, 111.5182>>
|
|
vEndPos3 = <<-1058.799072,-1151.694580,3.019048>>//<<-1059.2340, -1150.5060, 2.9722>>
|
|
vEndRot3 = <<-8.483372,0.155417,120.072861>>//<<-2.6296, 0.1930, 121.5018>>
|
|
|
|
vStartPos4 = <<-1073.324341,-1160.225464,2.467393>>//<<-1073.0204, -1158.7783, 2.1917>>
|
|
vStartRot4 = <<-9.078616,0.014872,-56.525623>>//<<5.2140, 0.0002, -55.0704>>
|
|
vEndPos4 = <<-1074.406738,-1161.540771,2.727543>>//<<-1074.1484, -1160.3064, 2.9714>>
|
|
vEndRot4 = <<-9.078616,0.014872,-56.525623>>//<<-8.1078, 0.0002, -56.6515>>
|
|
BREAK
|
|
|
|
// East Coast
|
|
CASE SEA_RACE_01
|
|
vStartPos = <<3071.705322,680.428650,-0.578093>>//<<3065.011719,655.342773,-1.230181>>//<< 3088.8801, 651.6200, 8.7519 >>
|
|
vStartRot = <<-14.997413,0.000000,169.470261>>//<<-14.041778,0.000000,173.785065>>//<< 0.6311, -1.0914, 54.0716 >>
|
|
vMidPos = <<3071.258057,678.948547,3.839843>>//<<3065.253662,654.307251,2.788802>>//<< 3088.8801, 651.6200, 8.7519 >>
|
|
vMidRot = <<-0.639399,0.000000,168.924576>>//<<0.727129,0.000000,173.297226>>//<< -16.2995, -1.0914, 129.8059 >>
|
|
vEndPos = <<3070.761230,677.424866,3.822088>>//<<3065.399658,653.291687,2.795851>>
|
|
vEndRot = <<-0.639399,-0.000000,169.174271>>//<<-0.507238,0.000000,176.951553>>
|
|
|
|
vStartPos2 = <<3074.792236,632.816650,2.242464>>
|
|
vStartRot2 = <<0.235991,0.000000,58.909027>>
|
|
vEndPos2 = <<3072.678711,629.829773,2.241469>>
|
|
vEndRot2 = <<0.235991,0.000000,32.618481>>
|
|
BREAK
|
|
|
|
// North East Coast
|
|
CASE SEA_RACE_02
|
|
vStartPos = <<3482.450684,5171.119629,-2.622287>>
|
|
vStartRot = <<-12.389264,0.000000,26.136166>>
|
|
vMidPos = <<3481.746582,5172.553711,6.654290>>//<<3481.746582,5172.553711,3.654290>>
|
|
vMidRot = <<-9.870142,-0.000000,26.136162>>//<<-5.870142,-0.000000,26.136162>>
|
|
vEndPos = <<3479.126709,5173.103027,6.487341>>//<<3479.126709,5173.103027,3.487341>>
|
|
vEndRot = <<-9.603036,-0.000000,21.927107>>//<<-3.603036,-0.000000,21.927107>>
|
|
|
|
vStartPos2 = <<3457.3281, 5187.8604, 4.6358>>//<<3457.3552, 5190.9644, 3.3545>>//<<3455.060059,5195.183105,4.763378>>//<<3455.060059,5195.183105,1.763378>>
|
|
vStartRot2 = <<-24.8126, 0.0397, -41.5662>>//<<-16.9467, -0.0000, -40.3688>>//<<-7.357910,-0.000000,-102.864853>>//<<-2.357910,-0.000000,-102.864853>>
|
|
vEndPos2 = <<3456.5105, 5197.8965, 3.9627>>//<<3458.0938, 5197.1948, 3.6239>>//<<3455.694580,5198.888672,4.791954>>//<<3455.694580,5198.888672,1.791954>>
|
|
vEndRot2 = <<-23.4737, 0.0397, -128.4928>>//<<-19.8012, 0.0000, -121.2162>>//<<-7.923511,-0.000000,-119.349350>>//<<-3.923511,-0.000000,-119.349350>>
|
|
BREAK
|
|
|
|
// Raton Canyon
|
|
CASE SEA_RACE_03
|
|
vStartPos = <<190.542801,3596.879395,28.210274>>
|
|
vStartRot = <<-16.612904,-0.000001,-17.123419>>
|
|
vMidPos = <<190.928116,3598.445557,33.460209>>
|
|
vMidRot = <<-6.513790,-0.000000,-20.806368>>
|
|
vEndPos = <<189.055481,3599.193604,33.459087>>
|
|
vEndRot = <<-6.431107,-0.000000,-24.993280>>
|
|
|
|
vStartPos2 = <<187.353561,3623.253174,31.377996>>
|
|
vStartRot2 = <<0.968793,-0.000000,-171.133331>>
|
|
vEndPos2 = <<189.636276,3623.848389,31.370586>>
|
|
vEndRot2 = <<0.968793,-0.000000,175.618408>>
|
|
BREAK
|
|
|
|
// Los Santos
|
|
CASE SEA_RACE_04
|
|
vStartPos = <<617.705261,-2150.886475,-6.053663>>
|
|
vStartRot = <<-12.894878,-0.000002,-21.272289>>
|
|
vMidPos = <<616.813843,-2149.222412,1.441951>>
|
|
vMidRot = <<5.644659,-0.000002,-24.942902>>
|
|
vEndPos = <<615.142029,-2147.595703,1.518046>>
|
|
vEndRot = <<3.451776,-0.000002,-29.075584>>
|
|
|
|
vStartPos2 = <<615.476135,-2124.191895,1.467611>>
|
|
vStartRot2 = <<0.143961,0.000000,-156.622635>>
|
|
vEndPos2 = <<617.970764,-2122.319092,1.464393>>
|
|
vEndRot2 = <<0.143961,0.000000,179.064117>>
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
// Need to change the last intro cameras if the player is using a very big vehicle
|
|
IF PLAYERS_CAR_IS_VERY_BIG()
|
|
vStartPos4 = <<-2.0797, -1.4090, 1.3288>>
|
|
vStartRot4 = <<-2.1875, 1.5807, 1.1049>>
|
|
vEndPos4 = <<-0.6528, -5.8087, 2.3170>>
|
|
vEndRot4 = <<-0.7557, -2.8423, 1.8806>>
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC CREATE_RACE_CAMERAS()
|
|
INT i_index = 0
|
|
REPEAT COUNT_OF(gridCamera) i_index
|
|
IF DOES_CAM_EXIST(gridCamera[i_index])
|
|
DESTROY_CAM(gridCamera[i_index])
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
gridCamera[0] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vStartPos, vStartRot, 35.0)
|
|
SET_CAM_ACTIVE(gridCamera[0], TRUE)
|
|
RENDER_SCRIPT_CAMS(TRUE, FALSE, 0)
|
|
|
|
gridCamera[1] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vMidPos, vMidRot, 35.0)
|
|
gridCamera[2] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vEndPos, vEndRot, 35.0)
|
|
|
|
gridCamera[3] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vStartPos2, vStartRot2, 50.0)
|
|
gridCamera[4] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vEndPos2, vEndRot2, 50.0)
|
|
|
|
iCamTimer = GET_GAME_TIMER() + 250
|
|
ELSE
|
|
IF sRaceData.eRaceTrack = STREET_RACE_06
|
|
gridCamera[0] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vStartPos, vStartRot, 40.0)
|
|
ELSE
|
|
gridCamera[0] = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA")
|
|
SET_CAM_FOV(gridCamera[0], 40.0)
|
|
ATTACH_CAM_TO_ENTITY(gridCamera[0], sPlayerVehicle.vehPlayerVehicle, vStartPos)
|
|
POINT_CAM_AT_ENTITY(gridCamera[0], sPlayerVehicle.vehPlayerVehicle, vStartRot)
|
|
ENDIF
|
|
|
|
gridCamera[1] = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA")
|
|
SET_CAM_FOV(gridCamera[1], 40.0)
|
|
ATTACH_CAM_TO_ENTITY(gridCamera[1], sPlayerVehicle.vehPlayerVehicle, vEndPos)
|
|
POINT_CAM_AT_ENTITY(gridCamera[1], sPlayerVehicle.vehPlayerVehicle, vEndRot)
|
|
|
|
SET_CAM_ACTIVE(gridCamera[0], TRUE)
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[1],gridCamera[0],3000,GRAPH_TYPE_SIN_ACCEL_DECEL)
|
|
RENDER_SCRIPT_CAMS(TRUE, FALSE, 0)
|
|
SHAKE_CAM(gridCamera[0],"ROAD_VIBRATION_SHAKE",0.5)
|
|
SHAKE_CAM(gridCamera[1],"ROAD_VIBRATION_SHAKE",0.5)
|
|
|
|
gridCamera[2] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vStartPos2, vStartRot2, 40.0)
|
|
gridCamera[3] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vEndPos2, vEndRot2, 40.0)
|
|
|
|
gridCamera[4] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vStartPos3, vStartRot3, 40.0)
|
|
gridCamera[5] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vEndPos3, vEndRot3, 40.0)
|
|
|
|
// Very big vehicles need custom finish cameras that are vehicle relative
|
|
IF PLAYERS_CAR_IS_VERY_BIG()
|
|
gridCamera[6] = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA")
|
|
SET_CAM_FOV(gridCamera[6], 50.0)
|
|
ATTACH_CAM_TO_ENTITY(gridCamera[6], sPlayerVehicle.vehPlayerVehicle, vStartPos4)
|
|
POINT_CAM_AT_ENTITY(gridCamera[6], sPlayerVehicle.vehPlayerVehicle, vStartRot4)
|
|
|
|
gridCamera[7] = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA")
|
|
SET_CAM_FOV(gridCamera[7], 50.0)
|
|
ATTACH_CAM_TO_ENTITY(gridCamera[7], sPlayerVehicle.vehPlayerVehicle, vEndPos4)
|
|
POINT_CAM_AT_ENTITY(gridCamera[7], sPlayerVehicle.vehPlayerVehicle, vEndRot4)
|
|
ELSE
|
|
gridCamera[6] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vStartPos4, vStartRot4, 50.0)
|
|
gridCamera[7] = CREATE_CAMERA_WITH_PARAMS(CAMTYPE_SCRIPTED, vEndPos4, vEndRot4, 50.0)
|
|
ENDIF
|
|
|
|
iCamTimer = -1
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Plays the sound effect while the camera is interpolating, see 1218670 and 1224076
|
|
PROC PLAY_INTRO_SOUND(BOOL bPlaySound = TRUE)
|
|
IF bPlayedIntroSound = FALSE
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
IF LOAD_STREAM("INTRO_STREAM","SEA_RACES_SOUNDSET")
|
|
//CPRINTLN(DEBUG_MISSION, "Street Race: Audio banks for intro sfx have loaded")
|
|
IF bPlaySound
|
|
CPRINTLN(DEBUG_MISSION, "Street Race: Audio banks for intro sfx have loaded, so playing intro sfx")
|
|
PLAY_STREAM_FRONTEND()
|
|
bPlayedIntroSound = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ELIF sRaceData.eRaceType = RACETYPE_BIKE
|
|
IF LOAD_STREAM("VESPUCCI_CANAL_INTRO","ROAD_RACE_SOUNDSET")
|
|
//CPRINTLN(DEBUG_MISSION, "Street Race: Audio banks for intro sfx have loaded")
|
|
IF bPlaySound
|
|
CPRINTLN(DEBUG_MISSION, "Street Race: Audio banks for intro sfx have loaded, so playing intro sfx")
|
|
PLAY_STREAM_FRONTEND()
|
|
bPlayedIntroSound = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF LOAD_STREAM("INTRO_STREAM","ROAD_RACE_SOUNDSET")
|
|
//CPRINTLN(DEBUG_MISSION, "Street Race: Audio banks for intro sfx have loaded")
|
|
IF bPlaySound
|
|
CPRINTLN(DEBUG_MISSION, "Street Race: Audio banks for intro sfx have loaded, so playing intro sfx")
|
|
PLAY_STREAM_FRONTEND()
|
|
bPlayedIntroSound = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC BOOL CONTROL_RACE_CAMERAS()
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
IF DOES_CAM_EXIST(gridCamera[0])
|
|
IF GET_GAME_TIMER() > iCamTimer
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[1],gridCamera[0],500,GRAPH_TYPE_LINEAR)
|
|
SET_CAM_MOTION_BLUR_STRENGTH(gridCamera[1],1.0)
|
|
PLAY_SOUND_FRONTEND(-1,"UNDER_WATER_COME_UP")
|
|
DESTROY_CAM(gridCamera[0])
|
|
ELSE
|
|
PLAY_INTRO_SOUND(FALSE)
|
|
ENDIF
|
|
ELIF DOES_CAM_EXIST(gridCamera[1])
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[1])
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[2],gridCamera[1],3000,GRAPH_TYPE_LINEAR)
|
|
SHAKE_CAM(gridCamera[2],"HAND_SHAKE",0.3)
|
|
DESTROY_CAM(gridCamera[1])
|
|
ELSE
|
|
PLAY_INTRO_SOUND()
|
|
ENDIF
|
|
ELIF DOES_CAM_EXIST(gridCamera[2])
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[2])
|
|
SET_CAM_ACTIVE(gridCamera[3], TRUE)
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[4],gridCamera[3],5000,GRAPH_TYPE_DECEL)
|
|
SHAKE_CAM(gridCamera[4],"HAND_SHAKE",0.3)
|
|
DESTROY_CAM(gridCamera[2])
|
|
iCamTimer = GET_GAME_TIMER() + 2000
|
|
ELSE
|
|
PLAY_INTRO_SOUND()
|
|
ENDIF
|
|
ELIF DOES_CAM_EXIST(gridCamera[4])
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[4])
|
|
STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()
|
|
INT i_index = 0
|
|
REPEAT COUNT_OF(gridCamera) i_index
|
|
IF DOES_CAM_EXIST(gridCamera[i_index])
|
|
DESTROY_CAM(gridCamera[i_index])
|
|
ENDIF
|
|
ENDREPEAT
|
|
ELSE
|
|
PLAY_INTRO_SOUND()
|
|
ENDIF
|
|
IF GET_GAME_TIMER() > iCamTimer
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
RETURN TRUE
|
|
ENDIF
|
|
ELSE
|
|
IF DOES_CAM_EXIST(gridCamera[1])
|
|
//IF GET_GAME_TIMER() > iCamTimer
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[1])
|
|
IF iCamTimer < 0
|
|
iCamTimer = GET_GAME_TIMER() + 1000
|
|
ELIF GET_GAME_TIMER() > iCamTimer
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[3],gridCamera[2],4000,GRAPH_TYPE_LINEAR)
|
|
SHAKE_CAM(gridCamera[2],"HAND_SHAKE",1.0)
|
|
SHAKE_CAM(gridCamera[3],"HAND_SHAKE",1.0)
|
|
DESTROY_CAM(gridCamera[1])
|
|
ENDIF
|
|
ELSE
|
|
PLAY_INTRO_SOUND(FALSE)
|
|
ENDIF
|
|
ELIF DOES_CAM_EXIST(gridCamera[3])
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[3])
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[5],gridCamera[4],4000,GRAPH_TYPE_LINEAR)
|
|
SHAKE_CAM(gridCamera[4],"HAND_SHAKE",1.0)
|
|
SHAKE_CAM(gridCamera[5],"HAND_SHAKE",1.0)
|
|
DESTROY_CAM(gridCamera[3])
|
|
IF sRaceData.eRaceTrack = STREET_RACE_04
|
|
OR sRaceData.eRaceTrack = STREET_RACE_06
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
IF IS_VEHICLE_DRIVEABLE(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_ENTITY_COORDS(sPlayerVehicle.vehPlayerVehicle, sTrackData.vStartGrid[sTrackData.iNumAIRacers])
|
|
SET_ENTITY_HEADING(sPlayerVehicle.vehPlayerVehicle, sTrackData.fStartGrid[sTrackData.iNumAIRacers])
|
|
SET_VEHICLE_ON_GROUND_PROPERLY(sPlayerVehicle.vehPlayerVehicle)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF IS_PED_UNINJURED(piGridGirlOne)
|
|
IF bGridGirlOneConvReady
|
|
IF CREATE_CONVERSATION(pedConvStruct, "STR1AUD", "STR1_GIRL1", CONV_PRIORITY_HIGH)
|
|
bGridGirlOneConvReady = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
PLAY_INTRO_SOUND()
|
|
ENDIF
|
|
ELIF DOES_CAM_EXIST(gridCamera[5])
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[5])
|
|
IF PLAYERS_CAR_IS_VERY_BIG()
|
|
SET_CAM_ACTIVE(gridCamera[6], TRUE)
|
|
ENDIF
|
|
SET_CAM_ACTIVE_WITH_INTERP(gridCamera[7],gridCamera[6],3000,GRAPH_TYPE_DECEL)
|
|
SHAKE_CAM(gridCamera[6],"HAND_SHAKE",1.0)
|
|
SHAKE_CAM(gridCamera[7],"HAND_SHAKE",1.0)
|
|
DESTROY_CAM(gridCamera[5])
|
|
RETURN TRUE
|
|
ELSE
|
|
IF IS_PED_UNINJURED(piGridGirlThree)
|
|
IF bGridGirlThreeConvReady
|
|
IF CREATE_CONVERSATION(pedConvStruct, "STR1AUD", "STR1_GIRL2", CONV_PRIORITY_HIGH)
|
|
bGridGirlThreeConvReady = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
PLAY_INTRO_SOUND()
|
|
ENDIF
|
|
ELIF DOES_CAM_EXIST(gridCamera[7])
|
|
IF NOT IS_CAM_INTERPOLATING(gridCamera[7])
|
|
STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()
|
|
INT i_index = 0
|
|
REPEAT COUNT_OF(gridCamera) i_index
|
|
IF DOES_CAM_EXIST(gridCamera[i_index])
|
|
DESTROY_CAM(gridCamera[i_index])
|
|
ENDIF
|
|
ENDREPEAT
|
|
//RETURN TRUE
|
|
ELSE
|
|
IF IS_PED_UNINJURED(piGridGirlThree)
|
|
IF bGridGirlThreeConvReady
|
|
IF CREATE_CONVERSATION(pedConvStruct, "STR1AUD", "STR1_GIRL2", CONV_PRIORITY_HIGH)
|
|
bGridGirlThreeConvReady = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
PLAY_INTRO_SOUND()
|
|
ENDIF
|
|
ELSE
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Sets up ped and car models for the Hao race
|
|
PROC SETUP_ALT_RIVAL_MODELS()
|
|
sRacer[0].modelCar = PRAIRIE
|
|
sRacer[1].modelCar = DOMINATOR
|
|
sRacer[2].modelCar = SENTINEL
|
|
sRacer[3].modelCar = PRAIRIE
|
|
sRacer[4].modelCar = DOMINATOR
|
|
sRacer[5].modelCar = SENTINEL
|
|
sRacer[6].modelCar = PRAIRIE
|
|
|
|
sRacer[0].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[1].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[2].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[3].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[4].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[5].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[6].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[7].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[8].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[9].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[10].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[11].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[12].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[13].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[14].modelPed = A_M_Y_EASTSA_01
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Setup required ped and car models depending on the race
|
|
PROC SETUP_RIVAL_MODELS()
|
|
|
|
// Set vehicle models
|
|
SWITCH sRaceData.eRaceTrack
|
|
CASE STREET_RACE_01 // South Los Santos
|
|
CASE STREET_RACE_02 // City Circuit
|
|
CASE STREET_RACE_04 // Airport
|
|
CASE STREET_RACE_05 // Freeway
|
|
sRacer[0].modelCar = BANSHEE
|
|
sRacer[1].modelCar = FELTZER2
|
|
sRacer[2].modelCar = SENTINEL
|
|
sRacer[3].modelCar = BANSHEE
|
|
sRacer[4].modelCar = FELTZER2
|
|
sRacer[5].modelCar = SENTINEL
|
|
sRacer[6].modelCar = BANSHEE
|
|
BREAK
|
|
CASE STREET_RACE_06 // Vespucci Canals
|
|
sRacer[0].modelCar = BATI
|
|
sRacer[1].modelCar = BATI
|
|
sRacer[2].modelCar = RUFFIAN
|
|
sRacer[3].modelCar = RUFFIAN
|
|
sRacer[4].modelCar = BATI
|
|
sRacer[5].modelCar = RUFFIAN
|
|
sRacer[6].modelCar = BATI
|
|
BREAK
|
|
CASE SEA_RACE_01 // North Coast
|
|
CASE SEA_RACE_02 // South Coast
|
|
CASE SEA_RACE_03 // Raton Canyon
|
|
CASE SEA_RACE_04 // Los Santos
|
|
sRacer[0].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[1].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[2].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[3].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[4].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[5].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[6].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[7].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[8].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[9].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[10].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[11].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[12].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[13].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
sRacer[14].modelCar = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(sRaceData.eRaceType)
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
// Set ped models
|
|
SWITCH sRaceData.eRaceTrack
|
|
CASE STREET_RACE_01 // South Los Santos
|
|
CASE STREET_RACE_02 // City Circuit
|
|
CASE STREET_RACE_04 // Airport
|
|
CASE STREET_RACE_05 // Freeway
|
|
sRacer[0].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[1].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[2].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[3].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[4].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[5].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[6].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[7].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[8].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[9].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[10].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[11].modelPed = A_M_Y_EASTSA_01
|
|
sRacer[12].modelPed = A_M_M_SOCENLAT_01
|
|
sRacer[13].modelPed = A_M_Y_HIPSTER_02
|
|
sRacer[14].modelPed = A_M_Y_EASTSA_01
|
|
BREAK
|
|
CASE STREET_RACE_06 // Vespucci Canals
|
|
sRacer[0].modelPed = A_M_Y_MotoX_02
|
|
sRacer[1].modelPed = A_M_Y_MotoX_01
|
|
sRacer[2].modelPed = A_M_Y_MotoX_02
|
|
sRacer[3].modelPed = A_M_Y_MotoX_01
|
|
sRacer[4].modelPed = A_M_Y_MotoX_02
|
|
sRacer[5].modelPed = A_M_Y_MotoX_01
|
|
sRacer[6].modelPed = A_M_Y_MotoX_02
|
|
sRacer[7].modelPed = A_M_Y_MotoX_01
|
|
sRacer[8].modelPed = A_M_Y_MotoX_02
|
|
sRacer[9].modelPed = A_M_Y_MotoX_01
|
|
sRacer[10].modelPed = A_M_Y_MotoX_02
|
|
sRacer[11].modelPed = A_M_Y_MotoX_01
|
|
sRacer[12].modelPed = A_M_Y_MotoX_02
|
|
sRacer[13].modelPed = A_M_Y_MotoX_01
|
|
sRacer[14].modelPed = A_M_Y_MotoX_02
|
|
BREAK
|
|
CASE SEA_RACE_01 // North Coast
|
|
CASE SEA_RACE_02 // South Coast
|
|
CASE SEA_RACE_03 // Raton Canyon
|
|
CASE SEA_RACE_04 // Los Santos
|
|
sRacer[0].modelPed = A_M_Y_Jetski_01
|
|
sRacer[1].modelPed = A_M_Y_JETSKI_01
|
|
sRacer[2].modelPed = A_M_Y_Jetski_01
|
|
sRacer[3].modelPed = A_M_Y_Jetski_01
|
|
sRacer[4].modelPed = A_M_Y_Jetski_01
|
|
sRacer[5].modelPed = A_M_Y_Jetski_01
|
|
sRacer[6].modelPed = A_M_Y_Jetski_01
|
|
sRacer[7].modelPed = A_M_Y_Jetski_01
|
|
sRacer[8].modelPed = A_M_Y_Jetski_01
|
|
sRacer[9].modelPed = A_M_Y_Jetski_01
|
|
sRacer[10].modelPed = A_M_Y_Jetski_01
|
|
sRacer[11].modelPed = A_M_Y_Jetski_01
|
|
sRacer[12].modelPed = A_M_Y_Jetski_01
|
|
sRacer[13].modelPed = A_M_Y_Jetski_01
|
|
sRacer[14].modelPed = A_M_Y_Jetski_01
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
ENDPROC
|
|
|
|
PROC SETUP_END_SCENE_COORDS()
|
|
SWITCH sRaceData.eRaceTrack
|
|
|
|
// South Los Santos
|
|
CASE STREET_RACE_01
|
|
vWinningCarPos = <<-168.60, -1575.16, 34.70>>//<<-72.35, -1798.04, 27.36>>
|
|
fWinningCarHeading = 141.57//229.02
|
|
|
|
vRewardPedPos = <<-170.0685, -1573.8658, 34.3070>>//<<-169.9326, -1574.0978, 34.3036>>//<<-171.44, -1572.61, 35.34>>//<<-76.34, -1800.73, 27.93>>
|
|
fRewardPedHeading = 191.3066//224.8836//-128.52//-28.65
|
|
|
|
// Commenting out for now in case this is needed again
|
|
/*vAltCarPos = <<-69.02, -1787.95, 27.51>>
|
|
fAltCarHeading = 229.77*/
|
|
BREAK
|
|
|
|
// City Circuit
|
|
CASE STREET_RACE_02
|
|
vWinningCarPos = <<353.12, 321.39, 103.65>>
|
|
fWinningCarHeading = 77.40
|
|
|
|
vRewardPedPos = <<353.4853, 323.3662, 103.0862>>//<<354.22, 326.03, 104.09>>
|
|
fRewardPedHeading = 127.4//166.34
|
|
|
|
// Commenting out for now in case this is needed again
|
|
/*vAltCarPos = <<-511.93, 270.68, 82.72>>
|
|
fAltCarHeading = 137.65*/
|
|
BREAK
|
|
|
|
// Airport
|
|
CASE STREET_RACE_04
|
|
vWinningCarPos = <<-794.5402, -2527.3931, 12.7891>>//<<-796.32, -2526.38, 13.40>>//<<-994.50, -2437.56, 19.61>>
|
|
fWinningCarHeading = 332.72//151.98
|
|
|
|
vRewardPedPos = <<-792.37, -2527.87, 13.83>>//<<-998.18, -2434.28, 20.17>>
|
|
fRewardPedHeading = 22.72//80.21//-112.87
|
|
|
|
// Commenting out for now in case this is needed again
|
|
/*vAltCarPos = <<-990.51, -2430.89, 19.62>>
|
|
fAltCarHeading = 151.97*/
|
|
BREAK
|
|
|
|
// Freeway
|
|
CASE STREET_RACE_05
|
|
// on the freeway, no end scene for this race
|
|
vWinningCarPos = <<818.13, -1161.54, 28.00>>
|
|
fWinningCarHeading = 76.46
|
|
|
|
vRewardPedPos = <<818.5804, -1159.6426, 27.2778>>//<<818.74, -1157.61, 28.26>>
|
|
fRewardPedHeading = 126.46//178.19
|
|
BREAK
|
|
|
|
// Vespucci Canals
|
|
CASE STREET_RACE_06
|
|
vWinningCarPos = <<-1025.28, -1130.25, 1.70>>//<<-989.86, -1111.95, 1.64>>//<<-1246.85, -1086.30, 7.71>>
|
|
fWinningCarHeading = 305.27//202.39
|
|
|
|
vRewardPedPos = <<-1024.5483, -1131.2539, 1.1861>>//<<-1022.20, -1134.06, 2.16>>//<<-987.10, -1114.75, 2.15>>//<<-1251.45, -1087.25, 8.32>>
|
|
fRewardPedHeading = 355.27//48.70//-64.17
|
|
|
|
// Commenting out for now in case this is needed again
|
|
/*vAltCarPos = <<-1249.22, -1078.61, 7.81>>
|
|
fAltCarHeading = 197.10*/
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
// ===========================================================================================================
|
|
// Mission States
|
|
// ===========================================================================================================
|
|
/// PURPOSE: Basic race setup
|
|
PROC RACE_INIT(BOOL bAltLineup = FALSE, BOOL bClearAreaPeds = TRUE)
|
|
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: RACE_INIT")
|
|
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: vehPlayerVehicle already exists")
|
|
ELSE
|
|
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
|
|
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
ADD_PED_FOR_DIALOGUE(pedConvStruct, 1, PLAYER_PED_ID(), "FRANKLIN")
|
|
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
sPlayerVehicle.vehPlayerVehicle = GET_VEHICLE_PED_IS_USING(PLAYER_PED_ID())
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Acquired player's vehicle")
|
|
ELSE
|
|
sPlayerVehicle.vehPlayerVehicle = GET_PLAYERS_LAST_VEHICLE()
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
ELSE
|
|
SCRIPT_ASSERT("Mission Race: somehow managed to allow the race to start when the player isn't in a vehicle")
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Init states
|
|
eRaceState = RACE_STATE_LINEUP
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
failReason = FAIL_DEFAULT
|
|
|
|
// Load track info
|
|
INIT_TRACK_DATA(sRaceData, sTrackData)
|
|
|
|
// Set the instance priority
|
|
SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_DRIVING)
|
|
|
|
// Setup race lineup cameras
|
|
SETUP_RACE_CAMERAS()
|
|
|
|
// Setup all required ped and car models we'll need to load in
|
|
IF bAltLineup
|
|
SETUP_ALT_RIVAL_MODELS()
|
|
ELSE
|
|
SETUP_RIVAL_MODELS()
|
|
// Deduct race fee
|
|
//DEBIT_BANK_ACCOUNT(GET_CURRENT_PLAYER_PED_ENUM(), BAAC_UNLOGGED_SMALL_ACTION, sRaceData.iRaceFee)
|
|
ENDIF
|
|
|
|
// Setup end scene coordinates
|
|
SETUP_END_SCENE_COORDS()
|
|
|
|
// Disable all peds...
|
|
SET_PED_POPULATION_BUDGET(0)
|
|
SET_REDUCE_PED_MODEL_BUDGET(TRUE)
|
|
|
|
// Traffic and cops
|
|
SET_VEHICLE_POPULATION_BUDGET(2)
|
|
SET_REDUCE_VEHICLE_MODEL_BUDGET(TRUE)
|
|
SET_DISPATCH_COPS_FOR_PLAYER(PLAYER_ID(), FALSE)
|
|
SET_CREATE_RANDOM_COPS(FALSE)
|
|
|
|
// Turn on the slipstream effect
|
|
SET_ENABLE_VEHICLE_SLIPSTREAMING(TRUE)
|
|
|
|
// Block all scenarios
|
|
//scenarioBlockArea = ADD_SCENARIO_BLOCKING_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 100.0>>)
|
|
|
|
// Needed to disable scenarios at docks
|
|
SET_SCENARIO_TYPE_ENABLED("DRIVE", FALSE)
|
|
|
|
// Remove vehicle gens
|
|
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 100.0>>, FALSE)
|
|
REMOVE_VEHICLES_FROM_GENERATORS_IN_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 100.0>>)
|
|
|
|
IF bClearAreaPeds AND DOES_ENTITY_EXIST(PLAYER_PED_ID())
|
|
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
IF sRaceData.eRaceType = RACETYPE_BIKE OR sRaceData.eRaceType = RACETYPE_CAR
|
|
sbiRaceStart = ADD_SCENARIO_BLOCKING_AREA_FROM_POSITION_AND_RADIUS(GET_ENTITY_COORDS(PLAYER_PED_ID()), 60.0)
|
|
SETUP_ROAD_BLOCKING(sRaceData.eRaceTrack, vRaceRoadPos1, vRaceRoadPos2, fRaceRoadWidth)
|
|
SET_ROADS_IN_ANGLED_AREA(vRaceRoadPos1, vRaceRoadPos2, fRaceRoadWidth, FALSE, FALSE)
|
|
ENDIF
|
|
CLEAR_AREA_OF_PEDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), 500) // B*930668 - make sure there are no ambient peds still mooching around
|
|
ENDIF
|
|
|
|
// Player cannot fly through windscrren
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(),PCF_WillFlyThroughWindscreen, FALSE)
|
|
ENDIF
|
|
|
|
SET_WANTED_LEVEL_MULTIPLIER(0.1) // See B*930410 - Imran asked for this to be set at 0.1
|
|
|
|
sPlayerVehicle.bDisplayedGetBackInVehicleText = FALSE
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Setup player for start of race
|
|
PROC SETUP_PLAYER_PRECUTSCENE()
|
|
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
|
|
// Teleport player and their vehicle to starting grid
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
IF IS_VEHICLE_DRIVEABLE(sPlayerVehicle.vehPlayerVehicle)
|
|
IF NOT IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle) AND IS_VEHICLE_SEAT_FREE(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
ENDIF
|
|
|
|
// Clear area around race location
|
|
PLAYER_INDEX pId = GET_PLAYER_INDEX()
|
|
CLEAR_AREA(GET_PLAYER_COORDS(pId), 50.0, TRUE)
|
|
CLEAR_AREA_OF_VEHICLES(GET_PLAYER_COORDS(pId), 500.0) // use a big area since ambient vehicles get turned off anyway
|
|
CLEAR_AREA_OF_PEDS(GET_PLAYER_COORDS(pId), 500.0)
|
|
|
|
VECTOR behind_pos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(sTrackData.vStartGrid[sTrackData.iNumAIRacers], sTrackData.fStartGrid[sTrackData.iNumAIRacers], <<0.0, -15.0, 1.0>>)
|
|
SNAP_3D_COORD_TO_GROUND(behind_pos)
|
|
FLOAT start_heading = sTrackData.fStartGrid[sTrackData.iNumAIRacers]
|
|
IF sRaceData.eRaceTrack = STREET_RACE_04
|
|
behind_pos = <<-825.03, -2575.13, 13.25>>
|
|
start_heading = 334.98
|
|
ELIF sRaceData.eRaceTrack = STREET_RACE_06
|
|
behind_pos = <<-1093.4932, -1173.1614, 2.4978>>
|
|
ELIF sRaceData.eRaceType = RACETYPE_SEA
|
|
behind_pos = sTrackData.vStartGrid[sTrackData.iNumAIRacers]
|
|
ENDIF
|
|
VECTOR targetPos
|
|
FLOAT fSpeed
|
|
/*IF sRaceData.eRaceType = RACETYPE_SEA
|
|
targetPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(sTrackData.vStartGrid[sTrackData.iNumAIRacers], sTrackData.fStartGrid[sTrackData.iNumAIRacers], <<1.0, 2.0, 0.0>>)
|
|
fSpeed = 7.0
|
|
EL*/IF sRaceData.eRaceType = RACETYPE_BIKE
|
|
targetPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(sTrackData.vStartGrid[sTrackData.iNumAIRacers], sTrackData.fStartGrid[sTrackData.iNumAIRacers], <<0.0, -1.0, 0.0>>)
|
|
fSpeed = 7.0
|
|
ELSE
|
|
targetPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(sTrackData.vStartGrid[sTrackData.iNumAIRacers], sTrackData.fStartGrid[sTrackData.iNumAIRacers], <<0.0, 2.3, 0.0>>)
|
|
fSpeed = 3.0
|
|
ENDIF
|
|
//CLEAR_PED_TASKS(PLAYER_PED_ID())
|
|
SET_VEHICLE_ENGINE_ON(sPlayerVehicle.vehPlayerVehicle, TRUE, TRUE)
|
|
SET_ENTITY_HEADING(sPlayerVehicle.vehPlayerVehicle, start_heading)
|
|
SET_ENTITY_COORDS_GROUNDED(sPlayerVehicle.vehPlayerVehicle, behind_pos)
|
|
//SET_VEHICLE_ON_GROUND_PROPERLY(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_VEHICLE_DOORS_SHUT(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_VEHICLE_IS_RACING(sPlayerVehicle.vehPlayerVehicle, TRUE)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
SET_VEHICLE_ON_GROUND_PROPERLY(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_BOAT_LOW_LOD_ANCHOR_DISTANCE(sPlayerVehicle.vehPlayerVehicle,0)
|
|
SET_BOAT_REMAINS_ANCHORED_WHILE_PLAYER_IS_DRIVER(sPlayerVehicle.vehPlayerVehicle,TRUE)
|
|
SET_FORCE_LOW_LOD_ANCHOR_MODE(sPlayerVehicle.vehPlayerVehicle,TRUE)
|
|
IF CAN_ANCHOR_BOAT_HERE(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_BOAT_ANCHOR(sPlayerVehicle.vehPlayerVehicle,TRUE)
|
|
ENDIF
|
|
ELSE
|
|
TASK_VEHICLE_DRIVE_TO_COORD(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle, targetPos, fSpeed, DRIVINGSTYLE_NORMAL, GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle), DF_ForceStraightLine|DRIVINGMODE_PLOUGHTHROUGH, 0.5, 15.0)
|
|
SET_VEHICLE_FORWARD_SPEED(sPlayerVehicle.vehPlayerVehicle, fSpeed)
|
|
FORCE_ENTITY_AI_AND_ANIMATION_UPDATE(sPlayerVehicle.vehPlayerVehicle)
|
|
ENDIF
|
|
//SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(PLAYER_PED_ID(), TRUE)
|
|
SET_ENTITY_VISIBLE(sPlayerVehicle.vehPlayerVehicle, TRUE)
|
|
// reduce the amount of damage the player's vehicle takes
|
|
SET_VEHICLE_STRONG(sPlayerVehicle.vehPlayerVehicle, TRUE)
|
|
SET_VEHICLE_HAS_STRONG_AXLES(sPlayerVehicle.vehPlayerVehicle, TRUE)
|
|
//IF (sRaceData.eRaceType = RACETYPE_BIKE OR sRaceData.eRaceType = RACETYPE_SEA) AND IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PLAYER_PLAYING(PLAYER_ID())
|
|
IF sRaceData.eRaceType = RACETYPE_SEA AND IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PLAYER_PLAYING(PLAYER_ID())
|
|
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(PLAYER_PED_ID(), KNOCKOFFVEHICLE_HARD)
|
|
ENDIF
|
|
//SET_FRONTEND_RADIO_ACTIVE(FALSE)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Turn player visibility back on
|
|
SET_ENTITY_VISIBLE(PLAYER_PED_ID(), TRUE)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC SETUP_PLAYER_COUNTDOWN()
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
// clear player tasks asthe drive to line up task may still be running
|
|
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
|
|
CLEAR_PED_TASKS(PLAYER_PED_ID())
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
IF IS_VEHICLE_DRIVEABLE(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_ENTITY_COORDS(sPlayerVehicle.vehPlayerVehicle, sTrackData.vStartGrid[sTrackData.iNumAIRacers])
|
|
SET_ENTITY_HEADING(sPlayerVehicle.vehPlayerVehicle, sTrackData.fStartGrid[sTrackData.iNumAIRacers])
|
|
SET_VEHICLE_ON_GROUND_PROPERLY(sPlayerVehicle.vehPlayerVehicle)
|
|
ENDIF
|
|
|
|
SET_ENTITY_VISIBLE(PLAYER_PED_ID(), TRUE)
|
|
SET_ENTITY_VISIBLE(sPlayerVehicle.vehPlayerVehicle, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Setups up some random mods on the rival's race vehicle
|
|
PROC SETUP_RIVAL_VEHICLE_MODS(INT i_car)
|
|
IF DOES_ENTITY_EXIST(sRacer[i_car].viCar)
|
|
AND NOT IS_ENTITY_DEAD(sRacer[i_car].viCar)
|
|
SET_VEHICLE_COLOUR_COMBINATION(sRacer[i_car].viCar, GET_RANDOM_INT_IN_RANGE(0, GET_NUMBER_OF_VEHICLE_COLOURS(sRacer[i_car].viCar)))
|
|
IF GET_NUM_MOD_KITS(sRacer[i_car].viCar) > 0
|
|
SET_VEHICLE_MOD_KIT(sRacer[i_car].viCar, 0)
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_SPOILER) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_SPOILER, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_SPOILER))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_BUMPER_F) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_BUMPER_F, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_BUMPER_F))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_BUMPER_R) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_BUMPER_R, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_BUMPER_R))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_SKIRT) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_SKIRT, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_SKIRT))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_EXHAUST) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_EXHAUST, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_EXHAUST))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_CHASSIS) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_CHASSIS, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_CHASSIS))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_GRILL) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_GRILL, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_GRILL))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_WING_L) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_WING_L, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_WING_L))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_WING_R) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_WING_R, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_WING_R))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_ENGINE) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_ENGINE, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_ENGINE))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_BRAKES) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_BRAKES, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_BRAKES))
|
|
ENDIF
|
|
IF GET_NUM_VEHICLE_MODS(sRacer[i_car].viCar, MOD_GEARBOX) > 0
|
|
SET_VEHICLE_MOD(sRacer[i_car].viCar, MOD_GEARBOX, GET_RANDOM_VEHICLE_MOD_INDEX(sRacer[i_car].viCar, MOD_GEARBOX))
|
|
ENDIF
|
|
TOGGLE_VEHICLE_MOD(sRacer[i_car].viCar, MOD_TOGGLE_TURBO, TRUE)
|
|
TOGGLE_VEHICLE_MOD(sRacer[i_car].viCar, MOD_TOGGLE_NITROUS, TRUE)
|
|
TOGGLE_VEHICLE_MOD(sRacer[i_car].viCar, MOD_TOGGLE_XENON_LIGHTS, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Set skill levels for the rivals
|
|
PROC SETUP_RIVAL_VEHICLE_SKILL_LEVELS()
|
|
// All tracks currently use this same data. Add a switch statement for tracks if required.
|
|
IF sRaceData.eRaceTrack = STREET_RACE_05
|
|
sRacer[0].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
sRacer[1].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
sRacer[2].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
sRacer[3].drivingSpeed = AI_DRIVING_SPEED_MEDIUM
|
|
sRacer[4].drivingSpeed = AI_DRIVING_SPEED_MEDIUM
|
|
sRacer[5].drivingSpeed = AI_DRIVING_SPEED_SLOW
|
|
sRacer[6].drivingSpeed = AI_DRIVING_SPEED_SLOW
|
|
|
|
ELIF sRaceData.eRaceTrack = SEA_RACE_03
|
|
|
|
sRacer[0].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
sRacer[1].drivingSpeed = AI_DRIVING_SPEED_MEDIUM
|
|
sRacer[2].drivingSpeed = AI_DRIVING_SPEED_SLOW
|
|
ELSE
|
|
sRacer[0].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
sRacer[1].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
sRacer[2].drivingSpeed = AI_DRIVING_SPEED_MEDIUM
|
|
sRacer[3].drivingSpeed = AI_DRIVING_SPEED_MEDIUM
|
|
sRacer[4].drivingSpeed = AI_DRIVING_SPEED_SLOW
|
|
sRacer[5].drivingSpeed = AI_DRIVING_SPEED_SLOW
|
|
sRacer[6].drivingSpeed = AI_DRIVING_SPEED_SLOW
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC SET_RIVALS_INFO(INT i_index)
|
|
IF IS_PED_UNINJURED(sRacer[i_index].piDriver)
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sRacer[i_index].piDriver, TRUE)
|
|
SET_VEHICLE_IS_RACING(sRacer[i_index].viCar, TRUE)
|
|
SET_VEHICLE_IS_CONSIDERED_BY_PLAYER(sRacer[i_index].viCar, FALSE)
|
|
SET_VEHICLE_ENGINE_ON(sRacer[i_index].viCar, TRUE, TRUE)
|
|
SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(sRacer[i_index].piDriver, TRUE)
|
|
SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(sRacer[i_index].viCar, TRUE)
|
|
SET_VEHICLE_STRONG(sRacer[i_index].viCar, TRUE)
|
|
SET_VEHICLE_HAS_STRONG_AXLES(sRacer[i_index].viCar, TRUE)
|
|
SET_VEHICLE_TYRES_CAN_BURST(sRacer[i_index].viCar, FALSE)
|
|
//SET_VEHICLE_CAN_DEFORM_WHEELS(sRacer[i_index].viCar, FALSE)
|
|
SET_PED_CONFIG_FLAG(sRacer[i_index].piDriver, PCF_WillFlyThroughWindscreen, FALSE)
|
|
SET_PED_CONFIG_FLAG(sRacer[i_index].piDriver, PCF_GetOutUndriveableVehicle, FALSE)
|
|
SET_PED_CONFIG_FLAG(sRacer[i_index].piDriver, PCF_GetOutBurningVehicle, FALSE)
|
|
SET_PED_CONFIG_FLAG(sRacer[i_index].piDriver, PCF_RunFromFiresAndExplosions, FALSE)
|
|
SET_PED_CONFIG_FLAG(sRacer[i_index].piDriver, PCF_DontAllowToBeDraggedOutOfVehicle, TRUE)
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(sRacer[i_index].viCar, TRUE)
|
|
SET_PED_DIES_IN_WATER(sRacer[i_index].piDriver, FALSE)
|
|
/*IF sRaceData.eRaceType = RACETYPE_BIKE OR sRaceData.eRaceType = RACETYPE_SEA // In bike races set rivals as hard to knock off their bikes
|
|
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(sRacer[i_index].piDriver, KNOCKOFFVEHICLE_HARD)
|
|
ENDIF*/
|
|
IF sRaceData.eRaceType = RACETYPE_SEA // See B*963685 - This ensures sea race rivals will update if more than 300m away
|
|
SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(sRacer[i_index].viCar, FALSE)
|
|
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(sRacer[i_index].piDriver, KNOCKOFFVEHICLE_HARD)
|
|
ENDIF
|
|
sRacer[i_index].stateAI = AI_RACER_INIT
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Setup AI racer positions on the starting grid
|
|
PROC SETUP_AI_RACERS(PED_INDEX piRacerOne = NULL, VEHICLE_INDEX viRacerOne = NULL)
|
|
|
|
INT i_index
|
|
|
|
// The vehicle that Hao replaces
|
|
i_index = sTrackData.iNumAIRacers-1//1
|
|
IF IS_PED_UNINJURED(piRacerOne) AND IS_VEHICLE_OK(viRacerOne) AND NOT DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
/*IF NOT IS_PED_IN_VEHICLE(piRacerOne, viRacerOne) AND IS_VEHICLE_SEAT_FREE(viRacerOne)
|
|
SET_PED_INTO_VEHICLE(piRacerOne, viRacerOne)
|
|
ENDIF*/
|
|
|
|
sRacer[i_index].viCar = viRacerOne
|
|
sRacer[i_index].modelCar = GET_ENTITY_MODEL(viRacerOne)
|
|
/*SET_ENTITY_COORDS(sRacer[i_index].viCar, sTrackData.vStartGrid[i_index])
|
|
SET_ENTITY_HEADING(sRacer[i_index].viCar, sTrackData.fStartGrid[i_index])*/
|
|
|
|
sRacer[i_index].piDriver = piRacerOne
|
|
sRacer[i_index].modelPed = GET_ENTITY_MODEL(piRacerOne)
|
|
SET_RIVALS_INFO(i_index)
|
|
ENDIF
|
|
|
|
LOAD_RIVAL_MODELS(TRUE) // Load all required rival models
|
|
|
|
// Create racers
|
|
VECTOR vModifiedStartPos
|
|
VECTOR targetPos
|
|
SEQUENCE_INDEX siDrive
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
|
|
// Create vehicle
|
|
WHILE NOT DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
IF HAS_MODEL_LOADED(sRacer[i_index].modelCar)
|
|
vModifiedStartPos = sTrackData.vStartGrid[i_index]
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
vModifiedStartPos.x += GET_RANDOM_FLOAT_IN_RANGE(-1, 1)
|
|
vModifiedStartPos.y += GET_RANDOM_FLOAT_IN_RANGE(-1, 1)
|
|
ELSE
|
|
vModifiedStartPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(sTrackData.vStartGrid[i_index], sTrackData.fStartGrid[i_index], <<0.0, -3.0, 0.0>>)
|
|
ENDIF
|
|
sRacer[i_index].viCar = CREATE_VEHICLE(sRacer[i_index].modelCar, vModifiedStartPos, sTrackData.fStartGrid[i_index])
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
SET_VEHICLE_ON_GROUND_PROPERLY(sRacer[i_index].viCar)
|
|
SET_BOAT_LOW_LOD_ANCHOR_DISTANCE(sRacer[i_index].viCar,0)
|
|
SET_BOAT_REMAINS_ANCHORED_WHILE_PLAYER_IS_DRIVER(sRacer[i_index].viCar,TRUE)
|
|
SET_FORCE_LOW_LOD_ANCHOR_MODE(sRacer[i_index].viCar,TRUE)
|
|
IF CAN_ANCHOR_BOAT_HERE(sRacer[i_index].viCar)
|
|
SET_BOAT_ANCHOR(sRacer[i_index].viCar,TRUE)
|
|
ENDIF
|
|
SET_ENTITY_DYNAMIC(sRacer[i_index].viCar,FALSE)
|
|
ELSE
|
|
SET_VEHICLE_ON_GROUND_PROPERLY(sRacer[i_index].viCar)
|
|
ENDIF
|
|
SET_VEHICLE_MODEL_IS_SUPPRESSED(sRacer[i_index].modelCar, TRUE)
|
|
ENDIF
|
|
WAIT(0)
|
|
ENDWHILE
|
|
|
|
SETUP_RIVAL_VEHICLE_SKILL_LEVELS()
|
|
IF IS_PED_UNINJURED(piRacerOne)
|
|
sRacer[sTrackData.iNumAIRacers-1].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
ENDIF
|
|
|
|
// Place driver inside vehicle
|
|
WHILE NOT DOES_ENTITY_EXIST(sRacer[i_index].piDriver)
|
|
IF DOES_ENTITY_EXIST(sRacer[i_index].viCar)
|
|
AND IS_VEHICLE_DRIVEABLE(sRacer[i_index].viCar)
|
|
AND HAS_MODEL_LOADED(sRacer[i_index].modelPed)
|
|
sRacer[i_index].piDriver = CREATE_PED_INSIDE_VEHICLE(sRacer[i_index].viCar, PEDTYPE_MISSION, sRacer[i_index].modelPed)
|
|
IF sRaceData.eRaceType <> RACETYPE_SEA
|
|
SET_VEHICLE_USE_ALTERNATE_HANDLING(sRacer[i_index].viCar, TRUE)
|
|
targetPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(sTrackData.vStartGrid[i_index], sTrackData.fStartGrid[i_index], <<0.0, 2.3, 0.0>>)
|
|
IF i_index = 0
|
|
OPEN_SEQUENCE_TASK(siDrive)
|
|
TASK_PAUSE(NULL, 2800)
|
|
TASK_VEHICLE_DRIVE_TO_COORD(NULL, sRacer[i_index].viCar, targetPos, 1.5, DRIVINGSTYLE_NORMAL, sRacer[i_index].modelCar, DF_ForceStraightLine|DRIVINGMODE_PLOUGHTHROUGH, 0.5, 15.0)
|
|
CLOSE_SEQUENCE_TASK(siDrive)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, siDrive)
|
|
CLEAR_SEQUENCE_TASK(siDrive)
|
|
ELIF i_index = 1
|
|
OPEN_SEQUENCE_TASK(siDrive)
|
|
TASK_PAUSE(NULL, 3300)
|
|
TASK_VEHICLE_DRIVE_TO_COORD(NULL, sRacer[i_index].viCar, targetPos, 1.2, DRIVINGSTYLE_NORMAL, sRacer[i_index].modelCar, DF_ForceStraightLine|DRIVINGMODE_PLOUGHTHROUGH, 0.5, 15.0)
|
|
CLOSE_SEQUENCE_TASK(siDrive)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, siDrive)
|
|
CLEAR_SEQUENCE_TASK(siDrive)
|
|
ELSE
|
|
OPEN_SEQUENCE_TASK(siDrive)
|
|
TASK_PAUSE(NULL, (5500+(i_index*100)))
|
|
TASK_VEHICLE_DRIVE_TO_COORD(NULL, sRacer[i_index].viCar, targetPos, 0.8, DRIVINGSTYLE_NORMAL, sRacer[i_index].modelCar, DF_ForceStraightLine|DRIVINGMODE_PLOUGHTHROUGH, 0.5, 15.0)
|
|
CLOSE_SEQUENCE_TASK(siDrive)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, siDrive)
|
|
CLEAR_SEQUENCE_TASK(siDrive)
|
|
ENDIF
|
|
ENDIF
|
|
IF sRaceData.eRaceType = RACETYPE_BIKE
|
|
GIVE_PED_HELMET(sRacer[i_index].piDriver)
|
|
ENDIF
|
|
SETUP_RIVAL_VEHICLE_MODS(i_index)
|
|
IF IS_PED_UNINJURED(sRacer[i_index].piDriver)
|
|
SET_RIVALS_INFO(i_index)
|
|
ENDIF
|
|
ENDIF
|
|
WAIT(0)
|
|
ENDWHILE
|
|
ENDFOR
|
|
|
|
// Hao needs a fast driving speed
|
|
IF IS_PED_UNINJURED(piRacerOne)
|
|
sRacer[sTrackData.iNumAIRacers-1].drivingSpeed = AI_DRIVING_SPEED_FAST
|
|
ENDIF
|
|
|
|
LOAD_RIVAL_MODELS(FALSE) // Unload all required rival models
|
|
|
|
SWITCH sRaceData.eRaceTrack
|
|
CASE STREET_RACE_01
|
|
sRaceWaypointRecording = "CityRace0_route1"
|
|
BREAK
|
|
CASE STREET_RACE_02
|
|
sRaceWaypointRecording = "CityRace1_route1"
|
|
BREAK
|
|
CASE STREET_RACE_04
|
|
sRaceWaypointRecording = "CityRace3_route1"
|
|
BREAK
|
|
CASE STREET_RACE_05
|
|
sRaceWaypointRecording = "CityRace4_route1"
|
|
BREAK
|
|
CASE STREET_RACE_06
|
|
sRaceWaypointRecording = "CityRace5_route1"
|
|
BREAK
|
|
CASE SEA_RACE_01
|
|
sRaceWaypointRecording = "SeaRace0_route1"
|
|
BREAK
|
|
CASE SEA_RACE_02
|
|
sRaceWaypointRecording = "SeaRace1_route1"
|
|
BREAK
|
|
CASE SEA_RACE_03
|
|
sRaceWaypointRecording = "SeaRace2_route1"
|
|
BREAK
|
|
CASE SEA_RACE_04
|
|
sRaceWaypointRecording = "SeaRace3_route1"
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
REQUEST_WAYPOINT_RECORDING(sRaceWaypointRecording)
|
|
WHILE NOT GET_IS_WAYPOINT_RECORDING_LOADED(sRaceWaypointRecording)
|
|
WAIT(0)
|
|
ENDWHILE
|
|
|
|
WAYPOINT_RECORDING_GET_NUM_POINTS(sRaceWaypointRecording, iNumWaypoints)
|
|
iNumWaypoints-=1 // adjust this to starting at zero
|
|
|
|
IF sTrackData.iNumLaps = 0
|
|
bLoopWaypointRecording = FALSE
|
|
ELSE
|
|
bLoopWaypointRecording = TRUE
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC PLACE_RACERS_FOR_RESTART()
|
|
INT i_index
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers - 1
|
|
IF IS_PED_UNINJURED(sRacer[i_index].piDriver) AND IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
CLEAR_PED_TASKS(sRacer[i_index].piDriver)
|
|
BRING_VEHICLE_TO_HALT(sRacer[i_index].viCar, 0.1, 1)
|
|
SET_ENTITY_HEADING(sRacer[i_index].viCar, sTrackData.fStartGrid[i_index])
|
|
SET_ENTITY_COORDS_GROUNDED(sRacer[i_index].viCar, sTrackData.vStartGrid[i_index])
|
|
CPRINTLN(DEBUG_MISSION, "Placed racer ", i_index)
|
|
ENDIF
|
|
ENDFOR
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Set distance to the next checkpoint - for use with mission failing if the player drives in the opposite direction, see B*929375
|
|
PROC SET_DISTANCE_TO_NEXT_CHECKPOINT()
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
fNextCheckpointDistance = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint])
|
|
// CPRINTLN(DEBUG_MISSION, "Mission Race: fNextCheckpointDistance = ", fNextCheckpointDistance)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Resets race HUD to initial values
|
|
PROC INIT_RACE_HUD()
|
|
|
|
// Initialise HUD values
|
|
sRaceHUD.iStartTime = GET_GAME_TIMER()
|
|
sRaceHUD.iCurrentCheckPoint = 0
|
|
sRaceHUD.iCurrentLap = 1
|
|
sRaceHUD.iCurrentTime = GET_GAME_TIMER()
|
|
sRaceHUD.iMaxCheckpoints = sTrackData.iNumCheckpoints
|
|
SET_DISTANCE_TO_NEXT_CHECKPOINT()
|
|
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Displays the lap number when the player starts a new lap
|
|
PROC DISPLAY_LAPS_BIG_TEXT()
|
|
SWITCH eLapTextState
|
|
CASE LTS_LOAD
|
|
siLapText = REQUEST_SCALEFORM_MOVIE("MIDSIZED_MESSAGE")
|
|
IF HAS_SCALEFORM_MOVIE_LOADED(siLapText)
|
|
eLapTextState = LTS_INIT
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE LTS_INIT
|
|
BEGIN_SCALEFORM_MOVIE_METHOD(siLapText, "SHOW_SHARD_MIDSIZED_MESSAGE")
|
|
BEGIN_TEXT_COMMAND_SCALEFORM_STRING("BM_LAP_STR")
|
|
SET_COLOUR_OF_NEXT_TEXT_COMPONENT(HUD_COLOUR_WHITE)
|
|
ADD_TEXT_COMPONENT_SUBSTRING_TEXT_LABEL("BM_LAP")
|
|
SET_COLOUR_OF_NEXT_TEXT_COMPONENT(HUD_COLOUR_WHITE)
|
|
ADD_TEXT_COMPONENT_INTEGER(sRaceHUD.iCurrentLap)
|
|
SET_COLOUR_OF_NEXT_TEXT_COMPONENT(HUD_COLOUR_WHITE)
|
|
ADD_TEXT_COMPONENT_INTEGER(sTrackData.iNumLaps)
|
|
END_TEXT_COMMAND_SCALEFORM_STRING()
|
|
END_SCALEFORM_MOVIE_METHOD_RETURN_VALUE()
|
|
iLapTextTimer = GET_GAME_TIMER() + LAP_TEXT_TIME
|
|
eLapTextState = LTS_DISPLAY
|
|
BREAK
|
|
|
|
CASE LTS_DISPLAY
|
|
IF GET_GAME_TIMER() < iLapTextTimer - 500
|
|
IF HAS_SCALEFORM_MOVIE_LOADED(siLapText)
|
|
DRAW_SCALEFORM_MOVIE_FULLSCREEN(siLapText, 255, 255, 255, 255)
|
|
SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_HUD)
|
|
ENDIF
|
|
ELSE
|
|
BEGIN_SCALEFORM_MOVIE_METHOD(siLapText, "SHARD_ANIM_OUT")
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(ENUM_TO_INT(HUD_COLOUR_WHITE))
|
|
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(0.33)
|
|
END_SCALEFORM_MOVIE_METHOD()
|
|
eLapTextState = LTS_CLEANUP
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE LTS_CLEANUP
|
|
IF GET_GAME_TIMER() < iLapTextTimer
|
|
IF HAS_SCALEFORM_MOVIE_LOADED(siLapText)
|
|
DRAW_SCALEFORM_MOVIE_FULLSCREEN(siLapText, 255, 255, 255, 255)
|
|
SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_HUD)
|
|
ENDIF
|
|
ELSE
|
|
IF HAS_SCALEFORM_MOVIE_LOADED(siLapText)
|
|
SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(siLapText)
|
|
ENDIF
|
|
eLapTextState = LTS_READY
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Updates race HUD (current lap, lap time, etc)
|
|
PROC UPDATE_RACE_HUD()
|
|
IF sRaceData.eRaceTrack = SEA_RACE_01 OR sRaceData.eRaceTrack = SEA_RACE_02 OR sRaceData.eRaceTrack = SEA_RACE_03 OR sRaceData.eRaceTrack = SEA_RACE_04
|
|
OR sRaceData.eRaceTrack = STREET_RACE_02
|
|
|
|
SET_FAR_RIGHT_TITLE_POSITION_HUD_THIS_FRAME()
|
|
|
|
DRAW_P2P_RACE_HUD(GET_GAME_TIMER() - sRaceHUD.iStartTime, // Race time elapsed
|
|
0, // friend/world/crew/personal record
|
|
"", // "RACE TIME"
|
|
sRaceHUD.iPlayerPosition, // PositionNum - The position Number
|
|
sTrackData.iNumAIRacers+1, // PositionMaxNumber - The position maximum number
|
|
"", // "POSITION"
|
|
0, // ExtraTimeGiven - If any extra time is given to the timer, pass this in to display +xs -xs
|
|
HUD_COLOUR_WHITE, // PlacementColour - The position numbers can change colour
|
|
sRaceHUD.iCurrentCheckPoint, // Current checkpoint number
|
|
sRaceHUD.iMaxCheckpoints, // Total number of checkpoints
|
|
"",
|
|
HUD_COLOUR_WHITE,TRUE, -1, "", -1.0, HUD_COLOUR_WHITE,-1.0,
|
|
iGlobalBest)
|
|
ELSE
|
|
//MAINTAIN_BIG_MESSAGE()
|
|
DISPLAY_LAPS_BIG_TEXT()
|
|
DISABLE_SCRIPT_HUD_THIS_FRAME(HUDPART_RANKBAR)
|
|
IF IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_MULTIPLAYER_INFO)
|
|
/*IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_FRONTEND_DOWN)
|
|
g_Show_Lap_Dpad = NOT g_Show_Lap_Dpad
|
|
iDpadDownTimer = GET_GAME_TIMER() + DPAD_DOWN_TIME*/
|
|
IF NOT g_Show_Lap_Dpad
|
|
g_Show_Lap_Dpad = TRUE
|
|
ENDIF
|
|
ELSE//IF GET_GAME_TIMER() > iDpadDownTimer
|
|
IF g_Show_Lap_Dpad
|
|
g_Show_Lap_Dpad = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SET_FAR_RIGHT_TITLE_POSITION_HUD_THIS_FRAME()
|
|
|
|
DRAW_LOOP_RACE_HUD(GET_GAME_TIMER() - sRaceHUD.iStartTime, // Race time elapsed
|
|
0, // friend/world/crew/personal record
|
|
"", // "RACE TIME"
|
|
sRaceHUD.iCurrentLap, // Current lap number
|
|
sTrackData.iNumLaps, // Maximum number of laps
|
|
"", // "LAP"
|
|
sRaceHUD.iPlayerPosition, // PositionNum - The position Number
|
|
sTrackData.iNumAIRacers+1, // PositionMaxNumber - The position maximum number
|
|
"", // "POSITION"
|
|
0, // ExtraTimeGiven - If any extra time is given to the timer, pass this in to display +xs -xs
|
|
HUD_COLOUR_WHITE, // PlacementColour - The position numbers can change colour
|
|
sRaceHUD.iCurrentCheckPoint, // Current checkpoint number
|
|
sRaceHUD.iMaxCheckpoints, // Total number of checkpoints
|
|
"",
|
|
HUD_COLOUR_WHITE,
|
|
-1,
|
|
-1,
|
|
"",
|
|
HUD_COLOUR_RED,
|
|
sRaceHUD.iBestTime, // BestTime - Will need this hooked up with save data
|
|
"", // BestTimeTitle - NULL by default
|
|
GET_GAME_TIMER() - sRaceHUD.iCurrentTime, // Time elapsed for current lap
|
|
"", // "CURRENT LAP"
|
|
PODIUMPOS_NONE,TRUE,-1,"",-1,HUD_COLOUR_WHITE,HUD_COLOUR_WHITE,-1,
|
|
iGlobalBest)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the player's vehicle is in water and if it should be
|
|
/// RETURNS:
|
|
/// TRUE if the player is in water and driving a speedophile OR is not in water and is driving a car or bike
|
|
FUNC BOOL IS_PLAYER_VEHICLE_APPROPRIATELY_IN_WATER()
|
|
IF IS_ENTITY_IN_WATER(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
|
|
IF sRaceData.eRaceType = RACETYPE_CAR
|
|
OR sRaceData.eRaceType = RACETYPE_BIKE
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player car / bike is in water")
|
|
RETURN FALSE
|
|
ELSE
|
|
IF iSpeedophileOutOfWaterTimer >=0
|
|
iSpeedophileOutOfWaterTimer = -1
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
IF IS_ENTITY_IN_AIR(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
|
|
iSpeedophileOutOfWaterTimer = -1
|
|
RETURN TRUE
|
|
ENDIF
|
|
IF iSpeedophileOutOfWaterTimer < 0
|
|
iSpeedophileOutOfWaterTimer = GET_GAME_TIMER() + 2000
|
|
ELIF GET_GAME_TIMER() > iSpeedophileOutOfWaterTimer
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player speedophile is not in water")
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Allows the player to respawn his car back on the track at the last checkpoint
|
|
PROC UPDATE_PLAYER_VEHICLE_RESPAWNING()
|
|
//SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_SCRIPT_RUP)
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_OnlyExitVehicleOnButtonRelease, TRUE)
|
|
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
IF NOT IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
|
|
bPlayerVehicleNeedsRecovering = TRUE
|
|
racesRespawnState = RACES_RESPAWN_ACTIVE
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player vehicle is undriveable")
|
|
ENDIF
|
|
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("RACES_RHELP")
|
|
IF NOT IS_PLAYER_VEHICLE_APPROPRIATELY_IN_WATER()
|
|
PRINT_HELP_FOREVER("RACES_RHELP") // Press and hold ~INPUT_SCRIPT_RUP~ to return to the race.
|
|
iStuckHelpTimer = GET_GAME_TIMER() + STUCK_HELP_TIME
|
|
ENDIF
|
|
IF IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_HUNG_UP, 30000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_JAMMED, 60000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_ROOF, 20000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_SIDE, 3000)
|
|
PRINT_HELP_FOREVER("RACES_RHELP") // Press and hold ~INPUT_SCRIPT_RUP~ to return to the race.
|
|
iStuckHelpTimer = GET_GAME_TIMER() + STUCK_HELP_TIME
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player vehicle is stuck")
|
|
ENDIF
|
|
ELIF GET_GAME_TIMER() > iStuckHelpTimer
|
|
IF IS_PLAYER_VEHICLE_APPROPRIATELY_IN_WATER()
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_HUNG_UP, 30000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_JAMMED, 60000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_ROOF, 20000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_SIDE, 3000)
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
IF IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
OR IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
OR bPlayerVehicleNeedsRecovering = TRUE
|
|
INT i_waypoint_to_warp_to, i_waypoint_to_point_to
|
|
VECTOR v_waypoint_to_warp_to, v_next_waypoint
|
|
SWITCH racesRespawnState
|
|
CASE RACES_RESPAWN_SET
|
|
iPlayerWantsToRecoverVehicleTimer = GET_GAME_TIMER()
|
|
racesRespawnState = RACES_RESPAWN_INIT
|
|
BREAK
|
|
CASE RACES_RESPAWN_INIT
|
|
IF (GET_GAME_TIMER() - iPlayerWantsToRecoverVehicleTimer) > 500
|
|
iPlayerWantsToRecoverVehicleTimer = GET_GAME_TIMER() // Set again
|
|
racesRespawnState = RACES_RESPAWN_CHECK
|
|
ENDIF
|
|
BREAK
|
|
CASE RACES_RESPAWN_CHECK
|
|
DRAW_GENERIC_METER(GET_GAME_TIMER() - iPlayerWantsToRecoverVehicleTimer, 1500, "RACES_RMETER", HUD_COLOUR_RED, 0, HUDORDER_EIGHTHBOTTOM, -1, -1, FALSE, TRUE)
|
|
IF (GET_GAME_TIMER() - iPlayerWantsToRecoverVehicleTimer) >= 400
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
ENDIF
|
|
IF (GET_GAME_TIMER() - iPlayerWantsToRecoverVehicleTimer) >= 1500
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player has held triangle for long enough, so begin respawning at last checkpoint")
|
|
racesRespawnState = RACES_RESPAWN_ACTIVE
|
|
ENDIF
|
|
BREAK
|
|
CASE RACES_RESPAWN_ACTIVE
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
/*IF sRaceHUD.iCurrentCheckPoint = 0
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, 0, v_waypoint_to_warp_to)
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, 1, v_next_waypoint)
|
|
ELSE*/
|
|
VECTOR vCheckpointToWarpTo
|
|
IF sRaceHUD.iCurrentCheckPoint > 0
|
|
vCheckpointToWarpTo = sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint - 1]
|
|
ELSE
|
|
vCheckpointToWarpTo = sTrackData.vStartGrid[sTrackData.iNumAIRacers]
|
|
ENDIF
|
|
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT(sRaceWaypointRecording, vCheckpointToWarpTo, i_waypoint_to_warp_to)
|
|
i_waypoint_to_point_to = i_waypoint_to_warp_to + 1
|
|
IF i_waypoint_to_point_to >= iNumWaypoints
|
|
i_waypoint_to_point_to = 0
|
|
ENDIF
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, i_waypoint_to_warp_to, v_waypoint_to_warp_to)
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, i_waypoint_to_point_to, v_next_waypoint)
|
|
//ENDIF
|
|
IF NOT IS_ANY_VEHICLE_NEAR_POINT(v_waypoint_to_warp_to, 5) // Make sure the new checkpoint we're warping to is clear
|
|
OR GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(sPlayerVehicle.vehPlayerVehicle, v_waypoint_to_warp_to) < 5 // In case it's this vehicle within the 5 metres
|
|
SET_ENTITY_COORDS(sPlayerVehicle.vehPlayerVehicle, v_waypoint_to_warp_to)
|
|
SET_ENTITY_HEADING_FACE_COORDS(sPlayerVehicle.vehPlayerVehicle, v_next_waypoint) // Face next waypoint
|
|
SET_VEHICLE_FIXED(sPlayerVehicle.vehPlayerVehicle)
|
|
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
ENDIF
|
|
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
|
|
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
|
|
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("RACES_RHELP")
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Successfully repositioned player's vehicle")
|
|
racesRespawnState = RACES_RESPAWN_WAIT
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
CASE RACES_RESPAWN_WAIT
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
IF NOT IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
AND NOT IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player released triangle")
|
|
ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
|
|
iPlayerWantsToRecoverVehicleTimer = -1
|
|
bPlayerVehicleNeedsRecovering = FALSE
|
|
racesRespawnState = RACES_RESPAWN_SET
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ELSE
|
|
/*IF iPlayerWantsToRecoverVehicleTimer > -1
|
|
AND (GET_GAME_TIMER() - iPlayerWantsToRecoverVehicleTimer) < 500 // Player only tapped triangle, so wants to exit his car
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player wants to exit vehicle, triangle was pressed for ", GET_GAME_TIMER() - iPlayerWantsToRecoverVehicleTimer)
|
|
IF GET_ENTITY_SPEED(PLAYER_PED_ID()) < 1.0
|
|
TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID())
|
|
ELSE
|
|
TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID(), 0, ECF_JUMP_OUT)
|
|
ENDIF
|
|
ENDIF*/
|
|
iPlayerWantsToRecoverVehicleTimer = -1
|
|
bPlayerVehicleNeedsRecovering = FALSE
|
|
racesRespawnState = RACES_RESPAWN_SET
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Works out which checkpoint type is needed based upon angle between checkpoints
|
|
FUNC CHECKPOINT_TYPE GET_RACE_CHECKPOINT_TYPE(INT iCheckNum)
|
|
|
|
VECTOR pos, pos2, pos3
|
|
VECTOR vec1, vec2
|
|
|
|
FLOAT fReturnAngle
|
|
|
|
pos = sTrackData.vCheckpoint[iCheckNum]
|
|
|
|
IF iCheckNum+1 = sTrackData.iNumCheckpoints //- 1
|
|
pos2 = sTrackData.vCheckpoint[0]
|
|
ELSE
|
|
pos2 = sTrackData.vCheckpoint[iCheckNum + 1]
|
|
ENDIF
|
|
|
|
IF iCheckNum - 1 >= 0
|
|
pos3 = sTrackData.vCheckpoint[iCheckNum-1]
|
|
ENDIF
|
|
|
|
vec1 = pos3 - pos
|
|
vec2 = pos2 - pos
|
|
|
|
fReturnAngle = GET_ANGLE_BETWEEN_2D_VECTORS(vec1.x, vec1.y, vec2.x, vec2.y)
|
|
|
|
IF fReturnAngle > 180
|
|
fReturnAngle = (360.0 - fReturnAngle)
|
|
ENDIF
|
|
|
|
IF fReturnAngle < fChev3
|
|
|
|
RETURN CHECKPOINT_RACE_GROUND_CHEVRON_3
|
|
|
|
ELIF fReturnAngle < fChev2
|
|
|
|
RETURN CHECKPOINT_RACE_GROUND_CHEVRON_2
|
|
|
|
ELIF fReturnAngle < fChev1
|
|
|
|
RETURN CHECKPOINT_RACE_GROUND_CHEVRON_1
|
|
ELSE
|
|
RETURN CHECKPOINT_RACE_GROUND_CHEVRON_1
|
|
ENDIF
|
|
|
|
RETURN CHECKPOINT_RACE_GROUND_CHEVRON_1
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Gets appropriate checkpoint colour based on chevron type
|
|
/*FUNC HUD_COLOURS GET_RACE_CHECKPOINT_COLOUR(CHECKPOINT_TYPE cpType)
|
|
|
|
IF cpType = CHECKPOINT_RACE_GROUND_CHEVRON_3
|
|
OR cpType = CHECKPOINT_RACE_WATER_CHEVRON_3
|
|
RETURN HUD_COLOUR_YELLOWDARK
|
|
|
|
ELIF cpType = CHECKPOINT_RACE_GROUND_CHEVRON_2
|
|
OR cpType = CHECKPOINT_RACE_WATER_CHEVRON_2
|
|
RETURN HUD_COLOUR_YELLOW
|
|
ELSE
|
|
RETURN HUD_COLOUR_YELLOWLIGHT
|
|
ENDIF
|
|
ENDFUNC*/
|
|
|
|
/// PURPOSE:
|
|
/// Gets appropriate checkpoint alpha based on the player's distance from the checkpoint
|
|
FUNC INT GET_CHECKPOINT_ALPHA(INT iCheckpoint)
|
|
FLOAT fDis
|
|
INT iA = 240
|
|
|
|
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
fDis = GET_DISTANCE_BETWEEN_COORDS(sTrackData.vCheckPoint[iCheckpoint], GET_ENTITY_COORDS(PLAYER_PED_ID()))
|
|
IF fDis > 100.0
|
|
iA = 240
|
|
ELSE
|
|
iA = ROUND(fDis*2.4)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN iA
|
|
ENDFUNC
|
|
|
|
FUNC VECTOR CALCULATE_QUAD_NORMAL(VECTOR &verts[])
|
|
INT i
|
|
VECTOR u, v
|
|
VECTOR norm
|
|
|
|
REPEAT COUNT_OF(verts) i
|
|
u = verts[i]
|
|
v = verts[(i + 1) % COUNT_OF(verts)]
|
|
|
|
norm.x += (u.y - v.y) * (u.z + v.z)
|
|
norm.y += (u.z - v.z) * (u.x + v.x)
|
|
norm.z += (u.x - v.x) * (u.y + v.y)
|
|
|
|
ENDREPEAT
|
|
|
|
RETURN NORMALISE_VECTOR(norm)
|
|
ENDFUNC
|
|
|
|
FUNC VECTOR GET_CHECKOINT_OFFSET(INT i)
|
|
SWITCH i
|
|
CASE 0 RETURN <<0,0,1>>
|
|
CASE 1 RETURN <<FMMC_CHECKPOINT_SIZE/2,0,1>>
|
|
CASE 2 RETURN <<-FMMC_CHECKPOINT_SIZE/2,0,1>>
|
|
CASE 3 RETURN <<0,FMMC_CHECKPOINT_SIZE/2,1>>
|
|
CASE 4 RETURN <<0,-FMMC_CHECKPOINT_SIZE/2,1>>
|
|
CASE 5 RETURN <<FMMC_CHECKPOINT_SIZE/2,FMMC_CHECKPOINT_SIZE/2,1>>
|
|
CASE 6 RETURN <<-FMMC_CHECKPOINT_SIZE/2,-FMMC_CHECKPOINT_SIZE/2,1>>
|
|
CASE 7 RETURN <<FMMC_CHECKPOINT_SIZE/2,-FMMC_CHECKPOINT_SIZE/2,1>>
|
|
CASE 8 RETURN <<-FMMC_CHECKPOINT_SIZE/2,FMMC_CHECKPOINT_SIZE/2,1>>
|
|
ENDSWITCH
|
|
RETURN <<0,0,0>>
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Clips the bottom off the checkpoint so it doesn't poke through roads
|
|
/// PARAMS:
|
|
/// checkP - The checpoint to clip
|
|
/// vCheckPointGroundPos - The coordinates of the checkpoint
|
|
PROC CLIP_THE_CHECKPOINT(CHECKPOINT_INDEX checkP, VECTOR vCheckPointGroundPos)
|
|
int i
|
|
VECTOR vecArray[8]
|
|
FLOAT fGround
|
|
FOR i = 0 TO 7
|
|
vecArray[i] = vCheckPointGroundPos + GET_CHECKOINT_OFFSET(i)
|
|
GET_GROUND_Z_FOR_3D_COORD(vecArray[i],fGround)
|
|
IF fGround < vCheckPointGroundPos.z - 2
|
|
OR fGround > vCheckPointGroundPos.z + 2
|
|
vecArray[i].z = vCheckPointGroundPos.z
|
|
PRINTINT(i)PRINTSTRING("vPos z. vecArray[i] = ")PRINTVECTOR(vecArray[i])PRINTNL()
|
|
ELSE
|
|
vecArray[i].z = fGround
|
|
PRINTINT(i)PRINTSTRING("offset z. vecArray[i] = ")PRINTVECTOR(vecArray[i])PRINTNL()
|
|
ENDIF
|
|
ENDFOR
|
|
|
|
VECTOR vFinalNormal = CALCULATE_QUAD_NORMAL(vecArray)
|
|
PRINTNL()PRINTSTRING("vFinalNormal = ")PRINTVECTOR(vFinalNormal)PRINTNL()PRINTNL()
|
|
SET_CHECKPOINT_CLIPPLANE_WITH_POS_NORM(checkP, vCheckPointGroundPos - <<0,0,0.3>>, vFinalNormal)
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Blip the destination marker
|
|
PROC BLIP_CURRENT_CHECKPOINT(INT iCheckpoint, BOOL bRaceFlag = FALSE, BOOL bDoPulse = TRUE)
|
|
|
|
INT iR, iG, iB, iA, iR2, iG2, iB2, iA2, iPreviousCheck
|
|
CHECKPOINT_TYPE cpType = GET_RACE_CHECKPOINT_TYPE(iCheckpoint)
|
|
|
|
GET_HUD_COLOUR(HUD_COLOUR_YELLOWLIGHT, iR, iG, iB, iA)
|
|
GET_HUD_COLOUR(HUD_COLOUR_NORTH_BLUE, iR2, iG2, iB2, iA2)
|
|
iA = GET_CHECKPOINT_ALPHA(iCheckpoint)
|
|
|
|
// Is this marker already shown?
|
|
IF DOES_BLIP_EXIST(biCurrentCheckPoint)
|
|
IF ciCurrentCheckPoint != NULL
|
|
SET_CHECKPOINT_RGBA(ciCurrentCheckPoint,iR, iG, iB, iA)
|
|
SET_CHECKPOINT_RGBA2(ciCurrentCheckPoint,iR2, iG2, iB2, iA)
|
|
ENDIF
|
|
ELSE
|
|
|
|
VECTOR currentCheckpoint, nextCheckpoint, prevCheckpoint, vHeightCheck
|
|
FLOAT fCheckPointSize, fCheckPointHeight, fHeightCheck
|
|
|
|
// Get current checkpoint position
|
|
currentCheckpoint = sTrackData.vCheckPoint[iCheckpoint]
|
|
|
|
// check the type of checkpoint needed
|
|
vHeightCheck = currentCheckpoint
|
|
vHeightCheck.z += 20.0
|
|
BOOL bUnderBridge = FALSE
|
|
IF GET_GROUND_Z_FOR_3D_COORD(vHeightCheck, fHeightCheck)
|
|
IF fHeightCheck > (currentCheckpoint.z + 1.0)
|
|
fCheckPointSize = FMMC_CHECKPOINT_SIZE*1*0.66
|
|
fCheckPointHeight = 2.0
|
|
bUnderBridge = TRUE
|
|
ELSE
|
|
fCheckPointSize = (CHECKPOINT_VISUAL_SIZE * CHECKPOINT_VISUAL_SIZE_MODIFIER)
|
|
fCheckPointHeight = fCheckpointDrawSize
|
|
ENDIF
|
|
ELSE
|
|
fCheckPointSize = (CHECKPOINT_VISUAL_SIZE * CHECKPOINT_VISUAL_SIZE_MODIFIER)
|
|
fCheckPointHeight = fCheckpointDrawSize
|
|
ENDIF
|
|
|
|
// Next checkpoint
|
|
IF iCheckpoint = sTrackData.iNumCheckpoints - 1
|
|
nextCheckpoint = sTrackData.vCheckPoint[0]
|
|
ELSE
|
|
nextCheckpoint = sTrackData.vCheckPoint[iCheckpoint+1]
|
|
ENDIF
|
|
|
|
// Previous checkpoint
|
|
iPreviousCheck = iCheckpoint - 1
|
|
IF iPreviousCheck < 0
|
|
iPreviousCheck = sTrackData.iNumCheckpoints - 1
|
|
ENDIF
|
|
prevCheckpoint = sTrackData.vCheckPoint[iPreviousCheck]
|
|
|
|
// Blip checkpoint
|
|
biCurrentCheckPoint = ADD_BLIP_FOR_COORD(currentCheckpoint)
|
|
|
|
SHOW_HEIGHT_ON_BLIP(biCurrentCheckPoint, FALSE)
|
|
|
|
// Setup race arrow for current checkpoint
|
|
IF NOT bRaceFlag
|
|
|
|
SET_BLIP_COLOUR(biCurrentCheckPoint, BLIP_COLOUR_YELLOW)
|
|
|
|
SET_BLIP_SCALE(biCurrentCheckPoint, 1.2)
|
|
SET_BLIP_PRIORITY(biCurrentCheckPoint, BLIPPRIORITY_HIGHEST)
|
|
|
|
IF bUnderBridge
|
|
SWITCH cpType
|
|
CASE CHECKPOINT_RACE_WATER_CHEVRON_3
|
|
CASE CHECKPOINT_RACE_GROUND_CHEVRON_3
|
|
cpType = CHECKPOINT_RACE_AIR_CHEVRON_3
|
|
BREAK
|
|
|
|
CASE CHECKPOINT_RACE_WATER_CHEVRON_2
|
|
CASE CHECKPOINT_RACE_GROUND_CHEVRON_2
|
|
cpType = CHECKPOINT_RACE_AIR_CHEVRON_2
|
|
BREAK
|
|
|
|
CASE CHECKPOINT_RACE_WATER_CHEVRON_1
|
|
CASE CHECKPOINT_RACE_GROUND_CHEVRON_1
|
|
cpType = CHECKPOINT_RACE_AIR_CHEVRON_1
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDIF
|
|
|
|
ciCurrentCheckPoint = CREATE_CHECKPOINT(cpType,(currentCheckpoint+<<0,0,fCheckPointHeight>>), nextCheckpoint, fCheckPointSize, iR, iG, iB, iA)//150)
|
|
SET_CHECKPOINT_RGBA2(ciCurrentCheckPoint,iR2, iG2, iB2, iA)
|
|
CLIP_THE_CHECKPOINT(ciCurrentCheckPoint, currentCheckpoint)
|
|
|
|
// Chequered flag!
|
|
ELSE
|
|
SET_BLIP_SPRITE(biCurrentCheckPoint, RADAR_TRACE_RACEFLAG)
|
|
SET_BLIP_PRIORITY(biCurrentCheckPoint, BLIPPRIORITY_HIGH)
|
|
SET_BLIP_SCALE(biCurrentCheckPoint, 1.2)
|
|
|
|
ciCurrentCheckPoint = CREATE_CHECKPOINT(CHECKPOINT_RACE_GROUND_FLAG, (currentCheckpoint+<<0,0,fCheckPointHeight>>), nextCheckpoint, fCheckPointSize, iR, iG, iB, iA)//150)
|
|
SET_CHECKPOINT_RGBA2(ciCurrentCheckPoint,iR2, iG2, iB2, iA)
|
|
CLIP_THE_CHECKPOINT(ciCurrentCheckPoint, currentCheckpoint)
|
|
ENDIF
|
|
|
|
IF bDoPulse
|
|
cpType = GET_RACE_CHECKPOINT_TYPE(iPreviousCheck)
|
|
GET_HUD_COLOUR(HUD_COLOUR_WHITE, iR, iG, iB, iPrevAlpha)
|
|
iPrevAlpha = 180
|
|
IF ciPreviousCheckPoint != NULL
|
|
DELETE_CHECKPOINT(ciPreviousCheckPoint)
|
|
ENDIF
|
|
ciPreviousCheckPoint = CREATE_CHECKPOINT(cpType,(prevCheckpoint+<<0,0,fCheckPointHeight>>), currentCheckpoint, fCheckPointSize, iR, iG, iB, iPrevAlpha)//150)
|
|
ENDIF
|
|
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
SET_CHECKPOINT_CYLINDER_HEIGHT(ciCurrentCheckPoint,16.0,16.0,100)
|
|
SET_CHECKPOINT_CYLINDER_HEIGHT(ciPreviousCheckPoint,16.0,16.0,100)
|
|
ELSE
|
|
SET_CHECKPOINT_CYLINDER_HEIGHT(ciCurrentCheckPoint,9.5,9.5,100)
|
|
SET_CHECKPOINT_CYLINDER_HEIGHT(ciPreviousCheckPoint,9.5,9.5,100)
|
|
ENDIF
|
|
SET_BLIP_NAME_FROM_TEXT_FILE(biCurrentCheckPoint, "BLIP_CPOINT")
|
|
ENDIF
|
|
|
|
// Fade out the green checkpoint
|
|
IF ciPreviousCheckPoint != NULL
|
|
iPrevAlpha -= 25
|
|
IF iPrevAlpha > 0
|
|
GET_HUD_COLOUR(HUD_COLOUR_WHITE, iR, iG, iB, iA)
|
|
SET_CHECKPOINT_RGBA(ciPreviousCheckPoint,iR, iG, iB, iPrevAlpha)
|
|
ELSE
|
|
DELETE_CHECKPOINT(ciPreviousCheckPoint)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Draw the current race marker
|
|
PROC BLIP_NEXT_CHECKPOINT(VECTOR nextCheckpoint, BOOL bRaceFlag = FALSE)
|
|
|
|
IF NOT DOES_BLIP_EXIST(biNextCheckPoint)
|
|
|
|
biNextCheckPoint = ADD_BLIP_FOR_COORD(nextCheckpoint)
|
|
|
|
SHOW_HEIGHT_ON_BLIP(biNextCheckPoint, FALSE)
|
|
|
|
IF NOT bRaceFlag
|
|
|
|
// Normal checkpoint
|
|
SET_BLIP_COLOUR(biNextCheckPoint, BLIP_COLOUR_YELLOW)
|
|
SET_BLIP_SCALE(biNextCheckPoint, 0.7)
|
|
ELSE
|
|
// Finish line
|
|
IF sRaceHUD.iCurrentLap = sTrackData.iNumLaps
|
|
SET_BLIP_SPRITE(biNextCheckPoint, RADAR_TRACE_RACEFLAG)
|
|
SET_BLIP_SCALE(biNextCheckPoint, 1.2)
|
|
/*ELSE
|
|
SET_BLIP_COLOUR(biNextCheckPoint, BLIP_COLOUR_WHITE)
|
|
SET_BLIP_SCALE(biNextCheckPoint, 0.7)*/
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SET_BLIP_NAME_FROM_TEXT_FILE(biNextCheckPoint, "BLIP_CPOINT")
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Draw the current race markers
|
|
PROC DRAW_RACE_CHECKPOINTS(BOOL bDoPulse = TRUE)
|
|
|
|
// Get next checkpoint
|
|
INT iNextCheckpoint = sRaceHUD.iCurrentCheckPoint + 1
|
|
|
|
// POINT TO POINT RACE
|
|
IF sRaceData.bP2P
|
|
|
|
// Final checkpoint of current lap
|
|
IF sRaceHUD.iCurrentCheckPoint = sTrackData.iNumCheckpoints - 1
|
|
BLIP_CURRENT_CHECKPOINT(sTrackData.iNumCheckpoints-1, TRUE, bDoPulse)
|
|
ELSE
|
|
// Normal checkpoint
|
|
BLIP_CURRENT_CHECKPOINT(sRaceHUD.iCurrentCheckPoint, FALSE, bDoPulse)
|
|
|
|
// Next checkpoint is the finish/new lap
|
|
IF iNextCheckpoint = sTrackData.iNumCheckpoints - 1
|
|
BLIP_NEXT_CHECKPOINT(sTrackData.vCheckPoint[iNextCheckpoint], TRUE)
|
|
ELSE
|
|
BLIP_NEXT_CHECKPOINT(sTrackData.vCheckPoint[iNextCheckpoint])
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// CIRCUIT RACE
|
|
ELSE
|
|
// Final checkpoint of current lap
|
|
IF sRaceHUD.iCurrentCheckPoint = sTrackData.iNumCheckpoints - 1
|
|
|
|
// Finish line
|
|
IF sRaceHUD.iCurrentLap = sTrackData.iNumLaps
|
|
BLIP_CURRENT_CHECKPOINT(sRaceHUD.iCurrentCheckPoint, TRUE, bDoPulse)
|
|
ELSE
|
|
// New lap
|
|
BLIP_CURRENT_CHECKPOINT(sRaceHUD.iCurrentCheckPoint, FALSE, bDoPulse)
|
|
BLIP_NEXT_CHECKPOINT(sTrackData.vCheckPoint[0])
|
|
ENDIF
|
|
ELSE
|
|
// Normal checkpoint
|
|
BLIP_CURRENT_CHECKPOINT(sRaceHUD.iCurrentCheckPoint, FALSE, bDoPulse)
|
|
|
|
// Next checkpoint is the finish/new lap
|
|
IF iNextCheckpoint = sTrackData.iNumCheckpoints - 1
|
|
BLIP_NEXT_CHECKPOINT(sTrackData.vCheckPoint[iNextCheckpoint], TRUE)
|
|
ELSE
|
|
BLIP_NEXT_CHECKPOINT(sTrackData.vCheckPoint[iNextCheckpoint])
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC REMOVE_PLAYER_VEHICLE_BLIP_AND_TEXT()
|
|
|
|
IF DOES_BLIP_EXIST(sPlayerVehicle.biPlayerVehicle)
|
|
REMOVE_BLIP(sPlayerVehicle.biPlayerVehicle)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
TRIGGER_MUSIC_EVENT("MGSR_BACK_ON")
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_THIS_PRINT_BEING_DISPLAYED("CAR_BACK") // ~s~Get back in the ~b~car.
|
|
OR IS_THIS_PRINT_BEING_DISPLAYED("BIKE_BACK") // ~s~Get back on the ~b~bike.
|
|
OR IS_THIS_PRINT_BEING_DISPLAYED("SEA_BACK") // ~s~Get back on the ~b~seashark.
|
|
CLEAR_PRINTS()
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_PLAYER_VEHICLE_STUCK()
|
|
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle) AND sRaceData.eRaceType = RACETYPE_CAR
|
|
IF IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_ROOF, 1000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_SIDE, 1000)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Checks for player being in his race vehicle, see B*929894
|
|
FUNC BOOL IS_PLAYER_IN_VEHICLE()
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
|
|
failReason = FAIL_ALERTED_COPS
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
|
|
IF IS_VEHICLE_DRIVEABLE(sPlayerVehicle.vehPlayerVehicle) AND NOT IS_PLAYER_VEHICLE_STUCK()
|
|
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
REMOVE_PLAYER_VEHICLE_BLIP_AND_TEXT()
|
|
UPDATE_PLAYER_VEHICLE_RESPAWNING()
|
|
RETURN TRUE
|
|
ELSE
|
|
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player has got into a different vehicle so abandoning race")
|
|
failReason = FAIL_ABANDONED_RACE
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ELSE
|
|
CLEANUP_CHECKPOINTS(FALSE)
|
|
// Remove the help message if the player leaves their vehicle
|
|
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("RACES_RHELP") AND GET_GAME_TIMER() > iStuckHelpTimer
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
IF NOT DOES_BLIP_EXIST(sPlayerVehicle.biPlayerVehicle) AND NOT
|
|
(sRaceData.eRaceType = RACETYPE_CAR AND (IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_ROOF, 1000)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sPlayerVehicle.vehPlayerVehicle, VEH_STUCK_ON_SIDE, 1000)))
|
|
sPlayerVehicle.biPlayerVehicle = ADD_BLIP_FOR_ENTITY(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_BLIP_AS_FRIENDLY(sPlayerVehicle.biPlayerVehicle, TRUE)
|
|
SET_BLIP_SCALE(sPlayerVehicle.biPlayerVehicle, BLIP_SIZE_VEHICLE)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
TRIGGER_MUSIC_EVENT("MGSR_FELL_OFF")
|
|
ENDIF
|
|
IF sPlayerVehicle.bDisplayedGetBackInVehicleText = FALSE
|
|
sPlayerVehicle.bDisplayedGetBackInVehicleText = TRUE
|
|
SWITCH sRaceData.eRaceType
|
|
CASE RACETYPE_BIKE
|
|
PRINT_NOW("BIKE_BACK", DEFAULT_GOD_TEXT_TIME, 1) // ~s~Get back on the ~b~bike.
|
|
BREAK
|
|
CASE RACETYPE_CAR
|
|
PRINT_NOW("CAR_BACK", DEFAULT_GOD_TEXT_TIME, 1) // ~s~Get back in the ~b~car.
|
|
BREAK
|
|
CASE RACETYPE_SEA
|
|
PRINT_NOW("SEA_BACK", DEFAULT_GOD_TEXT_TIME, 1) // ~s~Get back in the ~b~vehicle.
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
/*IF sPlayerVehicle.vehPlayerVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
|
|
CLEANUP_CHECKPOINTS(FALSE)
|
|
IF NOT DOES_BLIP_EXIST(sPlayerVehicle.biPlayerVehicle)
|
|
sPlayerVehicle.biPlayerVehicle = ADD_BLIP_FOR_ENTITY(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_BLIP_AS_FRIENDLY(sPlayerVehicle.biPlayerVehicle, TRUE)
|
|
SET_BLIP_SCALE(sPlayerVehicle.biPlayerVehicle, BLIP_SIZE_VEHICLE)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
TRIGGER_MUSIC_EVENT("MGSR_FELL_OFF")
|
|
ENDIF
|
|
IF sPlayerVehicle.bDisplayedGetBackInVehicleText = FALSE
|
|
sPlayerVehicle.bDisplayedGetBackInVehicleText = TRUE
|
|
SWITCH sRaceData.eRaceType
|
|
CASE RACETYPE_BIKE
|
|
PRINT_NOW("CMN_GENGETBCKBK", DEFAULT_GOD_TEXT_TIME, 1) // ~s~Get back on the ~b~bike.
|
|
BREAK
|
|
CASE RACETYPE_CAR
|
|
PRINT_NOW("CMN_GENGETBCK", DEFAULT_GOD_TEXT_TIME, 1) // ~s~Get back in the ~b~car.
|
|
BREAK
|
|
CASE RACETYPE_SEA
|
|
PRINT_NOW("SEA_GETINVEH", DEFAULT_GOD_TEXT_TIME, 1) // ~s~Get back in the ~b~vehicle.
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player has got into a different vehicle so abandoning race")
|
|
failReason = FAIL_ABANDONED_RACE
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ENDIF*/
|
|
ENDIF
|
|
ELSE
|
|
REMOVE_PLAYER_VEHICLE_BLIP_AND_TEXT()
|
|
failReason = FAIL_WRECKED
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE: Updates checkpoint markers
|
|
FUNC BOOL UPDATE_RACE_CHECKPOINTS(BOOL bDoPulse = TRUE)
|
|
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
|
|
// Handle drawing checkpoints and race arrows
|
|
DRAW_RACE_CHECKPOINTS(bDoPulse)
|
|
|
|
// Handle J-skipping
|
|
#IF IS_DEBUG_BUILD
|
|
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J)
|
|
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
|
|
SET_PED_COORDS_KEEP_VEHICLE(PLAYER_PED_ID(), sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint])
|
|
ENDIF
|
|
ENDIF
|
|
#ENDIF
|
|
|
|
// Swap for less costly IS_ENTITY_AT_COORDS check?
|
|
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint]) <= CHECKPOINT_LOCATE_SIZE
|
|
|
|
PLAY_SOUND_FRONTEND(-1, "CHECKPOINT_NORMAL", "HUD_MINI_GAME_SOUNDSET", FALSE)
|
|
|
|
// End of current lap
|
|
IF sRaceHUD.iCurrentCheckPoint = sRaceHUD.iMaxCheckpoints - 1
|
|
|
|
// Reset lap time
|
|
INT iLapTime = GET_GAME_TIMER() - sRaceHUD.iCurrentTime
|
|
IF sRaceHUD.iBestTime < 0 OR sRaceHUD.iBestTime > iLapTime
|
|
sRaceHUD.iBestTime = iLapTime
|
|
ENDIF
|
|
sRaceHUD.iCurrentTime = GET_GAME_TIMER()
|
|
|
|
// Chequered flag!
|
|
IF sRaceHUD.iCurrentLap = sTrackData.iNumLaps
|
|
CLEANUP_RACE_CHECKPOINTS()
|
|
RETURN TRUE
|
|
ELSE
|
|
// New lap
|
|
sRaceHUD.iCurrentLap++
|
|
sRaceHUD.iCurrentCheckPoint = 0
|
|
//SETUP_NEW_BIG_MESSAGE_WITH_2_INTS(BIG_MESSAGE_LAP, sRaceHUD.iCurrentLap, sTrackData.iNumLaps)
|
|
eLapTextState = LTS_LOAD
|
|
ENDIF
|
|
ELSE
|
|
// Update checkpoint
|
|
sRaceHUD.iCurrentCheckPoint++
|
|
ENDIF
|
|
//KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
|
|
//CONTROL_COORD_CHASE_HINT_CAM_ANY_MEANS(localChaseHintCamStruct, sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint])
|
|
|
|
SET_DISTANCE_TO_NEXT_CHECKPOINT()
|
|
|
|
// Remove checkpoint marker
|
|
CLEANUP_RACE_CHECKPOINTS()
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Returns the base speed for this particular rival driver on this particular track
|
|
FUNC FLOAT GET_BASE_SPEED(INT i_index)
|
|
FLOAT f_base_speed
|
|
SWITCH sRacer[i_index].drivingSpeed
|
|
CASE AI_DRIVING_SPEED_SLOW
|
|
f_base_speed = sTrackData.drivingSpeedSlow
|
|
BREAK
|
|
CASE AI_DRIVING_SPEED_MEDIUM
|
|
f_base_speed = sTrackData.drivingSpeedMedium
|
|
BREAK
|
|
CASE AI_DRIVING_SPEED_FAST
|
|
f_base_speed = sTrackData.drivingSpeedFast
|
|
BREAK
|
|
ENDSWITCH
|
|
RETURN f_base_speed
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Increases/decreases the driver's speed if it's behind/ahead of the player
|
|
PROC UPDATE_WAYPOINT_RECORDING_SPEED(INT i_index)
|
|
|
|
FLOAT f_new_speed = GET_BASE_SPEED(i_index)
|
|
FLOAT f_distance = GET_DISTANCE_BETWEEN_ENTITIES(sRacer[i_index].viCar, PLAYER_PED_ID())
|
|
|
|
IF sRacer[i_index].iCurrentPoint-1 < sRaceHUD.iCurrentCheckPoint // Rival is behind the player
|
|
IF f_distance > 50
|
|
f_new_speed += (f_new_speed*1.0) // Rival is far behind so speed up a lot
|
|
ELIF f_distance > 25
|
|
f_new_speed += (f_new_speed*0.7) // Rival is far behind so speed up a lot
|
|
ELSE
|
|
f_new_speed += (f_new_speed*0.3)
|
|
ENDIF
|
|
ELSE // Rival is ahead of the player
|
|
IF f_distance > 100
|
|
f_new_speed -= (f_new_speed*0.3) // Rival is far ahead so decrease a lot
|
|
ELIF f_distance > 25
|
|
f_new_speed -= (f_new_speed*0.1)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF sRacer[i_index].fLastSpeed <> f_new_speed
|
|
sRacer[i_index].fLastSpeed = f_new_speed
|
|
SET_DRIVE_TASK_CRUISE_SPEED(sRacer[i_index].piDriver, f_new_speed)
|
|
//CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " speed set to ", f_new_speed)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC UPDATE_AI_CHECKPOINT(INT i_index)
|
|
INT iFinalCheckpoint
|
|
IF sTrackData.iNumLaps = 0
|
|
iFinalCheckpoint = sTrackData.iNumCheckpoints - 2
|
|
ELSE
|
|
iFinalCheckpoint = sTrackData.iNumCheckpoints - 1
|
|
ENDIF
|
|
IF sRacer[i_index].iCurrentPoint = iFinalCheckpoint // End of current lap
|
|
sRacer[i_index].iCurrentPoint = 0
|
|
sRacer[i_index].iCurrentLap++
|
|
// Don't want AI racers to stop at the end of the final lap, keep them driving
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " starting lap ", sRacer[i_index].iCurrentLap)
|
|
|
|
// Switch the point to point racers to a wander task
|
|
IF sRacer[i_index].iCurrentLap > sTrackData.iNumLaps
|
|
TASK_VEHICLE_DRIVE_WANDER(sRacer[i_index].piDriver, sRacer[i_index].viCar, 30, DRIVINGMODE_AVOIDCARS_RECKLESS)
|
|
ENDIF
|
|
ELSE
|
|
sRacer[i_index].iCurrentPoint++
|
|
ENDIF
|
|
// Update AI destination
|
|
IF sRacer[i_index].stateAI = AI_RACER_ACTIVE
|
|
UPDATE_WAYPOINT_RECORDING_SPEED(i_index)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if a racer is in a suitable point to start warping
|
|
/// PARAMS:
|
|
/// i_index - which racer we're checking
|
|
/// bUsingHao - is Hao in this race
|
|
/// RETURNS:
|
|
/// TRUE if we might need to warp this racer
|
|
FUNC BOOL SHOULD_WE_CHECK_FOR_WARPING(INT i_index, BOOL bUsingHao)
|
|
|
|
IF (sRacer[i_index].iCurrentLap < sRaceHUD.iCurrentLap)
|
|
// a lap behind the player so good to check
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF (sRacer[i_index].iCurrentLap > sRaceHUD.iCurrentLap)
|
|
// a lap ahead of the player so no need to check
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (sRacer[i_index].iCurrentLap = sRaceHUD.iCurrentLap AND sRacer[i_index].iCurrentPoint >= sRaceHUD.iCurrentCheckPoint)
|
|
// Racer is on the same lap as the player but at a later checkpoint so no need to check
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// If we've got here, the racer is on the same lap but behind player
|
|
|
|
IF bUsingHao = FALSE
|
|
// Hao is not in this race so we're fine
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF bUsingHao AND i_index <> (sTrackData.iNumAIRacers-1)
|
|
// Hao is in this race but this isn't him so we're fine
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF (bUsingHao AND i_index = (sTrackData.iNumAIRacers-1) AND sRacer[i_index].iCurrentPoint > 1)
|
|
// This is Hao so also make sure he's not heading for the first checkpoint
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Tries to reposition the rival closer behind the player
|
|
PROC CHECK_REPOSITION_RIVAL_BEHIND_PLAYER(INT i_index, BOOL bUsingHao)
|
|
|
|
FLOAT fStopWarpDistance
|
|
IF bUsingHao AND i_index = (sTrackData.iNumAIRacers-1)
|
|
fStopWarpDistance = 20
|
|
ELSE
|
|
fStopWarpDistance = STOP_WARP_DISTANCE
|
|
ENDIF
|
|
|
|
SWITCH sRacer[i_index].eWarpState
|
|
CASE AWS_READY
|
|
IF SHOULD_WE_CHECK_FOR_WARPING(i_index, bUsingHao)
|
|
AND IS_PED_IN_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar) AND IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(sRacer[i_index].viCar)
|
|
AND GET_IS_WAYPOINT_RECORDING_LOADED(sRaceWaypointRecording)
|
|
|
|
INT iCurrentWaypoint, iPlayerWaypoint, iWarpWaypoint
|
|
FLOAT fDistance
|
|
VECTOR vWarpCoords, vPlayerWaypoint//, vNextWaypoint
|
|
|
|
iCurrentWaypoint = GET_VEHICLE_WAYPOINT_TARGET_POINT(sRacer[i_index].viCar)
|
|
IF iCurrentWaypoint < 1
|
|
iCurrentWaypoint = 1
|
|
ENDIF
|
|
//iCurrentWaypoint++ // increase by 1 to get the next waypoint along the route
|
|
|
|
IF iCurrentWaypoint < iNumWaypoints
|
|
iWarpWaypoint = iCurrentWaypoint + 1
|
|
ELSE
|
|
iWarpWaypoint = 1//0
|
|
ENDIF
|
|
|
|
IF WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT(sRaceWaypointRecording, GET_ENTITY_COORDS(PLAYER_PED_ID()), iPlayerWaypoint)
|
|
AND WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, iWarpWaypoint, vWarpCoords)
|
|
AND WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, iPlayerWaypoint, vPlayerWaypoint)
|
|
|
|
fDistance = GET_DISTANCE_BETWEEN_COORDS(vPlayerWaypoint, vWarpCoords)
|
|
|
|
IF (fDistance > WARP_DISTANCE OR sRacer[i_index].iCurrentLap < sRaceHUD.iCurrentLap) // Racer is too far behind the player
|
|
AND NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), sRacer[i_index].viCar, fStopWarpDistance)// AND sRacer[i_index].iCurrentLap >= sRaceHUD.iCurrentLap)
|
|
AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vWarpCoords, fStopWarpDistance)// AND sRacer[i_index].iCurrentLap >= sRaceHUD.iCurrentLap)
|
|
AND NOT IS_SPHERE_VISIBLE(GET_ENTITY_COORDS(sRacer[i_index].viCar), 5.0) // Racer has caught up so start racing again
|
|
AND NOT IS_SPHERE_VISIBLE(vWarpCoords, 5.0)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " has entered its warping state")
|
|
IF bUsingHao AND i_index = (sTrackData.iNumAIRacers-1)
|
|
sRacer[i_index].iWarpTimer = GET_GAME_TIMER() + 90
|
|
ELSE
|
|
sRacer[i_index].iWarpTimer = GET_GAME_TIMER() + 100 + (i_index*10)
|
|
ENDIF
|
|
sRacer[i_index].iWarpWaypoint = iWarpWaypoint
|
|
sRacer[i_index].eWarpState = AWS_WARPING
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE AWS_WARPING
|
|
INT iTargetWaypoint
|
|
VECTOR vWarpCoords, vNextWaypoint
|
|
|
|
IF sRacer[i_index].iWarpWaypoint < iNumWaypoints
|
|
iTargetWaypoint = sRacer[i_index].iWarpWaypoint + 1
|
|
ELSE
|
|
iTargetWaypoint = 1//0
|
|
ENDIF
|
|
|
|
IF WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, sRacer[i_index].iWarpWaypoint, vWarpCoords)
|
|
|
|
IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), sRacer[i_index].viCar, fStopWarpDistance)// AND sRacer[i_index].iCurrentLap >= sRaceHUD.iCurrentLap)
|
|
OR IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vWarpCoords, fStopWarpDistance)// AND sRacer[i_index].iCurrentLap >= sRaceHUD.iCurrentLap)
|
|
OR IS_SPHERE_VISIBLE(GET_ENTITY_COORDS(sRacer[i_index].viCar), 5.0) // Racer has caught up so start racing again
|
|
OR IS_SPHERE_VISIBLE(vWarpCoords, 5.0)
|
|
OR (sRacer[i_index].iCurrentLap = sRaceHUD.iCurrentLap AND sRacer[i_index].iCurrentPoint >= sRaceHUD.iCurrentCheckPoint) // Same lap but ahead of player
|
|
OR sRacer[i_index].iCurrentLap > sRaceHUD.iCurrentLap
|
|
|
|
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRacer[i_index].piDriver, sRacer[i_index].viCar, sRaceWaypointRecording, DRIVINGMODE_AVOIDCARS_RECKLESS, iTargetWaypoint, EWAYPOINT_VEHICLES_USE_AI_SLOWDOWN, -1, GET_BASE_SPEED(i_index), bLoopWaypointRecording)
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
SET_VEHICLE_FORWARD_SPEED(sRacer[i_index].viCar, GET_BASE_SPEED(i_index)*0.25)
|
|
ELSE
|
|
SET_VEHICLE_FORWARD_SPEED(sRacer[i_index].viCar, GET_BASE_SPEED(i_index)*0.5)
|
|
ENDIF
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " has completed its warping at waypoint ", sRacer[i_index].iWarpWaypoint)
|
|
sRacer[i_index].eWarpState = AWS_READY
|
|
ELSE
|
|
|
|
//IF NOT IS_SPHERE_VISIBLE(vWarpCoords, 3) AND NOT IS_SPHERE_VISIBLE(GET_ENTITY_COORDS(sRacer[i_index].viCar), 3.0) // Racer and target point are off screen
|
|
IF GET_GAME_TIMER() > sRacer[i_index].iWarpTimer
|
|
|
|
IF NOT IS_ANY_VEHICLE_NEAR_POINT(vWarpCoords, 5) // Make sure the new checkpoint we're warping to is clear
|
|
OR IS_ENTITY_IN_RANGE_COORDS(sRacer[i_index].viCar, vWarpCoords, 5) // In case it's this vehicle within the 5 metres
|
|
|
|
IF WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, iTargetWaypoint, vNextWaypoint)
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, vWarpCoords)
|
|
SET_ENTITY_HEADING_FACE_COORDS(sRacer[i_index].viCar, vNextWaypoint) // Face next checkpoint
|
|
// Check if racer has reached next checkpoint
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vWarpCoords, sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint], FALSE) <= (CHECKPOINT_LOCATE_SIZE*2)
|
|
//CPRINTLN(DEBUG_MISSION, "Mission Race: Updating checkpoint while warping for Rival ", i_index)
|
|
UPDATE_AI_CHECKPOINT(i_index)
|
|
ENDIF
|
|
sRacer[i_index].iWarpWaypoint = iTargetWaypoint
|
|
sRacer[i_index].iWarpTimer = GET_GAME_TIMER() + 100 + (i_index*10)
|
|
|
|
IF NOT IS_PED_IN_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar)
|
|
SET_PED_INTO_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar)
|
|
ENDIF
|
|
|
|
iReplayRecordWarpTimer = GET_GAME_TIMER() + 1500
|
|
iReplayRecordWarpTimer = iReplayRecordWarpTimer
|
|
//CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " has been repositioned at waypoint ", iTargetWaypoint)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE AWS_FINISHED
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the rival vehicle needs recovering (ie upsidedown, in water, etc)
|
|
FUNC BOOL DOES_RIVAL_VEHICLE_NEED_RECOVERING(INT i_index)
|
|
|
|
IF sRaceData.eRaceType = RACETYPE_CAR // Bikes and speedophiles can be corrected so only check if upsidedown for car races
|
|
IF IS_ENTITY_UPSIDEDOWN(sRacer[i_index].viCar)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sRacer[i_index].viCar, VEH_STUCK_ON_ROOF, ROOF_TIME)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sRacer[i_index].viCar, VEH_STUCK_ON_SIDE, SIDE_TIME)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " is upsidedown so needs recovering")
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_ENTITY_IN_WATER(sRacer[i_index].viCar)
|
|
IF sRaceData.eRaceType = RACETYPE_CAR
|
|
OR sRaceData.eRaceType = RACETYPE_BIKE
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Rival ", i_index, " is in water so needs recovering")
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_VEHICLE_STUCK_TIMER_UP(sRacer[i_index].viCar, VEH_STUCK_HUNG_UP, HUNG_UP_TIME)
|
|
OR IS_VEHICLE_STUCK_TIMER_UP(sRacer[i_index].viCar, VEH_STUCK_JAMMED, JAMMED_TIME)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
/*IF sRacer[i_index].iCurrentLap <= sRaceHUD.iCurrentLap AND sRacer[i_index].iCurrentPoint < sRaceHUD.iCurrentCheckPoint
|
|
AND GET_DISTANCE_BETWEEN_ENTITIES(sRacer[i_index].viCar, PLAYER_PED_ID(), FALSE) > 100
|
|
RETURN TRUE
|
|
ENDIF*/
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Rival needs recovering and is not onscreen, so warp him
|
|
PROC RECOVER_RIVAL_USING_WARP(INT i_index)
|
|
|
|
INT i_waypoint_to_warp_to
|
|
VECTOR v_waypoint_to_warp_to, v_next_waypoint
|
|
|
|
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT(sRaceWaypointRecording, GET_ENTITY_COORDS(sRacer[i_index].viCar), i_waypoint_to_warp_to)
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, i_waypoint_to_warp_to, v_waypoint_to_warp_to)
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, i_waypoint_to_warp_to+1, v_next_waypoint)
|
|
//FLOAT f_PlayerWarpPointDist = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), v_waypoint_to_warp_to, FALSE)
|
|
|
|
// Make sure the point to warp to is far enough from the player that the warp won't be seen
|
|
//IF f_PlayerWarpPointDist > 200
|
|
// Make sure the new checkpoint we're warping to is clear and not on screen
|
|
IF NOT IS_SPHERE_VISIBLE(v_waypoint_to_warp_to, 3)
|
|
IF NOT IS_ANY_VEHICLE_NEAR_POINT(v_waypoint_to_warp_to, 5)
|
|
OR GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(sRacer[i_index].viCar, v_waypoint_to_warp_to) < 5 // In case it's this vehicle within the 5 metres
|
|
SET_ENTITY_COORDS(sRacer[i_index].viCar, v_waypoint_to_warp_to)
|
|
SET_ENTITY_HEADING_FACE_COORDS(sRacer[i_index].viCar, v_next_waypoint) // Face next checkpoint
|
|
|
|
IF NOT IS_PED_IN_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar)
|
|
SET_PED_INTO_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar)
|
|
ENDIF
|
|
|
|
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRacer[i_index].piDriver, sRacer[i_index].viCar, sRaceWaypointRecording, DRIVINGMODE_AVOIDCARS_RECKLESS, i_waypoint_to_warp_to, EWAYPOINT_VEHICLES_USE_AI_SLOWDOWN, -1, GET_BASE_SPEED(i_index)*2, bLoopWaypointRecording)
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Warped rival ", i_index, " into his vehicle")
|
|
|
|
iReplayRecordWarpTimer = GET_GAME_TIMER() + 1500
|
|
iReplayRecordWarpTimer = iReplayRecordWarpTimer
|
|
ENDIF
|
|
ENDIF
|
|
//ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Rival no longer in his vehicle, and is onscreen, so task him to get back inside
|
|
PROC RECOVER_RIVAL_NOT_USING_WARP(INT i_index)
|
|
IF sRacer[i_index].gGivenGetOnVehTask = FALSE
|
|
INT i_waypoint_to_warp_to
|
|
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT(sRaceWaypointRecording, GET_ENTITY_COORDS(sRacer[i_index].viCar), i_waypoint_to_warp_to)
|
|
OPEN_SEQUENCE_TASK(seqGetInVehicle)
|
|
TASK_ENTER_VEHICLE(NULL, sRacer[i_index].viCar, 10000)
|
|
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(NULL, sRacer[i_index].viCar, sRaceWaypointRecording, DRIVINGMODE_AVOIDCARS_RECKLESS, i_waypoint_to_warp_to, EWAYPOINT_VEHICLES_USE_AI_SLOWDOWN, -1, GET_BASE_SPEED(i_index)*2, bLoopWaypointRecording)
|
|
CLOSE_SEQUENCE_TASK(seqGetInVehicle)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, seqGetInVehicle)
|
|
CLEAR_SEQUENCE_TASK(seqGetInVehicle)
|
|
sRacer[i_index].gGivenGetOnVehTask = TRUE
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Tasked rival ", i_index, " to get into his vehicle")
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if the AI racer has reached their next checkpoint, different tests for sea races and street races
|
|
/// PARAMS:
|
|
/// i_index - the index of the racer we're testing
|
|
/// RETURNS:
|
|
/// TRUE if the racer has reached their checkpoint
|
|
FUNC BOOL IS_AI_RACER_AT_CHECKPOINT(INT i_index)
|
|
VECTOR vCurrentRacerCoords
|
|
//IF sRaceData.eRaceType = RACETYPE_SEA
|
|
vCurrentRacerCoords = GET_ENTITY_COORDS(sRacer[i_index].viCar)
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vCurrentRacerCoords, sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint], FALSE) <= CHECKPOINT_LOCATE_SIZE // Racer has reached next checkpoint
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
INT iClosestWaypoint
|
|
INT j_index = 0
|
|
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT(sRaceWaypointRecording, GET_ENTITY_COORDS(sRacer[i_index].viCar), iClosestWaypoint)
|
|
|
|
REPEAT 5 j_index
|
|
IF (iClosestWaypoint-j_index) > 0
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, iClosestWaypoint-j_index, vCurrentRacerCoords)
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vCurrentRacerCoords, sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint], FALSE) <= CHECKPOINT_LOCATE_SIZE // Racer has reached next checkpoint
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
/*ELSE
|
|
vCurrentRacerCoords = GET_ENTITY_COORDS(sRacer[i_index].viCar)
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vCurrentRacerCoords, sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint], FALSE) <= CHECKPOINT_LOCATE_SIZE // Racer has reached next checkpoint
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF*/
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Handles the AI racer boosting at the race start
|
|
/// PARAMS:
|
|
/// i_index - the AI racer to boost
|
|
PROC HANDLE_AI_BOOST(INT i_index)
|
|
SWITCH sRacer[i_index].eBoostState
|
|
CASE BS_READY
|
|
// Only trigger on racers ahead of player
|
|
VECTOR vRacerRelativePos
|
|
vRacerRelativePos = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(PLAYER_PED_ID(), GET_ENTITY_COORDS(sRacer[i_index].viCar))
|
|
IF (vRacerRelativePos.x > -2 AND vRacerRelativePos.x < 2) OR i_index = 0
|
|
CPRINTLN(DEBUG_MISSION,"Boost triggered for racer ", i_index)
|
|
sRacer[i_index].iBoostTimer = GET_GAME_TIMER() + BOOST_TIME
|
|
sRacer[i_index].eBoostState = BS_ACTIVE
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION,"Racer ", i_index, " wasn't directly in front of the player")
|
|
sRacer[i_index].eBoostState = BS_FINISHED
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE BS_ACTIVE
|
|
IF GET_GAME_TIMER() > sRacer[i_index].iBoostTimer
|
|
CPRINTLN(DEBUG_MISSION,"Boost finished for racer ", i_index)
|
|
sRacer[i_index].eBoostState = BS_FINISHED
|
|
ELSE
|
|
APPLY_FORCE_TO_ENTITY(sRacer[i_index].viCar, APPLY_TYPE_FORCE, <<0.0, 25.0, 0.0>>, <<0.0, 0.0, 0.0>>, 0, TRUE, TRUE, TRUE)
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Makes the AI racer look at the player if the player bumps them
|
|
/// PARAMS:
|
|
/// i_index - the AI racer to handle looking
|
|
PROC HANDLE_AI_LOOKAT(INT i_index)
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle) AND IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
IF sRacer[i_index].bReadyToLook
|
|
IF IS_ENTITY_TOUCHING_ENTITY(sPlayerVehicle.vehPlayerVehicle, sRacer[i_index].viCar)
|
|
sRacer[i_index].bReadyToLook = FALSE
|
|
sRacer[i_index].iLookAtTimer = GET_GAME_TIMER() + 4000
|
|
CPRINTLN(DEBUG_MISSION,"Player bumped racer ", i_index, ", starting lookat")
|
|
ENDIF
|
|
ELSE
|
|
IF sRacer[i_index].iLookAtTimer > GET_GAME_TIMER()
|
|
SET_IK_TARGET(sRacer[i_index].piDriver, IK_PART_HEAD, PLAYER_PED_ID(), 0, << 0.0, 0.0, 0.0 >>, ITF_DEFAULT, 150, 400)
|
|
ELSE
|
|
sRacer[i_index].bReadyToLook = TRUE
|
|
CPRINTLN(DEBUG_MISSION,"Lookat finished for racer ", i_index)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Individual racer update
|
|
PROC UPDATE_RACER(INT i_index, BOOL bAllowRacerSix = TRUE, BOOL bUsingHao = FALSE)
|
|
|
|
// Array safety check
|
|
IF (i_index >= 0) OR (i_index < sTrackData.iNumAIRacers)
|
|
|
|
// Valid references
|
|
IF IS_RACER_OK(i_index)
|
|
|
|
CHECK_REPOSITION_RIVAL_BEHIND_PLAYER(i_index, bUsingHao)
|
|
|
|
// Check if the driver isn't in his vehicle, or the vehicle needs recovering
|
|
IF NOT IS_PED_IN_VEHICLE(sRacer[i_index].piDriver, sRacer[i_index].viCar)
|
|
|
|
/*IF GET_DISTANCE_BETWEEN_ENTITIES(sRacer[i_index].viCar, PLAYER_PED_ID(), FALSE) > 100
|
|
CHECK_REPOSITION_RIVAL_BEHIND_PLAYER(i_index)
|
|
EL*/IF NOT IS_SPHERE_VISIBLE(GET_ENTITY_COORDS(sRacer[i_index].viCar), 3)
|
|
RECOVER_RIVAL_USING_WARP(i_index)
|
|
ELSE
|
|
RECOVER_RIVAL_NOT_USING_WARP(i_index)
|
|
ENDIF
|
|
|
|
ELIF DOES_RIVAL_VEHICLE_NEED_RECOVERING(i_index)
|
|
|
|
/*IF GET_DISTANCE_BETWEEN_ENTITIES(sRacer[i_index].viCar, PLAYER_PED_ID(), FALSE) > 100
|
|
CHECK_REPOSITION_RIVAL_BEHIND_PLAYER(i_index)
|
|
EL*/IF NOT IS_SPHERE_VISIBLE(GET_ENTITY_COORDS(sRacer[i_index].viCar), 3)
|
|
RECOVER_RIVAL_USING_WARP(i_index)
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
HANDLE_AI_BOOST(i_index)
|
|
HANDLE_AI_LOOKAT(i_index)
|
|
|
|
// Handle racer state
|
|
SWITCH sRacer[i_index].stateAI
|
|
|
|
CASE AI_RACER_INIT
|
|
sRacer[i_index].iCurrentPoint = 0
|
|
sRacer[i_index].iCurrentLap = 1
|
|
IF sRaceData.eRaceType = RACETYPE_CAR // Only cars can do burnouts
|
|
IF bAllowRacerSix OR i_index <> 6
|
|
TASK_VEHICLE_TEMP_ACTION(sRacer[i_index].piDriver, sRacer[i_index].viCar, TEMPACT_BURNOUT, (i_index+1)*BURNOUT_SPREAD_TIME)
|
|
ENDIF
|
|
ENDIF
|
|
sRacer[i_index].stateAI = AI_RACER_WAIT_FOR_BURNOUT_FINISHED
|
|
BREAK
|
|
|
|
CASE AI_RACER_WAIT_FOR_BURNOUT_FINISHED
|
|
IF (((GET_GAME_TIMER() - sRaceHUD.iStartTime) > (i_index+1)*BURNOUT_SPREAD_TIME) OR sRaceData.eRaceType <> RACETYPE_CAR)
|
|
AND GET_IS_WAYPOINT_RECORDING_LOADED(sRaceWaypointRecording)
|
|
sRacer[i_index].fLastSpeed = GET_BASE_SPEED(i_index)
|
|
IF sRaceData.eRaceTrack = STREET_RACE_01 OR sRaceData.eRaceTrack = STREET_RACE_02 OR sRaceData.eRaceTrack = STREET_RACE_04 OR sRaceData.eRaceTrack = STREET_RACE_05 OR sRaceData.eRaceTrack = STREET_RACE_06
|
|
INT iTarget
|
|
VECTOR vDest
|
|
FLOAT fStraightLine
|
|
IF i_index = 0 OR i_index = 2 OR i_index = 4
|
|
iTarget = 0
|
|
ELSE
|
|
iTarget = 1
|
|
ENDIF
|
|
vDest = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sRacer[iTarget].viCar, <<0,20,0>>)
|
|
fStraightLine = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(sRacer[i_index].viCar, vDest)
|
|
SEQUENCE_INDEX siRace
|
|
OPEN_SEQUENCE_TASK(siRace)
|
|
TASK_VEHICLE_DRIVE_TO_COORD(NULL, sRacer[i_index].viCar, vDest, sRacer[i_index].fLastSpeed, DRIVINGSTYLE_RACING, GET_ENTITY_MODEL(sRacer[i_index].viCar), DRIVINGMODE_AVOIDCARS_RECKLESS | DF_ForceStraightLine, 3.0, fStraightLine)
|
|
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(NULL, sRacer[i_index].viCar, sRaceWaypointRecording, DRIVINGMODE_AVOIDCARS_RECKLESS, 0, EWAYPOINT_VEHICLES_USE_AI_SLOWDOWN | EWAYPOINT_START_FROM_CLOSEST_POINT, -1, sRacer[i_index].fLastSpeed, bLoopWaypointRecording)
|
|
CLOSE_SEQUENCE_TASK(siRace)
|
|
TASK_PERFORM_SEQUENCE(sRacer[i_index].piDriver, siRace)
|
|
CLEAR_SEQUENCE_TASK(siRace)
|
|
ELSE
|
|
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRacer[i_index].piDriver, sRacer[i_index].viCar, sRaceWaypointRecording, DRIVINGMODE_AVOIDCARS_RECKLESS, 0, EWAYPOINT_VEHICLES_USE_AI_SLOWDOWN, -1, sRacer[i_index].fLastSpeed, bLoopWaypointRecording)
|
|
ENDIF
|
|
sRacer[i_index].stateAI = AI_RACER_ACTIVE
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE AI_RACER_ACTIVE
|
|
/*VECTOR vCurrentRacerCoords
|
|
IF sRaceData.eRaceType = RACETYPE_SEA
|
|
INT iClosestWaypoint
|
|
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT(sRaceWaypointRecording, GET_ENTITY_COORDS(sRacer[i_index].viCar), iClosestWaypoint)
|
|
WAYPOINT_RECORDING_GET_COORD(sRaceWaypointRecording, iClosestWaypoint, vCurrentRacerCoords)
|
|
ELSE
|
|
vCurrentRacerCoords = GET_ENTITY_COORDS(sRacer[i_index].viCar)
|
|
ENDIF
|
|
IF GET_DISTANCE_BETWEEN_COORDS(vCurrentRacerCoords, sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint], FALSE) <= (FMMC_CHECKPOINT_SIZE + FMMC_CHECKPOINT_SIZE) // Racer has reached next checkpoint
|
|
*/
|
|
IF IS_AI_RACER_AT_CHECKPOINT(i_index) AND sRacer[i_index].eWarpState <> AWS_WARPING
|
|
UPDATE_AI_CHECKPOINT(i_index)
|
|
ENDIF
|
|
//CHECK_REPOSITION_RIVAL_BEHIND_PLAYER(i_index)
|
|
sRacer[i_index].gGivenGetOnVehTask = FALSE
|
|
BREAK
|
|
|
|
CASE AI_RACER_FINISHED_RACE
|
|
BREAK
|
|
|
|
ENDSWITCH
|
|
ENDIF
|
|
|
|
// Update the vehicle's blip position, this ensures the blip moves smoothly if the vehicle is warped
|
|
MANAGE_SLIDY_BLIP_FOR_ENTITY(sRacer[i_index].biBlip, sRacer[i_index].viCar, TRUE)
|
|
/*IF NOT DOES_BLIP_EXIST(sPlayerVehicle.biPlayerVehicle)
|
|
IF NOT DOES_BLIP_EXIST(sRacer[i_index].biBlip)
|
|
sRacer[i_index].biBlip = CREATE_BLIP_FOR_VEHICLE(sRacer[i_index].viCar)
|
|
ENDIF
|
|
ENDIF*/
|
|
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Updates the player's current position
|
|
PROC UPDATE_PLAYER_POS()
|
|
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
|
|
sRaceHUD.iPlayerPosition = 1 // If no racers are ahead of the player he is at position 1 so start with this value
|
|
|
|
INT i_closest_checkpoint_to_player = sRaceHUD.iCurrentCheckPoint // Set initially to the checkpoint that the player should be heading to
|
|
|
|
FLOAT fPlayerDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint])
|
|
|
|
IF fPlayerDistFromCheckpoint > fNextCheckpointDistance+100
|
|
CPRINTLN(DEBUG_MISSION, "Mission Race: Player going in opposite direction to the next checkpoint so abandoning race")
|
|
INT iNextCheckpoint = sRaceHUD.iCurrentCheckPoint + 1
|
|
IF iNextCheckpoint >= sTrackData.iNumCheckpoints
|
|
iNextCheckpoint = 0
|
|
ENDIF
|
|
FLOAT fPlayerDistFromNextCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sTrackData.vCheckPoint[iNextCheckpoint])
|
|
FLOAT fDistBetweenCheckpoints = GET_DISTANCE_BETWEEN_COORDS(sTrackData.vCheckPoint[iNextCheckpoint], sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint]) + 20
|
|
IF fPlayerDistFromNextCheckpoint < fDistBetweenCheckpoints
|
|
failReason = FAIL_MISSED_CHECKPOINT
|
|
ELSE
|
|
failReason = FAIL_ABANDONED_RACE
|
|
ENDIF
|
|
eRaceState = RACE_STATE_FAIL
|
|
eRaceSubState = RACE_SUBSTATE_SETUP
|
|
EXIT
|
|
ELIF fPlayerDistFromCheckpoint > fNextCheckpointDistance+FMMC_CHECKPOINT_SIZE // Player is driving away from the checkpoint he should be heading towards, FMMC_CHECKPOINT_SIZE is for overlap
|
|
// Player can reach a checkpoint then backtrack, so we need to check for which checkpoint the player is actually nearest to
|
|
// If he's nearer to a checkpoint less than sRaceHUD.iCurrentCheckPoint, we'll use the updated checkpoint to determine his position in the race, not the checkpoint he should be heading towards
|
|
INT i_checkpoint = 0
|
|
FLOAT f_closest_distance = 9999
|
|
FLOAT f_current_distance
|
|
REPEAT sTrackData.iNumCheckpoints i_checkpoint
|
|
IF i_checkpoint < sRaceHUD.iCurrentCheckPoint // Only look at checkpoints less than sRaceHUD.iCurrentCheckPoint
|
|
f_current_distance = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sTrackData.vCheckPoint[i_checkpoint])
|
|
IF f_current_distance < f_closest_distance
|
|
f_closest_distance = f_current_distance
|
|
i_closest_checkpoint_to_player = i_checkpoint
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDIF
|
|
//CPRINTLN(DEBUG_MISSION, "Mission Race: i_closest_checkpoint_to_player = ", i_closest_checkpoint_to_player, " fPlayerDistFromCheckpoint = ", fPlayerDistFromCheckpoint, " fNextCheckpointDistance = ", fNextCheckpointDistance)
|
|
|
|
FLOAT fRacerDistFromCheckpoint
|
|
|
|
INT i_index = 0
|
|
REPEAT sTrackData.iNumAIRacers i_index
|
|
|
|
IF IS_ENTITY_ALIVE(sRacer[i_index].piDriver)
|
|
|
|
IF sRacer[i_index].stateAI = AI_RACER_FINISHED_RACE // The racer has already finished
|
|
sRaceHUD.iPlayerPosition++
|
|
|
|
ELIF sRacer[i_index].iCurrentLap > sRaceHUD.iCurrentLap // The racer is a lap ahead of the player
|
|
sRaceHUD.iPlayerPosition++
|
|
|
|
ELIF sRacer[i_index].iCurrentLap = sRaceHUD.iCurrentLap // The racer is on the same lap as the player so compare their checkpoint positions
|
|
|
|
IF sRacer[i_index].iCurrentPoint > i_closest_checkpoint_to_player // The racer's checkpoint is further along than the player's checkpoint
|
|
sRaceHUD.iPlayerPosition++
|
|
|
|
ELIF sRacer[i_index].iCurrentPoint = i_closest_checkpoint_to_player // The racer's checkpoint is the same as the player's so compare their distances from it
|
|
|
|
fPlayerDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sTrackData.vCheckPoint[i_closest_checkpoint_to_player])
|
|
fRacerDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRacer[i_index].viCar), sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint])
|
|
IF fRacerDistFromCheckpoint < fPlayerDistFromCheckpoint // The racer is closer to the checkpoint than the player is
|
|
sRaceHUD.iPlayerPosition++
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
// Commenting out for now in case this is needed again
|
|
/// PURPOSE:
|
|
/// Gets the index of the second placed AI driver
|
|
/// RETURNS:
|
|
/// -1 if the function was unable to get a second place driver, the index otherwise
|
|
/*FUNC INT GET_SECOND_PLACE_CAR()
|
|
INT iRacerPosition[MAX_AI_RACERS]
|
|
FLOAT fRacerIDistFromCheckpoint
|
|
FLOAT fRacerJDistFromCheckpoint
|
|
|
|
INT i_index = 0
|
|
REPEAT sTrackData.iNumAIRacers i_index
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
iRacerPosition[i_index] = 2 // for this to have been called, the player must be in first place, therefore the best AI racer is in second
|
|
|
|
INT j_index = 0
|
|
REPEAT sTrackData.iNumAIRacers j_index
|
|
IF IS_VEHICLE_OK(sRacer[j_index].viCar)
|
|
|
|
IF sRacer[j_index].iCurrentLap > sRacer[i_index].iCurrentLap // racer j is a lap ahead of racer i
|
|
iRacerPosition[i_index]++
|
|
|
|
ELIF sRacer[j_index].iCurrentLap = sRacer[i_index].iCurrentLap // The racers are on the same lap so compare their checkpoint positions
|
|
|
|
IF sRacer[j_index].iCurrentPoint > sRacer[i_index].iCurrentPoint // racer j's checkpoint is further along than racer i's checkpoint
|
|
iRacerPosition[i_index]++
|
|
|
|
ELIF sRacer[j_index].iCurrentPoint = sRacer[i_index].iCurrentPoint // The racers's checkpoints are the same so compare their distances from it
|
|
|
|
fRacerIDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRacer[i_index].viCar), sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint])
|
|
fRacerJDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRacer[j_index].viCar), sTrackData.vCheckPoint[sRacer[j_index].iCurrentPoint])
|
|
IF fRacerJDistFromCheckpoint < fRacerIDistFromCheckpoint // The racer is closer to the checkpoint than the player is
|
|
iRacerPosition[i_index]++
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
i_index = 0
|
|
REPEAT sTrackData.iNumAIRacers i_index
|
|
IF iRacerPosition[i_index] = 2
|
|
RETURN i_index
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN -1
|
|
ENDFUNC*/
|
|
|
|
/// PURPOSE:
|
|
/// Sets the hint camera to target the AI car ahead of the player
|
|
/*PROC CAM_HINT_FOR_NEXT_CAR()
|
|
// If the player is in the lead, don't bother with the hint camera
|
|
IF sRaceHUD.iPlayerPosition > 1
|
|
INT iRacerPosition[MAX_AI_RACERS]
|
|
FLOAT fRacerIDistFromCheckpoint
|
|
FLOAT fOtherDistFromCheckpoint
|
|
|
|
INT i_index = 0
|
|
REPEAT sTrackData.iNumAIRacers i_index
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
iRacerPosition[i_index] = 1
|
|
|
|
VEHICLE_INDEX viPlayer
|
|
viPlayer = GET_PLAYERS_LAST_VEHICLE()
|
|
IF IS_VEHICLE_OK(viPlayer)
|
|
|
|
IF sRaceHUD.iCurrentLap > sRacer[i_index].iCurrentLap // player is a lap ahead of the racer
|
|
iRacerPosition[i_index]++
|
|
|
|
ELIF sRacer[i_index].iCurrentLap = sRaceHUD.iCurrentLap // racer is on the same lap as the player so compare checkpoint positions
|
|
IF sRacer[i_index].iCurrentPoint > sRaceHUD.iCurrentCheckPoint // player's checkpoint is ahead of the racer's
|
|
iRacerPosition[i_index]++
|
|
|
|
ELIF sRacer[i_index].iCurrentPoint = sRaceHUD.iCurrentCheckPoint // player's checkpoint is the same as the racer's, compare distances from it
|
|
fRacerIDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRacer[i_index].viCar), sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint])
|
|
fOtherDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(viPlayer), sTrackData.vCheckPoint[sRaceHUD.iCurrentCheckPoint])
|
|
IF fOtherDistFromCheckpoint < fRacerIDistFromCheckpoint // The player is closer to the checkpoint than the racer is
|
|
iRacerPosition[i_index]++
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
INT j_index = 0
|
|
REPEAT sTrackData.iNumAIRacers j_index
|
|
IF IS_VEHICLE_OK(sRacer[j_index].viCar)
|
|
|
|
IF sRacer[j_index].iCurrentLap > sRacer[i_index].iCurrentLap // racer j is a lap ahead of racer i
|
|
iRacerPosition[i_index]++
|
|
|
|
ELIF sRacer[j_index].iCurrentLap = sRacer[i_index].iCurrentLap // The racers are on the same lap so compare their checkpoint positions
|
|
|
|
IF sRacer[j_index].iCurrentPoint > sRacer[i_index].iCurrentPoint // racer j's checkpoint is further along than racer i's checkpoint
|
|
iRacerPosition[i_index]++
|
|
|
|
ELIF sRacer[j_index].iCurrentPoint = sRacer[i_index].iCurrentPoint // The racers's checkpoints are the same so compare their distances from it
|
|
|
|
fRacerIDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRacer[i_index].viCar), sTrackData.vCheckPoint[sRacer[i_index].iCurrentPoint])
|
|
fOtherDistFromCheckpoint = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRacer[j_index].viCar), sTrackData.vCheckPoint[sRacer[j_index].iCurrentPoint])
|
|
IF fOtherDistFromCheckpoint < fRacerIDistFromCheckpoint // racer j is closer to the checkpoint than racer i is
|
|
iRacerPosition[i_index]++
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
i_index = 0
|
|
REPEAT sTrackData.iNumAIRacers i_index
|
|
IF iRacerPosition[i_index] = (sRaceHUD.iPlayerPosition - 1)
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
CONTROL_VEHICLE_CHASE_HINT_CAM_ANY_MEANS(localChaseHintCamStruct, sRacer[i_index].viCar)
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
ELSE
|
|
KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
|
|
ENDIF
|
|
ENDPROC*/
|
|
|
|
FUNC BOOL HAS_PLAYER_COLLIDED_WITH_RACER()
|
|
INT i_index
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers-1
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
IF IS_ENTITY_TOUCHING_ENTITY(sPlayerVehicle.vehPlayerVehicle, sRacer[i_index].viCar)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDFOR
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
PROC INIT_STOPPED_SOUND()
|
|
iStoppedSound = GET_SOUND_ID()
|
|
iStoppedTimer = -1
|
|
ENDPROC
|
|
|
|
FUNC INT GET_CLOSEST_RACER()
|
|
INT i_index
|
|
FLOAT fDistance = 0
|
|
FLOAT fClosestDistance = 9999999999.9
|
|
INT iClosest
|
|
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers-1
|
|
IF IS_VEHICLE_OK(sRacer[i_index].viCar)
|
|
fDistance = GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRacer[i_index].viCar)
|
|
|
|
IF fDistance < fClosestDistance
|
|
fClosestDistance = fDistance
|
|
iClosest = i_index
|
|
ENDIF
|
|
ENDIF
|
|
ENDFOR
|
|
|
|
RETURN iClosest
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Plays dialogue if the player gains a position, loses a position or crashes
|
|
PROC CHECK_RACE_CONVS()
|
|
//IF GET_GAME_TIMER() > iPositionConvTimer AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
IF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_FRANKLIN
|
|
IF sRaceHUD.iPlayerPosition < iPreviousPosition
|
|
// Player has gained one or more positions
|
|
IF GET_GAME_TIMER() > iPositionConvTimer /*AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()*/ AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(PLAYER_PED_ID(), "RACE_RANKUP", "FRANKLIN_NORMAL", SPEECH_PARAMS_FORCE_SHOUTED_CLEAR)
|
|
CPRINTLN(DEBUG_MISSION, "Triggered Rankup line")
|
|
//IF CREATE_CONVERSATION(pedConvStruct, "SPR_CIT", "SPR_RANKUP", CONV_PRIORITY_MEDIUM)
|
|
iPreviousPosition = sRaceHUD.iPlayerPosition
|
|
iPositionConvTimer = GET_GAME_TIMER() + POSITION_CONV_TIME
|
|
//ENDIF
|
|
ELSE
|
|
iPreviousPosition = sRaceHUD.iPlayerPosition
|
|
ENDIF
|
|
ELIF sRaceHUD.iPlayerPosition > iPreviousPosition
|
|
// Player has lost one or more positions
|
|
IF GET_GAME_TIMER() > iPositionConvTimer /*AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()*/ AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(PLAYER_PED_ID(), "RACE_RANKDOWN", "FRANKLIN_NORMAL", SPEECH_PARAMS_FORCE_SHOUTED_CLEAR)
|
|
CPRINTLN(DEBUG_MISSION, "Triggered Rankdown line")
|
|
//IF CREATE_CONVERSATION(pedConvStruct, "SPR_CIT", "SPR_RANKDOWN", CONV_PRIORITY_MEDIUM)
|
|
iPreviousPosition = sRaceHUD.iPlayerPosition
|
|
iPositionConvTimer = GET_GAME_TIMER() + POSITION_CONV_TIME
|
|
//ENDIF
|
|
ELSE
|
|
iPreviousPosition = sRaceHUD.iPlayerPosition
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF /*sRaceData.eRaceType <> RACETYPE_SEA AND*/ IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
IF GET_GAME_TIMER() > iPositionConvTimer /*AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()*/ AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
//IF HAS_ENTITY_COLLIDED_WITH_ANYTHING(sPlayerVehicle.vehPlayerVehicle)
|
|
IF HAS_PLAYER_COLLIDED_WITH_RACER()
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(PLAYER_PED_ID(), "RACE_CRASH", "FRANKLIN_NORMAL", SPEECH_PARAMS_FORCE_SHOUTED_CLEAR)
|
|
CPRINTLN(DEBUG_MISSION, "Triggered Crash line")
|
|
//IF CREATE_CONVERSATION(pedConvStruct, "SPR_CIT", "SPR_CRASH", CONV_PRIORITY_MEDIUM)
|
|
iPositionConvTimer = GET_GAME_TIMER() + POSITION_CONV_TIME
|
|
//ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF sRaceData.eRaceType <> RACETYPE_SEA
|
|
IF IS_CHAR_ALMOST_STOPPED(PLAYER_PED_ID())
|
|
IF iStoppedTimer < 0
|
|
iStoppedTimer = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(2500, 5000)
|
|
ELIF GET_GAME_TIMER() > iStoppedTimer
|
|
PLAY_SOUND_FROM_ENTITY(iStoppedSound, "DISTANT_RACERS", sRacer[GET_CLOSEST_RACER()].viCar, "ROAD_RACE_SOUNDSET")
|
|
iStoppedTimer = -1
|
|
ENDIF
|
|
ELSE
|
|
IF iStoppedTimer > 0
|
|
iStoppedTimer = -1
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if it's a valid condition to create the end scene
|
|
/// RETURNS:
|
|
/// TRUE if it's OK to create the end scene
|
|
FUNC BOOL END_SCENE_IS_VALID()
|
|
IF sRaceHUD.iPlayerPosition = 1
|
|
IF sRaceData.eRaceTrack = STREET_RACE_01
|
|
OR sRaceData.eRaceTrack = STREET_RACE_02
|
|
OR sRaceData.eRaceTrack = STREET_RACE_04
|
|
OR sRaceData.eRaceTrack = STREET_RACE_05
|
|
OR sRaceData.eRaceTrack = STREET_RACE_06
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Puts the player's car in the correct position and gives them their reward for winning the race
|
|
PROC SETUP_END_SCENE(VEHICLE_INDEX viPlayer)
|
|
IF END_SCENE_IS_VALID()
|
|
IF NOT IS_PED_UNINJURED(piRewardPed)
|
|
IF HAS_MODEL_LOADED(A_F_Y_Genhot_01)
|
|
// Commenting out for now in case this is needed again
|
|
//bDeleteSecondPlace = TRUE
|
|
//IF sRaceHUD.iPlayerPosition = 1
|
|
// Player has won the race, give them a reward
|
|
/*IF sRaceData.eRaceType = RACETYPE_SEA
|
|
// sea race, give them double their money back
|
|
CREDIT_BANK_ACCOUNT(CHAR_FRANKLIN, BAAC_UNLOGGED_SMALL_ACTION, (sRaceData.iRaceFee * 2))
|
|
ELSE
|
|
// Car race, refund their money and give them the number two driver's car
|
|
CREDIT_BANK_ACCOUNT(CHAR_FRANKLIN, BAAC_UNLOGGED_SMALL_ACTION, sRaceData.iRaceFee)
|
|
|
|
iSecondPlaceID = GET_SECOND_PLACE_CAR()
|
|
IF iSecondPlaceID > -1 AND IS_VEHICLE_OK(sRacer[iSecondPlaceID].viCar)
|
|
SET_VEHICLE_FIXED(sRacer[iSecondPlaceID].viCar)
|
|
SET_VEHICLE_FORWARD_SPEED(sRacer[iSecondPlaceID].viCar, 0.0)
|
|
SET_ENTITY_COORDS(sRacer[iSecondPlaceID].viCar, sTrackData.vRewardVehicleSpawnPoint)
|
|
SET_ENTITY_HEADING(sRacer[iSecondPlaceID].viCar, sTrackData.fRewardVehicleHeading)
|
|
SET_VEHICLE_IS_CONSIDERED_BY_PLAYER(sRacer[iSecondPlaceID].viCar, TRUE)
|
|
SAFE_DELETE_PED(sRacer[iSecondPlaceID].piDriver)
|
|
ADD_HELP_TO_FLOW_QUEUE("STREET_WIN", FHP_HIGH)
|
|
bDeleteSecondPlace = FALSE
|
|
ENDIF
|
|
ENDIF*/
|
|
|
|
// Place the player's car in the winning position for the end of race scene
|
|
/*IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_VEHICLE_FORWARD_SPEED(sPlayerVehicle.vehPlayerVehicle, 0.0)
|
|
SET_ENTITY_COORDS(sPlayerVehicle.vehPlayerVehicle, vWinningCarPos)
|
|
SET_ENTITY_HEADING(sPlayerVehicle.vehPlayerVehicle, fWinningCarHeading)
|
|
ENDIF*/
|
|
IF IS_VEHICLE_OK(viPlayer)
|
|
CLEAR_PED_TASKS(PLAYER_PED_ID())
|
|
SET_VEHICLE_FORWARD_SPEED(viPlayer, 0.0)
|
|
SET_ENTITY_COORDS(viPlayer, vWinningCarPos)
|
|
SET_ENTITY_HEADING(viPlayer, fWinningCarHeading)
|
|
ENDIF
|
|
// Commenting out for now in case this is needed again
|
|
/*ELIF sRaceData.eRaceType <> RACETYPE_SEA
|
|
// Place the winning car in the winning position and the player's car in the alternative position
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle)
|
|
SET_VEHICLE_FORWARD_SPEED(sPlayerVehicle.vehPlayerVehicle, 0.0)
|
|
SET_ENTITY_COORDS(sPlayerVehicle.vehPlayerVehicle, vAltCarPos)
|
|
SET_ENTITY_HEADING(sPlayerVehicle.vehPlayerVehicle, fAltCarHeading)
|
|
ENDIF
|
|
|
|
iSecondPlaceID = GET_SECOND_PLACE_CAR() // This function returns the leading AI car, if the player didn't win, this car did
|
|
IF iSecondPlaceID > -1 AND IS_VEHICLE_OK(sRacer[iSecondPlaceID].viCar) AND IS_PED_UNINJURED(sRacer[iSecondPlaceID].piDriver)
|
|
SET_VEHICLE_FIXED(sRacer[iSecondPlaceID].viCar)
|
|
SET_VEHICLE_FORWARD_SPEED(sRacer[iSecondPlaceID].viCar, 0.0)
|
|
SET_ENTITY_COORDS(sRacer[iSecondPlaceID].viCar, vWinningCarPos)
|
|
SET_ENTITY_HEADING(sRacer[iSecondPlaceID].viCar, fWinningCarHeading)
|
|
TASK_VEHICLE_TEMP_ACTION(sRacer[iSecondPlaceID].piDriver, sRacer[iSecondPlaceID].viCar, TEMPACT_WAIT, 99999999)
|
|
bDeleteSecondPlace = FALSE
|
|
ENDIF
|
|
ENDIF*/
|
|
|
|
CLEANUP_RACERS(TRUE)//, bDeleteSecondPlace)
|
|
|
|
// Create the reward giving ped
|
|
piRewardPed = CREATE_PED(PEDTYPE_CIVFEMALE, A_F_Y_Genhot_01, vRewardPedPos, fRewardPedHeading)
|
|
ADD_PED_FOR_DIALOGUE(pedConvStruct, 3, piRewardPed, "StrRaceGirl", TRUE)
|
|
STOP_PED_SPEAKING(piRewardPed, TRUE)
|
|
SET_MODEL_AS_NO_LONGER_NEEDED(A_F_Y_Genhot_01)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE: Updates AI racers
|
|
PROC UPDATE_RACE_AI(BOOL bAllowRacerSix = TRUE, BOOL bUsingHao = FALSE)
|
|
|
|
// Iterate through all racers
|
|
INT i_index
|
|
FOR i_index = 0 TO sTrackData.iNumAIRacers-1
|
|
UPDATE_RACER(i_index, bAllowRacerSix, bUsingHao)
|
|
ENDFOR
|
|
|
|
ADD_CLOSEST_RACER_TO_MIX()
|
|
ENDPROC
|
|
|
|
PROC HANDLE_START_BOOST()
|
|
SWITCH eBoostState
|
|
CASE BS_READY
|
|
IF iBoostTimer > 0
|
|
IF GET_GAME_TIMER() < iBoostTimer
|
|
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_VEH_ACCELERATE)
|
|
CPRINTLN(DEBUG_MISSION,"Player triggered boost")
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle) AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
IF IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle))
|
|
SET_VEHICLE_BOOST_ACTIVE(sPlayerVehicle.vehPlayerVehicle, TRUE)
|
|
ENDIF
|
|
ANIMPOSTFX_PLAY("RaceTurbo", 0, FALSE)
|
|
iBoostTimer = GET_GAME_TIMER() + BOOST_TIME
|
|
eBoostState = BS_ACTIVE
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_MISSION,"Boost window timed out")
|
|
eBoostState = BS_FINISHED
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE BS_ACTIVE
|
|
IF GET_GAME_TIMER() > iBoostTimer
|
|
CPRINTLN(DEBUG_MISSION,"Boost finished")
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle) AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
IF IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle))
|
|
SET_VEHICLE_BOOST_ACTIVE(sPlayerVehicle.vehPlayerVehicle, FALSE)
|
|
ENDIF
|
|
eBoostState = BS_FINISHED
|
|
ENDIF
|
|
ELSE
|
|
IF IS_VEHICLE_OK(sPlayerVehicle.vehPlayerVehicle) AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), sPlayerVehicle.vehPlayerVehicle)
|
|
APPLY_FORCE_TO_ENTITY(sPlayerVehicle.vehPlayerVehicle, APPLY_TYPE_FORCE, <<0.0, 25.0, 0.0>>, <<0.0, 0.0, 0.0>>, 0, TRUE, TRUE, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|