//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 <> 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 <> CASE 6 RETURN <<-FMMC_CHECKPOINT_SIZE/2,-FMMC_CHECKPOINT_SIZE/2,1>> CASE 7 RETURN <> 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