Files
2025-09-29 00:52:08 +02:00

2516 lines
81 KiB
Python
Executable File

// Includes
USING "rage_builtins.sch"
USING "globals.sch"
USING "brains.sch"
USING "common_Races.sch"
USING "flow_public_core.sch"
USING "commands_script.sch"
USING "commands_misc.sch"
USING "flow_help_public.sch"
USING "menu_public.sch"
USING "rc_launcher_public.sch"
USING "PM_MissionCreator_Public.sch"
USING "load_queue_public.sch"
#IF IS_DEBUG_BUILD
USING "COMMANDS_DEBUG.sch"
USING "debug_Races.sch"
#ENDIF
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : launcher_Racing.sc
// AUTHOR : David Roberts
// DESCRIPTION : Launcher script for the ambient street and sea races
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
// Enums
ENUM RACE_LAUNCHER_STATE
STATE_INACTIVE,
STATE_WAIT_FOR_TRIGGER,
STATE_RACE_MENU,
STATE_LAUNCH_RACE
ENDENUM
ENUM CHALLENGER_GREETING_STATE
CGS_INIT = 0,
CGS_FACING_PLAYER,
CGS_FACING_PLAYER_WAIT,
CGS_CHALLENGING_PLAYER,
CGS_GREETING_PLAYER,
CGS_GREETING_PLAYER_WAIT
ENDENUM
ENUM RACE_MENU_STATE
MENU_INIT,
MENU_UPDATE,
MENU_CLEANUP
ENDENUM
ENUM RACE_VEHICLE_TYPE
RVT_OK,
RVT_COP,
RVT_NOT_SUITABLE
ENDENUM
// Constants
CONST_FLOAT WORLD_POINT_COORD_TOLERANCE 1.0 // Used to obtain race location
CONST_INT ACTIVATION_RANGE 20 // Context interaction range
CONST_INT VEHICLE_DAMAGE_LIMIT 200 // Minimum amount of health allowed for vehicle
CONST_INT CROWD_SIZE 7 // Maximum number of crowd peds
CONST_INT LINEUP_SIZE 3
// Launcher info
RACE_LAUNCHER_STATE eState // Launcher state
RACE_DATA raceData // Race information
VECTOR vInCoords // World point coord
BOOL bDisplayHelp // Manages help text
BOOL bHintCamReady = TRUE // Manages hint cam
BOOL bCreatedAreaBlocks = FALSE // Remember when we've created pathing blocks so we can clean them up.
// Use a timer to ensure that help text isn't cleared before it's been onscreen for at least a second
INT iHelpTextTimer
CONST_INT MIN_HELP_TEXT_TIME 1000
// Race menu
RACE_MENU_STATE eRaceMenu // Menu state
INT iCurrentMenuItem
INT iMenuInputTimer
BOOL bLaunchRace
BOOL bPlayOnline
BOOL bRadioSwitchDisabled
//BOOL bAnchored = FALSE
BOOL bStartPedSixTurning = TRUE
// Race initial scene
PED_INDEX piCrowd[CROWD_SIZE] // Crowd ped info
VEHICLE_INDEX viCar
PED_INDEX piDriver
VECTOR vCarPos
FLOAT fCarFoc
VEHICLE_INDEX viCar2
VECTOR vCarPos2
FLOAT fCarFoc2
VECTOR vLineupPos[LINEUP_SIZE]
FLOAT fLineupFoc[LINEUP_SIZE]
VECTOR offset_pos[CROWD_SIZE]
FLOAT offset_heading[CROWD_SIZE]
VEHICLE_INDEX viLineup[LINEUP_SIZE]
PED_INDEX piLineup[LINEUP_SIZE]
// Crowd setup
MODEL_NAMES ePedModel[CROWD_SIZE]
MODEL_NAMES eCarModel
MODEL_NAMES eCarModel2 = FELTZER2
STRING sAnimDict
STRING sAnimName[CROWD_SIZE]
BOOL bReleaseModels = TRUE
/*INT iSyncedSceneOne
INT iSyncedSceneTwo*/
BOOL bTriggeredMenu = FALSE
CHALLENGER_GREETING_STATE eChallengerState = CGS_INIT
BOOL bSaidSecondSpeech = FALSE
BOOL bSaidThirdSpeech = FALSE
structTimer greetTimer
// The min and max coordinates used to turn off ped paths around the start of the race
VECTOR vMinRaceArea = <<0,0,0>>
VECTOR vMaxRaceArea = <<1,1,1>>
// Disable road nodes near the race start
VECTOR vRaceRoadPos1 = <<0,0,0>>
VECTOR vRaceRoadPos2 = <<0,0,0>>
FLOAT fRaceRoadWidth = 0
SCENARIO_BLOCKING_INDEX sbiRaceStart
SCENARIO_BLOCKING_INDEX sbiStreetRaceTwo
LoadQueueMedium sLoadQueue
// ===========================================================================================================
// Helper functions
// ===========================================================================================================
/// PURPOSE:
/// Preloads or releases vehicle models needed for the AI races
/// PARAMS:
/// bRequest - Requests the models if this is true, releases them if it's false
PROC REQUEST_RIVAL_MODELS(BOOL bRequest = TRUE)
IF bRequest
// Set vehicle models
SWITCH raceData.eRaceTrack
CASE STREET_RACE_01 // South Los Santos
CASE STREET_RACE_02 // City Circuit
CASE STREET_RACE_04 // Airport
CASE STREET_RACE_05 // Freeway
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, BANSHEE)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, FELTZER2)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, SENTINEL)
// REQUEST_MODEL(BANSHEE)
// REQUEST_MODEL(FELTZER2)
// REQUEST_MODEL(SENTINEL)
BREAK
CASE STREET_RACE_06 // Vespucci Canals
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, BATI)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, RUFFIAN)
// REQUEST_MODEL(BATI)
// REQUEST_MODEL(RUFFIAN)
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
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, SEASHARK)
// REQUEST_MODEL(SEASHARK)
BREAK
ENDSWITCH
ELSE
SET_LOAD_QUEUE_MEDIUM_AS_NO_LONGER_NEEDED(sLoadQueue)
// Release vehicle models
// SWITCH raceData.eRaceTrack
// CASE STREET_RACE_01 // South Los Santos
// CASE STREET_RACE_02 // City Circuit
// CASE STREET_RACE_04 // Airport
// CASE STREET_RACE_05 // Freeway
// SET_MODEL_AS_NO_LONGER_NEEDED(BANSHEE)
// SET_MODEL_AS_NO_LONGER_NEEDED(FELTZER2)
// SET_MODEL_AS_NO_LONGER_NEEDED(SENTINEL)
// BREAK
// CASE STREET_RACE_06 // Vespucci Canals
// SET_MODEL_AS_NO_LONGER_NEEDED(BATI)
// SET_MODEL_AS_NO_LONGER_NEEDED(RUFFIAN)
// 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
// SET_MODEL_AS_NO_LONGER_NEEDED(SEASHARK)
// BREAK
// ENDSWITCH
ENDIF
ENDPROC
// ===========================================================================================================
// Launcher cleanup
// ===========================================================================================================
PROC SCRIPT_CLEANUP(BOOL bStartedRace = TRUE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: SCRIPT CLEANUP")
// Remove debug widget
#IF IS_DEBUG_BUILD
CLEANUP_RACE_WIDGET()
IF g_RaceLaunchedFromDebug = TRUE
CPRINTLN(DEBUG_MISSION, "Race Launcher Cleanup: Triggered from debug menu")
g_RaceLaunchedFromDebug = FALSE
ENDIF
#ENDIF
// Remove the initial scene peds
IF NOT bHintCamReady
STOP_GAMEPLAY_HINT()
bHintCamReady = TRUE
ENDIF
INT iIndex = 0
REPEAT CROWD_SIZE iIndex
IF IS_ENTITY_ALIVE(piCrowd[iIndex])
CLEAR_PED_TASKS(piCrowd[iIndex])
TASK_WANDER_STANDARD(piCrowd[iIndex])
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piCrowd[iIndex], FALSE)
SET_PED_AS_NO_LONGER_NEEDED(piCrowd[iIndex])
ENDIF
ENDREPEAT
iIndex = 0
REPEAT LINEUP_SIZE iIndex
IF IS_ENTITY_ALIVE(piLineup[iIndex])
IF IS_ENTITY_ALIVE(viLineup[iIndex])
CLEAR_PED_TASKS(piLineup[iIndex])
IF IS_THIS_MODEL_A_BOAT(GET_ENTITY_MODEL(viLineup[iIndex]))
SET_BOAT_ANCHOR(viLineup[iIndex], FALSE)
ENDIF
TASK_VEHICLE_DRIVE_WANDER(piLineup[iIndex],viLineup[iIndex],20,DRIVINGMODE_AVOIDCARS_STOPFORPEDS_OBEYLIGHTS)
SET_PED_KEEP_TASK(piLineup[iIndex],TRUE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piLineup[iIndex], FALSE)
SET_PED_AS_NO_LONGER_NEEDED(piLineup[iIndex])
SET_VEHICLE_AS_NO_LONGER_NEEDED(viLineup[iIndex])
ENDIF
ENDIF
ENDREPEAT
IF IS_ENTITY_ALIVE(piDriver)
IF IS_ENTITY_ALIVE(viCar)
CLEAR_PED_TASKS(piDriver)
SET_PED_COMBAT_ATTRIBUTES(piDriver, CA_USE_VEHICLE,True)
TASK_VEHICLE_DRIVE_WANDER(piDriver, viCar,15,DRIVINGMODE_AVOIDCARS_STOPFORPEDS_OBEYLIGHTS)
SET_PED_KEEP_TASK(piDriver,TRUE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piDriver, FALSE)
SET_PED_AS_NO_LONGER_NEEDED(piDriver)
SET_VEHICLE_AS_NO_LONGER_NEEDED(viCar)
ENDIF
ENDIF
IF IS_ENTITY_ALIVE(viCar2)
SET_VEHICLE_AS_NO_LONGER_NEEDED(viCar2)
ENDIF
// Cleanup blips
SWITCH raceData.eRaceTrack
// Sea Races
CASE SEA_RACE_01
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_SEA_RACE1, FALSE)
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_EAST))
BREAK
CASE SEA_RACE_02
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_SEA_RACE2, FALSE)
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_NORTH))
BREAK
CASE SEA_RACE_03
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_SEA_RACE3, FALSE)
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_CANYON))
BREAK
CASE SEA_RACE_04
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_SEA_RACE4, FALSE)
SET_BIT(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_CITY))
BREAK
// Street Races
CASE STREET_RACE_01
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_STREET_RACE1, FALSE)
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_LOS_SANTOS))
BREAK
CASE STREET_RACE_02
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_STREET_RACE2, FALSE)
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
BREAK
CASE STREET_RACE_04
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_STREET_RACE4, FALSE)
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_AIRPORT))
BREAK
CASE STREET_RACE_05
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_STREET_RACE5, FALSE)
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_FREEWAY))
BREAK
CASE STREET_RACE_06
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_STREET_RACE6, FALSE)
SET_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_VESPUCCI_CANALS))
BREAK
ENDSWITCH
// Clear help text
IF bDisplayHelp
CLEAR_HELP()
ENDIF
SET_RADIO_STATION_MUSIC_ONLY(GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)), FALSE)
// Script has terminated with flow help disabled
IF bRadioSwitchDisabled
// Ensure player can use radio
SET_USER_RADIO_CONTROL_ENABLED(TRUE)
ENDIF
IF bTriggeredMenu AND NOT bStartedRace
PLAYER_INDEX piPlayer = GET_PLAYER_INDEX()
IF IS_PLAYER_PLAYING(piPlayer)
IF NOT IS_PLAYER_CONTROL_ON(piPlayer)
SET_PLAYER_CONTROL(piPlayer, TRUE)
ENDIF
ENDIF
ENDIF
IF NOT bStartedRace
REQUEST_RIVAL_MODELS(FALSE)
ENDIF
// Restore ped paths
IF bCreatedAreaBlocks
SET_PED_PATHS_BACK_TO_ORIGINAL(vMinRaceArea, vMaxRaceArea, TRUE)
SET_ROADS_BACK_TO_ORIGINAL_IN_ANGLED_AREA(vRaceRoadPos1, vRaceRoadPos2, fRaceRoadWidth)
bCreatedAreaBlocks = FALSE
ENDIF
// Turn off parking scenarios
SET_SCENARIO_TYPE_ENABLED("WORLD_VEHICLE_PARK_PERPENDICULAR_NOSE_IN", TRUE)
SET_SCENARIO_TYPE_ENABLED("WORLD_VEHICLE_PARK_PARALLEL", TRUE)
IF raceData.eRaceTrack = STREET_RACE_02
REMOVE_SCENARIO_BLOCKING_AREA(sbiStreetRaceTwo)
ENDIF
IF raceData.eRaceType = RACETYPE_BIKE OR raceData.eRaceType = RACETYPE_CAR
REMOVE_SCENARIO_BLOCKING_AREA(sbiRaceStart)
ELSE
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_ForceDirectEntry, FALSE)
ENDIF
CLEANUP_LOAD_QUEUE_MEDIUM(sLoadQueue)
// Terminate script
TERMINATE_THIS_THREAD()
ENDPROC
// ===========================================================================================================
// Functions
// ===========================================================================================================
/// PURPOSE: Check if a specific race track has been unlocked yet.
FUNC BOOL IS_RACE_UNLOCKED(RACE_TRACK_ID paramRaceID)
SWITCH paramRaceID
CASE STREET_RACE_01
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_LOS_SANTOS))
BREAK
CASE STREET_RACE_02
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
BREAK
CASE STREET_RACE_04
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_AIRPORT))
BREAK
CASE STREET_RACE_05
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_FREEWAY))
BREAK
CASE STREET_RACE_06
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(STREET_RACE_VESPUCCI_CANALS))
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE: Clears help when the player goes out of activation range or has the cellphone up
PROC MANAGE_RACE_HELP()
// Help message was displayed..
IF bDisplayHelp AND GET_GAME_TIMER() > iHelpTextTimer
CLEAR_HELP()
bDisplayHelp = FALSE
ENDIF
ENDPROC
/// PURPOSE:
/// Checks if the player has threatened the launch scene peds in any way
/// RETURNS:
/// TRUE if the player has been threatening
FUNC BOOL PLAYER_THREATENED_LAUNCH_SCENE()
INT iIndex
// Make scene peds flee when the player is wanted
IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)
RETURN TRUE
ENDIF
// Sea races have more limited initial scenes
IF raceData.eRaceType = RACETYPE_SEA
FOR iIndex = 0 TO COUNT_OF(piLineup) - 1
IF DOES_ENTITY_EXIST(piLineup[iIndex])
IF IS_PED_INJURED(piLineup[iIndex])
RETURN TRUE
ELIF HAS_PLAYER_THREATENED_PED(piLineup[iIndex]) OR IS_PED_BEING_JACKED(piLineup[iIndex])
RETURN TRUE
ENDIF
ENDIF
IF DOES_ENTITY_EXIST(viLineup[iIndex])
IF IS_ENTITY_DEAD(viLineup[iIndex])
RETURN TRUE
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(viLineup[iIndex], PLAYER_PED_ID())
AND GET_ENTITY_HEALTH(viLineup[iIndex]) < 900
RETURN TRUE
ENDIF
ENDIF
ENDFOR
IF DOES_ENTITY_EXIST(viCar)
IF IS_ENTITY_DEAD(viCar)
RETURN TRUE
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(viCar, PLAYER_PED_ID())
AND GET_ENTITY_HEALTH(viCar) < 900
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDIF
IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(),vInCoords, 50) AND IS_PED_SHOOTING(PLAYER_PED_ID())
RETURN TRUE
ENDIF
IF DOES_ENTITY_EXIST(piDriver)
IF IS_PED_INJURED(piDriver)
RETURN TRUE
ELIF HAS_PLAYER_THREATENED_PED(piDriver)
RETURN TRUE
ELIF IS_PED_BEING_JACKED(piDriver)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piDriver, FALSE)
RETURN TRUE
ENDIF
ENDIF
IF DOES_ENTITY_EXIST(viCar)
IF IS_ENTITY_DEAD(viCar)
RETURN TRUE
ELIF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viCar, TRUE) OR HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(viCar, PLAYER_PED_ID())
RETURN TRUE
ENDIF
ENDIF
IF DOES_ENTITY_EXIST(viCar2)
IF IS_ENTITY_DEAD(viCar2)
RETURN TRUE
ELIF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viCar2, TRUE) OR HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(viCar2, PLAYER_PED_ID())
RETURN TRUE
ENDIF
ENDIF
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1
IF DOES_ENTITY_EXIST(piCrowd[iIndex])
IF IS_PED_INJURED(piCrowd[iIndex])
RETURN TRUE
ELIF HAS_PLAYER_THREATENED_PED(piCrowd[iIndex])
RETURN TRUE
ENDIF
ENDIF
ENDFOR
RETURN FALSE
ENDFUNC
/// PURPOSE: Can race be triggered at current time of day
FUNC BOOL IS_RACE_ALLOWED_FOR_TIME_OF_DAY()
// Sea Races currently not restricted by time
IF raceData.eRaceType = RACETYPE_SEA
RETURN TRUE
ELIF raceData.eRaceType = RACETYPE_BIKE OR raceData.eRaceType = RACETYPE_CAR
// Check current time of day
IF GET_CLOCK_HOURS() >= MIN_STREET_RACE_HOUR
OR GET_CLOCK_HOURS() < MAX_STREET_RACE_HOUR
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Checks if the leave area bit has been set for this race
/// RETURNS:
/// TRUE if the bit has been set
FUNC BOOL IS_LEAVE_AREA_BIT_SET()
SWITCH raceData.eRaceTrack
// Sea Races
CASE SEA_RACE_01
RETURN IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_EAST))
BREAK
CASE SEA_RACE_02
RETURN IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_NORTH))
BREAK
CASE SEA_RACE_03
RETURN IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_CANYON))
BREAK
CASE SEA_RACE_04
RETURN IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(SEA_RACE_CITY))
BREAK
// Street Races
CASE STREET_RACE_01
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_LOS_SANTOS))
BREAK
CASE STREET_RACE_02
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_CITY_CIRCUIT))
BREAK
CASE STREET_RACE_04
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_AIRPORT))
BREAK
CASE STREET_RACE_05
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_FREEWAY))
BREAK
CASE STREET_RACE_06
RETURN IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(STREET_RACE_VESPUCCI_CANALS))
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Check if there are any reasons why the races cannot be launced
/// RETURNS:
/// TRUE if no conditions to not launch were found
FUNC BOOL IS_RACE_ALLOWED_TO_LAUNCH()
IF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_MINIGAME)
CPRINTLN(DEBUG_MISSION, "Currently on minigame")
RETURN FALSE
ENDIF
IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY)
OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY_WITH_MG)
CPRINTLN(DEBUG_MISSION, "Currently on friend activity")
RETURN FALSE
ENDIF
IF g_bMissionOverStatTrigger
CPRINTLN(DEBUG_MISSION, "g_bMissionOverStatTrigger = TRUE")
RETURN FALSE
ENDIF
// Check if the player has to leave the area
IF IS_LEAVE_AREA_BIT_SET()
CPRINTLN(DEBUG_MISSION, "Leave area bit has been set")
RETURN FALSE
ENDIF
// Racing is only available for Franklin
IF (raceData.eRaceType <> RACETYPE_SEA) AND (GET_CURRENT_PLAYER_PED_ENUM() <> CHAR_FRANKLIN)
CPRINTLN(DEBUG_MISSION, "Player is not Franklin")
RETURN FALSE
ENDIF
IF IS_STUNT_JUMP_IN_PROGRESS()
CPRINTLN(DEBUG_MISSION, "Stunt jump in progress")
RETURN FALSE
ENDIF
// If the player isn't in the driver's seat they're either on the bus tour or getting a taxi ride so don't offer the race
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE()
IF IS_VEHICLE_OK(viPlayer) AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), viPlayer) AND NOT IS_PED_SITTING_IN_VEHICLE_SEAT(PLAYER_PED_ID(), viPlayer, VS_DRIVER)
AND GET_ENTITY_MODEL(viPlayer) <> TAXI
CPRINTLN(DEBUG_MISSION, "Player is on the tour bus")
RETURN FALSE
ENDIF
ENDIF
// Need to move race track over to use global enums
// Post-lockdown!
SWITCH raceData.eRaceTrack
// Street Races
CASE STREET_RACE_01
IF g_bStreetRaceTimeout[0]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE STREET_RACE_02
IF g_bStreetRaceTimeout[1]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE STREET_RACE_04
IF g_bStreetRaceTimeout[2]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE STREET_RACE_05
IF g_bStreetRaceTimeout[3]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE STREET_RACE_06
IF g_bStreetRaceTimeout[4]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
// Sea Races
CASE SEA_RACE_01
IF g_bSeaRaceTimeout[0]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE SEA_RACE_02
IF g_bSeaRaceTimeout[1]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE SEA_RACE_03
IF g_bSeaRaceTimeout[2]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
CASE SEA_RACE_04
IF g_bSeaRaceTimeout[3]
CPRINTLN(DEBUG_MISSION, "Race is currently timed out...")
RETURN FALSE
ENDIF
BREAK
ENDSWITCH
// Race has elapsed allowedtime
IF NOT IS_RACE_ALLOWED_FOR_TIME_OF_DAY()
CPRINTLN(DEBUG_MISSION, "Race is not allowed at this time of day")
INT iIndex
SEQUENCE_INDEX siWander
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1
IF IS_PED_UNINJURED(piCrowd[iIndex])
OPEN_SEQUENCE_TASK(siWander)
TASK_PAUSE(NULL, iIndex*100)
TASK_WANDER_STANDARD(NULL)
CLOSE_SEQUENCE_TASK(siWander)
TASK_PERFORM_SEQUENCE(piCrowd[iIndex], siWander)
ENDIF
ENDFOR
FOR iIndex = 0 TO COUNT_OF(piLineup) - 1
IF IS_PED_UNINJURED(piLineup[iIndex])
OPEN_SEQUENCE_TASK(siWander)
TASK_PAUSE(NULL, iIndex*110)
IF IS_VEHICLE_OK(viLineup[iIndex]) AND IS_PED_IN_VEHICLE(piLineup[iIndex], viLineup[iIndex])
TASK_VEHICLE_DRIVE_WANDER(NULL, viLineup[iIndex], 30, DRIVINGMODE_AVOIDCARS_OBEYLIGHTS)
ELSE
TASK_WANDER_STANDARD(NULL)
ENDIF
CLOSE_SEQUENCE_TASK(siWander)
TASK_PERFORM_SEQUENCE(piLineup[iIndex], siWander)
ENDIF
ENDFOR
IF IS_PED_UNINJURED(piDriver)
IF IS_VEHICLE_OK(viCar) AND IS_PED_IN_VEHICLE(piDriver, viCar)
TASK_VEHICLE_DRIVE_WANDER(piDriver, viCar, 30, DRIVINGMODE_AVOIDCARS_OBEYLIGHTS)
ELSE
TASK_WANDER_STANDARD(piDriver)
ENDIF
ENDIF
RETURN FALSE
ENDIF
// Don't offer the race if the player has been aggressive towards the launch scene peds
// Make launch scene peds flee in this case
IF PLAYER_THREATENED_LAUNCH_SCENE()
CPRINTLN(DEBUG_MISSION, "Player threatened the launch scene")
SEQUENCE_INDEX siLeave
INT iIndex
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1
IF IS_PED_UNINJURED(piCrowd[iIndex])
OPEN_SEQUENCE_TASK(siLeave)
TASK_PAUSE(NULL, iIndex*50)
TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 500, -1)
CLOSE_SEQUENCE_TASK(siLeave)
IF iIndex % 2 = 0
MAKE_PED_SCREAM(piCrowd[iIndex])
ENDIF
TASK_PERFORM_SEQUENCE(piCrowd[iIndex], siLeave)
ENDIF
ENDFOR
FOR iIndex = 0 TO COUNT_OF(piLineup) - 1
IF IS_VEHICLE_OK(viLineup[iIndex]) AND raceData.eRaceType = RACETYPE_SEA
SET_BOAT_ANCHOR(viLineup[iIndex], FALSE)
ENDIF
IF IS_PED_UNINJURED(piLineup[iIndex])
OPEN_SEQUENCE_TASK(siLeave)
TASK_PAUSE(NULL, iIndex*60)
IF IS_VEHICLE_OK(viLineup[iIndex]) AND IS_PED_IN_VEHICLE(piLineup[iIndex], viLineup[iIndex])
TASK_VEHICLE_DRIVE_WANDER(NULL, viLineup[iIndex], 50, DRIVINGMODE_AVOIDCARS_RECKLESS)
ELSE
TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 500, -1)
ENDIF
CLOSE_SEQUENCE_TASK(siLeave)
TASK_PERFORM_SEQUENCE(piLineup[iIndex], siLeave)
IF iIndex % 2 = 0
MAKE_PED_SCREAM(piLineup[iIndex])
ENDIF
ENDIF
ENDFOR
IF IS_VEHICLE_OK(viCar) AND raceData.eRaceType = RACETYPE_SEA
SET_BOAT_ANCHOR(viCar, FALSE)
ENDIF
IF IS_PED_UNINJURED(piDriver)
IF IS_VEHICLE_OK(viCar) AND IS_PED_IN_VEHICLE(piDriver, viCar)
TASK_VEHICLE_DRIVE_WANDER(piDriver, viCar, 50, DRIVINGMODE_AVOIDCARS_RECKLESS)
ELSE
TASK_SMART_FLEE_PED(piDriver, PLAYER_PED_ID(), 500, -1)
ENDIF
ENDIF
// Need to move race track over to use global enums
// Post-lockdown!
SWITCH raceData.eRaceTrack
// Street Races
CASE STREET_RACE_01
g_bStreetRaceTimeout[0] = TRUE
g_iStreetRaceCooldown[0] = GET_GAME_TIMER()
BREAK
CASE STREET_RACE_02
g_bStreetRaceTimeout[1] = TRUE
g_iStreetRaceCooldown[1] = GET_GAME_TIMER()
BREAK
CASE STREET_RACE_04
g_bStreetRaceTimeout[2] = TRUE
g_iStreetRaceCooldown[2] = GET_GAME_TIMER()
BREAK
CASE STREET_RACE_05
g_bStreetRaceTimeout[3] = TRUE
g_iStreetRaceCooldown[3] = GET_GAME_TIMER()
BREAK
CASE STREET_RACE_06
g_bStreetRaceTimeout[4] = TRUE
g_iStreetRaceCooldown[4] = GET_GAME_TIMER()
BREAK
// Sea Races
CASE SEA_RACE_01
g_bSeaRaceTimeout[0] = TRUE
g_iSeaRaceCooldown[0] = GET_GAME_TIMER()
BREAK
CASE SEA_RACE_02
g_bSeaRaceTimeout[1] = TRUE
g_iSeaRaceCooldown[1] = GET_GAME_TIMER()
BREAK
CASE SEA_RACE_03
g_bSeaRaceTimeout[2] = TRUE
g_iSeaRaceCooldown[2] = GET_GAME_TIMER()
BREAK
CASE SEA_RACE_04
g_bSeaRaceTimeout[3] = TRUE
g_iSeaRaceCooldown[3] = GET_GAME_TIMER()
BREAK
ENDSWITCH
CPRINTLN(DEBUG_MISSION, "Race timeout activated!")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE: Is the player within activation range of the race start point?
FUNC BOOL IS_PLAYER_IN_RACE_ACTIVATION_RANGE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
INT iActivationRange = ACTIVATION_RANGE
IF raceData.eRaceType = RACETYPE_SEA
iActivationRange = ACTIVATION_RANGE*2
ENDIF
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()),vInCoords) < iActivationRange
AND GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) = NULL // Kill this if the player enters a shop
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE: Is the player in a suitable race car
//FUNC BOOL IS_PLAYER_IN_SUITABLE_RACE_CAR()
FUNC RACE_VEHICLE_TYPE IS_PLAYER_IN_SUITABLE_RACE_CAR()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
// Get model name of player vehicle
MODEL_NAMES vehModel = GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle)
// General checks
IF IS_MODEL_POLICE_VEHICLE(vehModel)
RETURN RVT_COP
ENDIF
// these vehicles aren't covered by the IS_MODEL_POLICE_VEHICLE function
IF vehModel = POLICE4
OR vehModel = POLICEOLD1
OR vehModel = POLICEOLD2
OR vehModel = FBI
OR vehModel = FBI2
OR vehModel = LGUARD
OR vehModel = SHERIFF
OR vehModel = SHERIFF2
OR vehModel = PRANGER
OR vehModel = AMBULANCE
OR vehModel = FIRETRUK
RETURN RVT_COP
ENDIF
IF IS_THIS_MODEL_A_BIKE(vehModel)
OR IS_THIS_MODEL_A_BOAT(vehModel)
OR IS_THIS_MODEL_A_HELI(vehModel)
OR IS_THIS_MODEL_A_PLANE(vehModel)
RETURN RVT_NOT_SUITABLE
ENDIF
// Race blacklist
INT iIndex
MODEL_NAMES mBlacklist[83]
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] = BOXVILLE3
mBlacklist[17] = ANNIHILATOR
mBlacklist[18] = DINGHY
mBlacklist[19] = DUMMY_MODEL_FOR_SCRIPT
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] = DUMMY_MODEL_FOR_SCRIPT
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] = DUMMY_MODEL_FOR_SCRIPT
mBlacklist[81] = BLIMP
mBlacklist[82] = BLIMP2
REPEAT COUNT_OF(mBlacklist) iIndex
IF vehModel = mBlacklist[iIndex]
//RETURN FALSE
RETURN RVT_NOT_SUITABLE
ENDIF
ENDREPEAT
ENDIF
ENDIF
//RETURN TRUE
RETURN RVT_OK
ENDFUNC
/// PURPOSE: Is the player in a vehicle and in the air
FUNC BOOL IS_PLAYER_AIRBORNE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
// Is the player in a vehicle
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
// Get vehicle index
VEHICLE_INDEX viVehicle = GET_VEHICLE_PED_IS_USING(PLAYER_PED_ID())
// Are we in the air?
IF IS_ENTITY_ALIVE(viVehicle)
IF IS_ENTITY_IN_AIR(viVehicle)
IF raceData.eRaceType = RACETYPE_SEA AND IS_ENTITY_IN_WATER(viVehicle)
RETURN FALSE
ENDIF
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE: Is the player on a motorbike (not bicycle or quad bike)
FUNC RACE_VEHICLE_TYPE IS_PLAYER_ON_SUITABLE_RACE_BIKE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
MODEL_NAMES model = GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle)
IF model = POLICEB
RETURN RVT_COP
ENDIF
IF IS_THIS_MODEL_A_BIKE(model)
AND NOT IS_THIS_MODEL_A_BICYCLE(model)
RETURN RVT_OK
ENDIF
ENDIF
ENDIF
RETURN RVT_NOT_SUITABLE
ENDFUNC
/// PURPOSE: Is the player in a race suitable sea vehicle
FUNC BOOL IS_PLAYER_IN_SUITABLE_SEA_VEHICLE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF DOES_ENTITY_EXIST(sPlayerVehicle.vehPlayerVehicle)
MODEL_NAMES model = GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle)
IF model = SEASHARK
OR model = SEASHARK2
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE: Checks valid vehicle for car or bike race
FUNC BOOL IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_RACE()
RACE_VEHICLE_TYPE rvtCheck
SWITCH raceData.eRaceType
CASE RACETYPE_BIKE
rvtCheck = IS_PLAYER_ON_SUITABLE_RACE_BIKE()
IF rvtCheck = RVT_COP
// "Can't enter a street race in an emergency vehicle."
DISPLAY_RACE_HELP("STREET_NA_COP")
RETURN FALSE
ELIF rvtCheck = RVT_NOT_SUITABLE
// "You need a motorbike in order to enter this Street Race."
DISPLAY_RACE_HELP("STREET_NA_BIKE")
RETURN FALSE
ENDIF
BREAK
CASE RACETYPE_CAR
rvtCheck = IS_PLAYER_IN_SUITABLE_RACE_CAR()
IF rvtCheck = RVT_COP
// "Can't enter a street race in an emergency vehicle."
DISPLAY_RACE_HELP("STREET_NA_COP")
RETURN FALSE
ELIF rvtCheck = RVT_NOT_SUITABLE
// "You need a car in order to enter this Street Race."
DISPLAY_RACE_HELP("STREET_NA_CAR")
RETURN FALSE
ENDIF
BREAK
CASE RACETYPE_SEA
IF NOT IS_PLAYER_IN_SUITABLE_SEA_VEHICLE()
// "You need a suitable vehicle in order to enter this Sea Race."
STRING sSeaMsg
IF IS_VEHICLE_OK(viCar)
sSeaMsg = "SEA_NA_VEH"
ELSE
sSeaMsg = "SEA_NA_VEH2"
ENDIF
DISPLAY_RACE_HELP(sSeaMsg)
RETURN FALSE
ENDIF
BREAK
ENDSWITCH
RETURN TRUE
ENDFUNC
FUNC BOOL PLAYERS_TYRES_BURST()
MODEL_NAMES vehModel = GET_ENTITY_MODEL(sPlayerVehicle.vehPlayerVehicle)
IF IS_THIS_MODEL_A_BIKE(vehModel)
IF IS_VEHICLE_TYRE_BURST(sPlayerVehicle.vehPlayerVehicle, SC_WHEEL_BIKE_FRONT)
OR IS_VEHICLE_TYRE_BURST(sPlayerVehicle.vehPlayerVehicle, SC_WHEEL_BIKE_REAR)
RETURN TRUE
ENDIF
ELIF IS_THIS_MODEL_A_CAR(vehModel)
IF IS_VEHICLE_TYRE_BURST(sPlayerVehicle.vehPlayerVehicle, SC_WHEEL_CAR_FRONT_LEFT)
OR IS_VEHICLE_TYRE_BURST(sPlayerVehicle.vehPlayerVehicle, SC_WHEEL_CAR_FRONT_RIGHT)
OR IS_VEHICLE_TYRE_BURST(sPlayerVehicle.vehPlayerVehicle, SC_WHEEL_CAR_REAR_LEFT)
OR IS_VEHICLE_TYRE_BURST(sPlayerVehicle.vehPlayerVehicle, SC_WHEEL_CAR_REAR_RIGHT)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC DISPLAY_NEED_VEHICLE_HELP()
IF raceData.eRaceType = RACETYPE_SEA
// "You need a suitable vehicle in order to enter this Sea Race"
STRING sSeaMsg
IF IS_VEHICLE_OK(viCar)
sSeaMsg = "SEA_NA_VEH"
ELSE
sSeaMsg = "SEA_NA_VEH2"
ENDIF
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED(sSeaMsg)
PRINT_HELP_FOREVER(sSeaMsg)
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER() + MIN_HELP_TEXT_TIME
ENDIF
ELIF raceData.eRaceType = RACETYPE_BIKE
// "A motorbike is needed to enter this street race
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("STREET_NA_BIKE")
PRINT_HELP_FOREVER("STREET_NA_BIKE")
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER() + MIN_HELP_TEXT_TIME
ENDIF
ELSE
// "You need a car in order to enter this Street Race."
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("STREET_NA_CAR")
PRINT_HELP_FOREVER("STREET_NA_CAR")
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER() + MIN_HELP_TEXT_TIME
ENDIF
ENDIF
ENDPROC
/// PURPOSE: Checks global flags to see whether race script can be launched
FUNC BOOL CAN_PLAYER_LAUNCH_RACE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
// Is the player airborne in a vehicle?
IF IS_PLAYER_AIRBORNE()
RETURN FALSE
ENDIF
// Check for race entry fee
IF GET_TOTAL_CASH(GET_CURRENT_PLAYER_PED_ENUM()) < raceData.iRaceFee
IF raceData.eRaceType = RACETYPE_SEA
// "You can't afford to enter this Sea Race. You need $ in order to participate in this race."
DISPLAY_RACE_HELP_WITH_NUMBER("SEA_NA_CASH", raceData.iRaceFee)
ELSE
// "You can't afford to enter this Street Race...
DISPLAY_RACE_HELP_WITH_NUMBER("STREET_NA_CASH", raceData.iRaceFee)
ENDIF
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER() + MIN_HELP_TEXT_TIME
RETURN FALSE
ENDIF
// Is the player in a vehicle
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
// Get vehicle index
SAFE_RELEASE_VEHICLE(sPlayerVehicle.vehPlayerVehicle)
sPlayerVehicle.vehPlayerVehicle = GET_VEHICLE_PED_IS_USING(PLAYER_PED_ID())
// Check for correct type of vehicle
IF NOT IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_RACE()
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER() + MIN_HELP_TEXT_TIME
RETURN FALSE
ELIF ((GET_ENTITY_HEALTH(sPlayerVehicle.vehPlayerVehicle) <= VEHICLE_DAMAGE_LIMIT) OR IS_ENTITY_ON_FIRE(sPlayerVehicle.vehPlayerVehicle))
OR PLAYERS_TYRES_BURST()
// "Your vehicle is too damaged to race."
DISPLAY_RACE_HELP("RACE_VehDmg")
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER() + MIN_HELP_TEXT_TIME
RETURN FALSE
ELIF GET_PED_IN_VEHICLE_SEAT(sPlayerVehicle.vehPlayerVehicle, VS_DRIVER) <> PLAYER_PED_ID()
// Player has taken a taxi ride to the race start
DISPLAY_NEED_VEHICLE_HELP()
RETURN FALSE
ELSE
// Races cannot be triggered when phone is onscreen
IF IS_PHONE_ONSCREEN()
OR GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("appInternet")) > 0
MANAGE_RACE_HELP()
RETURN FALSE
ENDIF
// Otherwise we are ok to launch..
SWITCH raceData.eRaceType
CASE RACETYPE_BIKE DISPLAY_RACE_HELP_WITH_NUMBER("STREET_PLAY_B", raceData.iRaceFee) BREAK
CASE RACETYPE_CAR DISPLAY_RACE_HELP_WITH_NUMBER("STREET_PLAY_C", raceData.iRaceFee) BREAK
CASE RACETYPE_SEA DISPLAY_RACE_HELP("SEA_PLAY") BREAK
ENDSWITCH
bDisplayHelp = TRUE
iHelpTextTimer = GET_GAME_TIMER()
RETURN TRUE
ENDIF
ELSE
SAFE_RELEASE_VEHICLE(sPlayerVehicle.vehPlayerVehicle)
DISPLAY_NEED_VEHICLE_HELP()
RETURN FALSE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE: Requests candidate ID and asks permission to launch script
FUNC BOOL RACE_REQUEST_PERMISSION_TO_RUN()
// Get mission candidate ID
m_enumMissionCandidateReturnValue allowLaunch = Request_Mission_Launch(raceData.iCandidateID, MCTID_MUST_LAUNCH, MISSION_TYPE_MINIGAME)
#IF IS_DEBUG_BUILD
IF (allowLaunch = MCRET_DENIED)
PRINTLN("DENIED - Another mission must have launched, Street Race should terminate...")
ENDIF
IF (allowLaunch = MCRET_PROCESSING)
PRINTLN("PROCESSING - Race should keep trying...")
ENDIF
IF (allowLaunch = MCRET_ACCEPTED)
PRINTLN("ACCEPTED - Race must run because it now has control of the IS_CURRENTLY_ON_MISSION_TO_TYPE() flag...")
ENDIF
#ENDIF
IF NOT (allowLaunch = MCRET_ACCEPTED)
// DENIED or still PROCESSING.
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE: Launch race script
PROC SAFE_REQUEST_AND_LAUNCH_RACE()
// Request and load race script
CPRINTLN(DEBUG_MISSION, "Race Launcher: Requesting mission race script...")
IF NOT IS_REPEAT_PLAY_ACTIVE()
REQUEST_SCRIPT("mission_Race")
WHILE NOT HAS_SCRIPT_LOADED("mission_Race")
REQUEST_SCRIPT("mission_Race")
WAIT(0)
ENDWHILE
// Start script and terminate launcher
CPRINTLN(DEBUG_MISSION, "Race Launcher: Starting mission race script...")
START_NEW_SCRIPT_WITH_ARGS("mission_Race", raceData, SIZE_OF(raceData), MISSION_STACK_SIZE)
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Skipped launching mission race script as a repeat play was activated.")
ENDIF
SET_SCRIPT_AS_NO_LONGER_NEEDED("mission_Race")
SCRIPT_CLEANUP()
ENDPROC
/// PURPOSE:
/// Launches a single player instance of the race
PROC DO_RACE_LAUNCH_SP()
CPRINTLN(DEBUG_MISSION, "Race Launcher: DO_RACE_LAUNCH_SP")
// Reset candidate ID
raceData.iCandidateID = NO_CANDIDATE_ID
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF NOT IS_PED_WEARING_HELMET(PLAYER_PED_ID())
SET_PED_HELMET(PLAYER_PED_ID(), FALSE)
ENDIF
ENDIF
// Request permission to launch race
WHILE NOT RACE_REQUEST_PERMISSION_TO_RUN()
WAIT(0)
ENDWHILE
// Deduct race fee
IF raceData.eRaceType <> RACETYPE_SEA
DEBIT_BANK_ACCOUNT(GET_CURRENT_PLAYER_PED_ENUM(), BAAC_UNLOGGED_SMALL_ACTION, raceData.iRaceFee)
//WAIT(2000)
INT iWaitTime = GET_GAME_TIMER() + 1500
VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE()
IF IS_VEHICLE_OK(viPlayer)
WHILE NOT BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(viPlayer, 3.0, 2) // Reduce stopping distance to reduce chance of player hitting the initial scene peds B* 1510355
OR GET_GAME_TIMER() < iWaitTime
WAIT(0)
ENDWHILE
/*ELSE
WAIT(1500)*/
ENDIF
//WAIT(1500)
//ANIMPOSTFX_PLAY("SwitchSceneNeutral", 0, TRUE)
// Disable player control
PLAYER_INDEX pId = GET_PLAYER_INDEX()
IF IS_PLAYER_PLAYING(pId)
SET_PLAYER_CONTROL(pId, FALSE)
ENDIF
//WAIT(500)
/*iWaitTime = GET_GAME_TIMER() + 500
WHILE NOT BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(viPlayer, DEFAULT_VEH_STOPPING_DISTANCE, 2)
OR GET_GAME_TIMER() < iWaitTime
WAIT(0)
ENDWHILE*/
ENDIF
// Launch the race
SAFE_REQUEST_AND_LAUNCH_RACE()
ENDPROC
/// PURPOSE:
/// Notify systems that we want to launch a MP
PROC DO_RACE_LAUNCH_MP()
CPRINTLN(DEBUG_MISSION, "Race Launcher: DO_RACE_LAUNCH_MP")
// Call MP commands to launch FM
SET_PAUSE_MENU_WARP_FROM_MODE(GAMEMODE_SP)
SET_PAUSE_MENU_WARP_TO_MODE(GAMEMODE_FM)
SET_PAUSE_MENU_WARP_TO_VECTOR(vInCoords)
SET_PAUSE_MENU_REQUESTING_A_WARP()
// Setup globals
g_FMSP_Race_Data.bActive = TRUE
g_FMSP_Race_Data.iRaceID = ENUM_TO_INT(raceData.eRaceTrack)
g_FMSP_Race_Data.sUserID = GET_CLOUD_ID()
g_FMSP_Race_Data.sFilename = GET_RACE_FILENAME(raceData.eRaceTrack)
g_FMSP_Race_Data.vLocation = vInCoords
g_Private_ReturningFromActivitySession = TRUE
// Output MP globals
#IF IS_DEBUG_BUILD
OUTPUT_MP_GLOBALS_TO_TTY()
#ENDIF
SCRIPT_CLEANUP()
ENDPROC
/// PURPOSE: Determine which race is associated with this world point
PROC GET_RACE_LOCATION()
/************************************* STREET RACES **********************************/
// South Los Santos
IF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_STREET_RACE1), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: South Los Santos")
raceData.eRaceTrack = STREET_RACE_01
raceData.eRaceType = RACETYPE_CAR
raceData.iRaceFee = 100
raceData.iSaveSlot = 20
// City circuit
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_STREET_RACE2), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: City Circuit")
raceData.eRaceTrack = STREET_RACE_02
raceData.eRaceType = RACETYPE_CAR
raceData.iRaceFee = 500
raceData.iSaveSlot = 18
// Airport
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_STREET_RACE4), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Airport")
raceData.eRaceTrack = STREET_RACE_04
raceData.eRaceType = RACETYPE_CAR
raceData.iRaceFee = 1000
raceData.iSaveSlot = 2
// Freeway
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_STREET_RACE5), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Freeway")
raceData.eRaceTrack = STREET_RACE_05
raceData.eRaceType = RACETYPE_CAR
raceData.iRaceFee = 1250
raceData.iSaveSlot = 4
// Vespucci Canals
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_STREET_RACE6), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Vespucci Canals")
raceData.eRaceTrack = STREET_RACE_06
raceData.eRaceType = RACETYPE_BIKE
raceData.iRaceFee = 1500
raceData.iSaveSlot = 5
/************************************* SEA RACES **********************************/
// North Coast
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_SEA_RACE1), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: North Coast)")
raceData.eRaceTrack = SEA_RACE_01
raceData.eRaceType = RACETYPE_SEA
raceData.iRaceFee = 0
raceData.iSaveSlot = 16
// East Coast
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_SEA_RACE2), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: South Coast")
raceData.eRaceTrack = SEA_RACE_02
raceData.eRaceType = RACETYPE_SEA
raceData.iRaceFee = 0
raceData.iSaveSlot = 13
// Raton Canyon
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_SEA_RACE3), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Raton Canyon")
raceData.eRaceTrack = SEA_RACE_03
raceData.eRaceType = RACETYPE_SEA
raceData.iRaceFee = 0
raceData.iSaveSlot = 15
raceData.bP2P = TRUE
// Los Santos
ELIF ARE_VECTORS_ALMOST_EQUAL(GET_STATIC_BLIP_POSITION(STATIC_BLIP_MINIGAME_SEA_RACE4), vInCoords, WORLD_POINT_COORD_TOLERANCE)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Los Santos")
raceData.eRaceTrack = SEA_RACE_04
raceData.eRaceType = RACETYPE_SEA
raceData.iSaveSlot = 24
raceData.iRaceFee = 0
raceData.bP2P = TRUE
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: No Race Found")
SCRIPT_CLEANUP(FALSE)
ENDIF
ENDPROC
/// PURPOSE:
/// Checks if the initial scene should be created - if we're debug skipping here or the player is more than 100 metres away
/// RETURNS:
/// TRUE if we're OK to create the initial scene
FUNC BOOL ALLOW_INITIAL_SCENE()
IF NOT IS_RACE_ALLOWED_FOR_TIME_OF_DAY()
RETURN FALSE
ENDIF
#IF IS_DEBUG_BUILD
IF g_RaceLaunchedFromDebug = TRUE
RETURN TRUE
ENDIF
#ENDIF
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vCarPos, 100.0) OR IS_SCREEN_FADED_OUT()
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Sets up the values needed to create the initial scene
PROC SETUP_INITIAL_SCENE()
IF raceData.eRaceType = RACETYPE_BIKE
OR raceData.eRaceType = RACETYPE_CAR
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Is a car or bike race")
SWITCH raceData.eRaceTrack
// South Los Santos
CASE STREET_RACE_01
vCarPos = <<-158.67, -1555.16, 34.63>>
fCarFoc = 187.71
vCarPos2 = <<-155.15, -1550.83, 34.53>>
fCarFoc2 = 213.13
// min and max coords for the race area
vMinRaceArea = <<-68.878784,-1818.902710,24.553106>>
vMaxRaceArea = <<-56.009800,-1807.028687,27.854170>>
// Offsets
offset_pos[0] = <<-157.19, -1555.36, 35.07>>
offset_pos[1] = <<-157.04, -1557.57, 35.11>>
offset_pos[2] = <<-159.83, -1557.39, 34.96>>
offset_pos[3] = <<-156.64, -1551.96, 34.92>>
offset_pos[4] = <<-156.25, -1552.58, 34.93>>
offset_pos[5] = <<-153.23, -1553.05, 34.93>>
offset_pos[6] = <<-155.30, -1556.41, 35.13>>
offset_heading [0] = 101.91//16.54
offset_heading [1] = 38.48//-141.52
offset_heading [2] = -36.70
offset_heading [3] = -52.93
offset_heading [4] = -75.07
offset_heading [5] = 33.13
offset_heading [6] = -170.02
BREAK
// City Circuit
CASE STREET_RACE_02
vCarPos = <<368.72, 294.06, 102.96>>
fCarFoc = 25.17
vCarPos2 = <<373.71, 290.72, 102.89>>
fCarFoc2 = 33.24
// min and max coords for the race area
vMinRaceArea = <<-523.549683,262.298553,80.019905>>
vMaxRaceArea = <<-509.101349,272.478027,86.177132>>
// Offsets
offset_pos[0] = <<367.24, 293.81, 103.41>>
offset_pos[1] = <<368.73, 296.89, 103.41>>
offset_pos[2] = <<366.94, 296.34, 103.43>>
offset_pos[3] = <<375.21, 291.85, 103.25>>
offset_pos[4] = <<374.81, 292.47, 103.26>>
offset_pos[5] = <<371.51, 291.85, 103.31>>
offset_pos[6] = <<373.86, 296.30, 103.31>>
offset_heading [0] = -64.83
offset_heading [1] = -163.04
offset_heading [2] = -118.77
offset_heading [3] = 127.18
offset_heading [4] = 105.04
offset_heading [5] = -146.75
offset_heading [6] = 10.11
BREAK
// Airport
CASE STREET_RACE_04
vCarPos = <<-807.98, -2555.14, 13.34>>
fCarFoc = 3.35
vCarPos2 = <<-810.10, -2560.85, 13.38>>//<<-809.86, -2560.89, 13.38>>
fCarFoc2 = 43.57
// min and max coords for the race area
vMinRaceArea = <<-1000.758545,-2436.091797,17.169464>>
vMaxRaceArea = <<-986.739929,-2424.869873,22.169460>>
// Offsets
offset_pos[0] = <<-809.45, -2554.82, 13.76>>
offset_pos[1] = <<-808.47, -2552.43, 13.76>>
offset_pos[2] = <<-806.32, -2552.87, 13.76>>
offset_pos[3] = <<-808.59, -2559.50, 13.76>>
offset_pos[4] = <<-809.10, -2558.97, 13.76>>
offset_pos[5] = <<-812.82, -2559.48, 13.76>>
offset_pos[6] = <<-810.72, -2555.37, 13.76>>
offset_heading [0] = -86.65
offset_heading [1] = -130.05
offset_heading [2] = 150.04
offset_heading [3] = 137.51
offset_heading [4] = 115.37
offset_heading [5] = -136.43
offset_heading [6] = 20.43
BREAK
// Freeway
CASE STREET_RACE_05
vCarPos = <<778.59, -1160.20, 28.35>>
fCarFoc = 302.47
vCarPos2 = <<778.47, -1164.01, 28.25>>
fCarFoc2 = 287.97
// min and max coords for the race area
vMinRaceArea = <<-1000.758545,-2436.091797,17.169464>>
vMaxRaceArea = <<-986.739929,-2424.869873,22.169460>>
// Offsets
offset_pos[0] = <<778.16, -1158.78, 28.88>>
offset_pos[1] = <<780.82, -1158.10, 28.73>>
offset_pos[2] = <<781.52, -1158.81, 28.70>>
offset_pos[3] = <<779.16, -1165.74, 28.72>>
offset_pos[4] = <<779.86, -1165.52, 28.72>>
offset_pos[5] = <<780.75, -1161.99, 28.65>>
offset_pos[6] = <<783.80, -1165.61, 28.74>>
offset_heading [0] = -147.53
offset_heading [1] = 171.51
offset_heading [2] = 104.94
offset_heading [3] = 21.91
offset_heading [4] = -0.22
offset_heading [5] = 107.91
offset_heading [6] = -95.23
BREAK
// Vespucci Canals
CASE STREET_RACE_06
vCarPos = <<-1066.59, -1151.04, 1.71>>
fCarFoc = 258.32
// Offsets
offset_pos[0] = <<-1065.07, -1151.02, 2.16>>
offset_pos[1] = <<-1065.35, -1149.36, 2.16>>
offset_pos[2] = <<-1067.13, -1151.68, 2.16>>
offset_pos[3] = <<-1066.30, -1149.38, 2.16>>
offset_pos[4] = <<-1066.01, -1152.26, 2.16>>
offset_heading [0] = 75.06
offset_heading [1] = 134.25
offset_heading [2] = -52.71
offset_heading [3] = -93.39
offset_heading [4] = -141.52
// min and max coords for the race area
vMinRaceArea = <<-1265.744385,-1057.199219,5.410841>>
vMaxRaceArea = <<-1258.678955,-1049.919067,9.443882>>
BREAK
ENDSWITCH
SETUP_ROAD_BLOCKING(raceData.eRaceTrack, vRaceRoadPos1, vRaceRoadPos2, fRaceRoadWidth)
ePedModel[0] = A_F_Y_Hipster_02
ePedModel[1] = A_M_Y_Hipster_02
ePedModel[2] = A_M_Y_Hipster_02
ePedModel[3] = A_F_Y_Hipster_02
ePedModel[4] = A_M_Y_Hipster_02
ePedModel[5] = A_M_Y_Hipster_02
ePedModel[6] = A_M_Y_Hipster_02
// Animations
IF raceData.eRaceType = RACETYPE_BIKE
sAnimDict = "random@street_race"
sAnimName[0] = "_car_b_chatting_female"
sAnimName[1] = "_car_b_chatting_male"
sAnimName[2] = "_car_b_chatting_male"
sAnimName[3] = "_car_b_chatting_female"
sAnimName[4] = "_car_b_lookout"
ELSE
sAnimDict = "random@street_race"
sAnimName[0] = "_car_a_flirt_girl"
sAnimName[1] = "_car_a_gawker_male_a"
sAnimName[2] = "_car_a_gawker_male_b"
sAnimName[3] = "_car_b_chatting_female"
sAnimName[4] = "_car_b_chatting_male"
sAnimName[5] = "_car_b_driver"
sAnimName[6] = "_car_b_lookout"
// REQUEST_MODEL(eCarModel2)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, eCarModel2)
ENDIF
eCarModel = GET_MODEL_NAME_BASED_OFF_RACE_TYPE(raceData.eRaceType)
// Request ped models
INT iIndex
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1
// REQUEST_MODEL(ePedModel[iIndex])
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, ePedModel[iIndex])
ENDFOR
// REQUEST_MODEL(eCarModel)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, eCarModel)
// Request animations
// REQUEST_ANIM_DICT(sAnimDict)
LOAD_QUEUE_MEDIUM_ADD_ANIM_DICT(sLoadQueue, sAnimDict)
// stop other peds walking through the area
SET_PED_PATHS_IN_AREA(vMinRaceArea, vMaxRaceArea, FALSE)
SET_ROADS_IN_ANGLED_AREA(vRaceRoadPos1, vRaceRoadPos2, fRaceRoadWidth, FALSE, FALSE)
bCreatedAreaBlocks = TRUE
ELIF raceData.eRaceType = RACETYPE_SEA
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Is a sea race")
SWITCH raceData.eRaceTrack
// North Coast
CASE SEA_RACE_01
vCarPos = <<3066.63, 650.90, 0.17>>
fCarFoc = 351.81
vLineupPos[0] = <<3073.57, 648.09, 0.01>>
fLineupFoc[0] = 5.72
vLineupPos[1] = <<3071.53, 648.79, -0.09>>
fLineupFoc[1] = 351.33
vLineupPos[2] = <<3068.73, 645.53, -0.07>>
fLineupFoc[2] = 348.18
BREAK
// East coast
CASE SEA_RACE_02
vCarPos = <<3462.11, 5192.15, -0.04>>
fCarFoc = 222.90
vLineupPos[0] = <<3456.64, 5195.91, 0.12>>
fLineupFoc[0] = 211.54
vLineupPos[1] = <<3453.19, 5192.84, -0.17>>
fLineupFoc[1] = 201.55
vLineupPos[2] = <<3451.06, 5189.43, -0.30>>
fLineupFoc[2] = 221.55
BREAK
// Raton Canyon
CASE SEA_RACE_03
vCarPos = <<194.64, 3621.27, 29.91>>//<<145.66, 3455.27, 29.93>>
fCarFoc = 163.95//154.48
vLineupPos[0] = <<198.62, 3620.46, 29.91>>//<<149.65, 3453.45, 29.90>>
fLineupFoc[0] = 175.40//164.07
vLineupPos[1] = <<202.78, 3619.69, 29.87>>//<<153.37, 3452.00, 29.90>>
fLineupFoc[1] = 163.69//152.39
vLineupPos[2] = <<210.14, 3618.88, 29.87>>//<<157.20, 3449.60, 29.99>>
fLineupFoc[2] = 175.31//140.07
BREAK
// Los Santos
CASE SEA_RACE_04
vCarPos = <<627.58, -2138.06, -0.07>>
fCarFoc = 180.09
vLineupPos[0] = <<643.09, -2146.11, -0.09>>
fLineupFoc[0] = 143.89
vLineupPos[1] = <<638.21, -2145.30, -0.10>>
fLineupFoc[1] = 172.41
vLineupPos[2] = <<633.56, -2143.83, -0.04>>
fLineupFoc[2] = 191.97
BREAK
ENDSWITCH
eCarModel = SEASHARK
// REQUEST_MODEL(eCarModel)
// REQUEST_MODEL(A_M_Y_Jetski_01)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, eCarModel)
LOAD_QUEUE_MEDIUM_ADD_MODEL(sLoadQueue, A_M_Y_Jetski_01)
ENDIF
ENDPROC
/// PURPOSE:
/// Creates the initial scene
PROC CREATE_INITIAL_SCENE()
IF HAS_LOAD_QUEUE_MEDIUM_LOADED(sLoadQueue)
IF raceData.eRaceType = RACETYPE_CAR
IF ALLOW_INITIAL_SCENE()
IF NOT DOES_ENTITY_EXIST(viCar)
IF HAS_MODEL_LOADED(eCarModel) AND HAS_MODEL_LOADED(eCarModel)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Creating vehicle")
//Create vehicle...
viCar = CREATE_VEHICLE(eCarModel, vCarPos, fCarFoc)
IF CAN_CREATE_RANDOM_PED(RPM_MALE_PED) AND CAN_CREATE_RANDOM_DRIVER()
piDriver = CREATE_RANDOM_PED_AS_DRIVER(viCar)
TASK_VEHICLE_TEMP_ACTION(piDriver, viCar, TEMPACT_WAIT, 99999999)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piDriver, TRUE)
SET_PED_KEEP_TASK(piDriver, TRUE)
ENDIF
SET_VEHICLE_ON_GROUND_PROPERLY(viCar)
SET_VEHICLE_ENGINE_ON(viCar, TRUE, TRUE)
SET_VEHICLE_RADIO_ENABLED(viCar, TRUE)
SET_VEHICLE_RADIO_LOUD(viCar, TRUE)
SET_RADIO_STATION_MUSIC_ONLY(GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)), TRUE)
SET_VEH_RADIO_STATION(viCar, GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)))
SET_VEHICLE_NOT_STEALABLE_AMBIENTLY(viCar, FALSE)
SET_MODEL_AS_NO_LONGER_NEEDED(eCarModel)
WAIT(0)
ENDIF
ENDIF
IF NOT DOES_ENTITY_EXIST(viCar2)
IF HAS_MODEL_LOADED(eCarModel2)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Creating vehicle")
//Create vehicle...
viCar2 = CREATE_VEHICLE(eCarModel2, vCarPos2, fCarFoc2)
SET_VEHICLE_ENGINE_ON(viCar2, FALSE, TRUE)
SET_VEHICLE_RADIO_ENABLED(viCar2, TRUE)
SET_VEHICLE_RADIO_LOUD(viCar2, TRUE)
SET_VEHICLE_ON_GROUND_PROPERLY(viCar2)
SET_RADIO_STATION_MUSIC_ONLY(GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)), TRUE)
SET_VEH_RADIO_STATION(viCar2, GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)))
SET_VEHICLE_NOT_STEALABLE_AMBIENTLY(viCar2, FALSE)
SET_MODEL_AS_NO_LONGER_NEEDED(eCarModel2)
WAIT(0)
ENDIF
ENDIF
// Wait for models and animations to load
IF HAS_ANIM_DICT_LOADED(sAnimDict)
IF bReleaseModels
INT iIndex
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1
// Play animation and look towards player when the ped has been created
IF DOES_ENTITY_EXIST(piCrowd[iIndex])
IF NOT IS_ENTITY_DEAD(piCrowd[iIndex]) AND NOT IsPedPerformingTask(piCrowd[iIndex], SCRIPT_TASK_PLAY_ANIM)
//SET_ENTITY_COORDS_NO_OFFSET(piCrowd[iIndex], offset_pos[iIndex])
TASK_PLAY_ANIM(piCrowd[iIndex], sAnimDict, sAnimName[iIndex], INSTANT_BLEND_IN, INSTANT_BLEND_OUT, -1, AF_LOOPING)
SET_PED_KEEP_TASK(piCrowd[iIndex], TRUE)
// Release model
//SET_MODEL_AS_NO_LONGER_NEEDED(ePedModel[iIndex])
ENDIF
ELSE
// Ped hasn't been created yet, let's create him!
IF HAS_MODEL_LOADED(ePedModel[iIndex])
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Creating peds")
piCrowd[iIndex] = CREATE_PED(PEDTYPE_SPECIAL, ePedModel[iIndex], offset_pos[iIndex], offset_heading[iIndex])
SET_ENTITY_COORDS_NO_OFFSET(piCrowd[iIndex], offset_pos[iIndex])
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piCrowd[iIndex], TRUE)
TASK_PLAY_ANIM(piCrowd[iIndex], sAnimDict, sAnimName[iIndex], INSTANT_BLEND_IN, INSTANT_BLEND_OUT, -1, AF_LOOPING)
SET_PED_KEEP_TASK(piCrowd[iIndex], TRUE)
ENDIF
ENDIF
ENDFOR
IF IS_PED_UNINJURED(piCrowd[0]) AND IS_PED_UNINJURED(piCrowd[1]) AND IS_PED_UNINJURED(piCrowd[2]) AND IS_PED_UNINJURED(piCrowd[3]) AND IS_PED_UNINJURED(piCrowd[4])
AND IS_PED_UNINJURED(piCrowd[5]) AND IS_PED_UNINJURED(piCrowd[6]) AND IS_VEHICLE_OK(viCar) AND IS_VEHICLE_OK(viCar2)
/*iSyncedSceneOne = CREATE_SYNCHRONIZED_SCENE(GET_WORLD_POSITION_OF_ENTITY_BONE(viCar, GET_ENTITY_BONE_INDEX_BY_NAME(viCar, "chassis_dummy")),GET_ENTITY_ROTATION(viCar))
SET_SYNCHRONIZED_SCENE_LOOPED(iSyncedSceneOne,TRUE)
SET_SYNCHRONIZED_SCENE_HOLD_LAST_FRAME(iSyncedSceneOne,FALSE)
//ATTACH_SYNCHRONIZED_SCENE_TO_ENTITY(iSyncedSceneOne, viCar, GET_ENTITY_BONE_INDEX_BY_NAME(viCar, "chassis_dummy"))
iSyncedSceneTwo = CREATE_SYNCHRONIZED_SCENE(GET_WORLD_POSITION_OF_ENTITY_BONE(viCar2, GET_ENTITY_BONE_INDEX_BY_NAME(viCar2, "chassis_dummy")),GET_ENTITY_ROTATION(viCar2))
SET_SYNCHRONIZED_SCENE_LOOPED(iSyncedSceneTwo,TRUE)
SET_SYNCHRONIZED_SCENE_HOLD_LAST_FRAME(iSyncedSceneTwo,FALSE)
//ATTACH_SYNCHRONIZED_SCENE_TO_ENTITY(iSyncedSceneTwo, viCar2, GET_ENTITY_BONE_INDEX_BY_NAME(viCar2, "chassis_dummy"))
TASK_SYNCHRONIZED_SCENE(piCrowd[0], iSyncedSceneOne, sAnimDict, sAnimName[0], INSTANT_BLEND_IN, SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_SYNCHRONIZED_SCENE(piCrowd[1], iSyncedSceneOne, sAnimDict, sAnimName[1], INSTANT_BLEND_IN, SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_SYNCHRONIZED_SCENE(piCrowd[2], iSyncedSceneOne, sAnimDict, sAnimName[2], INSTANT_BLEND_IN, SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_SYNCHRONIZED_SCENE(piCrowd[3], iSyncedSceneTwo, sAnimDict, sAnimName[3], INSTANT_BLEND_IN, SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_SYNCHRONIZED_SCENE(piCrowd[4], iSyncedSceneTwo, sAnimDict, sAnimName[4], INSTANT_BLEND_IN, SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_SYNCHRONIZED_SCENE(piCrowd[5], iSyncedSceneTwo, sAnimDict, sAnimName[5], INSTANT_BLEND_IN, SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_SYNCHRONIZED_SCENE(piCrowd[6], iSyncedSceneTwo, sAnimDict, sAnimName[6], INSTANT_BLEND_IN, NORMAL_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT)
TASK_LOOK_AT_ENTITY(piCrowd[6], PLAYER_PED_ID(), -1, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH)*/
bStartPedSixTurning = TRUE
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1
SET_MODEL_AS_NO_LONGER_NEEDED(ePedModel[iIndex])
ENDFOR
bReleaseModels = FALSE
ENDIF
ENDIF
ENDIF
ENDIF
ELIF raceData.eRaceType = RACETYPE_BIKE
IF ALLOW_INITIAL_SCENE()
IF NOT DOES_ENTITY_EXIST(viCar)
IF HAS_MODEL_LOADED(eCarModel)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Creating vehicle")
//Create vehicle...
viCar = CREATE_VEHICLE(eCarModel, vCarPos, fCarFoc)
IF CAN_CREATE_RANDOM_PED(RPM_DONT_CARE) AND CAN_CREATE_RANDOM_BIKE_RIDER()
piDriver = CREATE_RANDOM_PED_AS_DRIVER(viCar)
TASK_VEHICLE_TEMP_ACTION(piDriver, viCar, TEMPACT_WAIT, 99999999)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piDriver, TRUE)
SET_PED_KEEP_TASK(piDriver, TRUE)
ENDIF
SET_VEHICLE_ENGINE_ON(viCar, TRUE, TRUE)
SET_VEHICLE_RADIO_ENABLED(viCar, TRUE)
SET_VEHICLE_RADIO_LOUD(viCar, TRUE)
SET_RADIO_STATION_MUSIC_ONLY(GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)), TRUE)
SET_VEH_RADIO_STATION(viCar, GET_RADIO_STATION_NAME(ENUM_TO_INT(RADIO_GENRE_DANCE)))
SET_VEHICLE_NOT_STEALABLE_AMBIENTLY(viCar, FALSE)
SET_MODEL_AS_NO_LONGER_NEEDED(eCarModel)
ENDIF
ENDIF
// Wait for models and animations to load
IF HAS_ANIM_DICT_LOADED(sAnimDict)
IF bReleaseModels
INT iIndex
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 3 // Only creating five peds for the bike race
// Play animation and look towards player when the ped has been created
IF DOES_ENTITY_EXIST(piCrowd[iIndex])
IF NOT IS_ENTITY_DEAD(piCrowd[iIndex]) AND NOT IsPedPerformingTask(piCrowd[iIndex], SCRIPT_TASK_PLAY_ANIM)
SET_ENTITY_COORDS_NO_OFFSET(piCrowd[iIndex], offset_pos[iIndex])
IF iIndex <> 2 AND iIndex <> 3
TASK_PLAY_ANIM(piCrowd[iIndex], sAnimDict, sAnimName[iIndex], INSTANT_BLEND_IN, INSTANT_BLEND_OUT, -1, AF_LOOPING)
ELSE
TASK_PLAY_ANIM(piCrowd[iIndex], sAnimDict, sAnimName[iIndex], INSTANT_BLEND_IN, INSTANT_BLEND_OUT, -1, AF_LOOPING, 0.5)
ENDIF
SET_PED_KEEP_TASK(piCrowd[iIndex], TRUE)
ENDIF
ELSE
// Ped hasn't been created yet, let's create him!
IF HAS_MODEL_LOADED(ePedModel[iIndex])
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Creating peds")
piCrowd[iIndex] = CREATE_PED(PEDTYPE_SPECIAL, ePedModel[iIndex], offset_pos[iIndex], offset_heading[iIndex])
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piCrowd[iIndex], TRUE)
ENDIF
ENDIF
ENDFOR
IF IS_PED_UNINJURED(piCrowd[0]) AND IS_PED_UNINJURED(piCrowd[1]) AND IS_PED_UNINJURED(piCrowd[2]) AND IS_PED_UNINJURED(piCrowd[3]) AND IS_PED_UNINJURED(piCrowd[4])
TASK_LOOK_AT_ENTITY(piCrowd[4], PLAYER_PED_ID(), -1, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH)
FOR iIndex = 0 TO COUNT_OF(ePedModel) - 1 // Only five peds but seven models were loaded...
SET_MODEL_AS_NO_LONGER_NEEDED(ePedModel[iIndex])
ENDFOR
bReleaseModels = FALSE
ENDIF
ENDIF
ENDIF
ENDIF
ELIF raceData.eRaceType = RACETYPE_SEA
IF ALLOW_INITIAL_SCENE()
IF NOT DOES_ENTITY_EXIST(viCar)
CPRINTLN(DEBUG_MISSION,"Creating spare seashark")
IF HAS_MODEL_LOADED(eCarModel)
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene: Creating vehicle")
//Create vehicle...
viCar = CREATE_VEHICLE(eCarModel, vCarPos, fCarFoc)
//ACTIVATE_PHYSICS(viCar)
SET_VEHICLE_ON_GROUND_PROPERLY(viCar)
SET_BOAT_LOW_LOD_ANCHOR_DISTANCE(viCar,0)
//SET_BOAT_REMAINS_ANCHORED_WHILE_PLAYER_IS_DRIVER(viCar,TRUE)
SET_BOAT_REMAINS_ANCHORED_WHILE_PLAYER_IS_DRIVER(viCar,FALSE)
SET_FORCE_LOW_LOD_ANCHOR_MODE(viCar,FALSE)
IF CAN_ANCHOR_BOAT_HERE(viCar)
SET_BOAT_ANCHOR(viCar,TRUE)
ENDIF
SET_VEHICLE_ENGINE_ON(viCar, FALSE, TRUE)
//bAnchored = TRUE
ENDIF
ENDIF
INT i_index = 0
REPEAT LINEUP_SIZE i_index
IF DOES_ENTITY_EXIST(viLineup[i_index])
IF DOES_ENTITY_EXIST(piLineup[i_index])
IF NOT IS_PED_INJURED(piLineup[i_index]) AND IS_VEHICLE_OK(viLineup[i_index])
IF IS_VEHICLE_SEAT_FREE(viLineup[i_index])
SET_PED_INTO_VEHICLE(piLineup[i_index], viLineup[i_index])
ENDIF
ENDIF
ELSE
IF IS_VEHICLE_OK(viLineup[i_index]) AND HAS_MODEL_LOADED(A_M_Y_Jetski_01)
piLineup[i_index] = CREATE_PED_INSIDE_VEHICLE(viLineup[i_index], PEDTYPE_SPECIAL, A_M_Y_Jetski_01)
SET_PED_DIES_IN_WATER(piLineup[i_index], FALSE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(piLineup[i_index], TRUE)
ENDIF
ENDIF
ELSE
IF HAS_MODEL_LOADED(eCarModel)
viLineup[i_index] = CREATE_VEHICLE(eCarModel, vLineupPos[i_index], fLineupFoc[i_index])
SET_VEHICLE_ON_GROUND_PROPERLY(viLineup[i_index])
SET_BOAT_LOW_LOD_ANCHOR_DISTANCE(viLineup[i_index],0)
SET_BOAT_REMAINS_ANCHORED_WHILE_PLAYER_IS_DRIVER(viLineup[i_index],TRUE)
SET_FORCE_LOW_LOD_ANCHOR_MODE(viLineup[i_index],TRUE)
IF CAN_ANCHOR_BOAT_HERE(viLineup[i_index])
SET_BOAT_ANCHOR(viLineup[i_index],TRUE)
ENDIF
SET_VEHICLE_ENGINE_ON(viLineup[i_index], FALSE, TRUE)
ENDIF
ENDIF
ENDREPEAT
IF DOES_ENTITY_EXIST(viCar) AND DOES_ENTITY_EXIST(viLineup[0]) AND DOES_ENTITY_EXIST(viLineup[1]) AND DOES_ENTITY_EXIST(viLineup[2])
SET_MODEL_AS_NO_LONGER_NEEDED(eCarModel)
ENDIF
IF DOES_ENTITY_EXIST(piLineup[0]) AND DOES_ENTITY_EXIST(piLineup[1]) AND DOES_ENTITY_EXIST(piLineup[2])
SET_MODEL_AS_NO_LONGER_NEEDED(A_M_Y_Jetski_01)
ENDIF
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_ForceDirectEntry, TRUE)
ENDIF
ENDIF
ENDIF
ENDPROC
// ===========================================================================================================
// States
// ===========================================================================================================
/// PURPOSE: Basic launcher setup
PROC RACELAUNCH_INIT()
// Launcher init
eState = STATE_INACTIVE
bDisplayHelp = FALSE
bLaunchRace = FALSE
bPlayOnline = FALSE
// Menu setup
eRaceMenu = MENU_INIT
iCurrentMenuItem = 0
iMenuInputTimer = 0
// Pre-load models for the race
REQUEST_RIVAL_MODELS()
// Turn off parking scenarios
SET_SCENARIO_TYPE_ENABLED("WORLD_VEHICLE_PARK_PERPENDICULAR_NOSE_IN", FALSE)
SET_SCENARIO_TYPE_ENABLED("WORLD_VEHICLE_PARK_PARALLEL", FALSE)
IF raceData.eRaceTrack = STREET_RACE_02
sbiStreetRaceTwo = ADD_SCENARIO_BLOCKING_AREA_FROM_POSITION_AND_RADIUS(<<374.008331,279.591919,102.330574>>, 40.0)
CLEAR_AREA_OF_VEHICLES(<<374.008331,279.591919,102.330574>>, 25.0)
ENDIF
IF raceData.eRaceType = RACETYPE_BIKE OR raceData.eRaceType = RACETYPE_CAR
sbiRaceStart = ADD_SCENARIO_BLOCKING_AREA_FROM_POSITION_AND_RADIUS(vInCoords, 60.0)
ENDIF
// Create debug widgets
#IF IS_DEBUG_BUILD
SETUP_RACE_WIDGET(raceData)
#ENDIF
ENDPROC
PROC HANDLE_HINT_CAM(INT iChallengeGuy)
IF IS_PLAYER_PLAYING(PLAYER_ID()) AND NOT IS_PLAYER_IN_FIRST_PERSON_CAMERA()
IF IS_PED_UNINJURED(piCrowd[iChallengeGuy])
IF bHintCamReady AND GET_ENTITY_SPEED(PLAYER_PED_ID()) < 20
SET_GAMEPLAY_ENTITY_HINT(piCrowd[iChallengeGuy], <<0,0,0>>)
bHintCamReady = FALSE
ENDIF
ENDIF
ENDIF
ENDPROC
PROC RACELAUNCH_HANDLE_GREETING(INT iChallengeGuy)
IF NOT IS_ENTITY_DEAD( piCrowd[iChallengeGuy] ) AND NOT IS_ENTITY_DEAD( PLAYER_PED_ID() )
SWITCH eChallengerState
CASE CGS_INIT
IF VDIST2( GET_ENTITY_COORDS( piCrowd[iChallengeGuy] ), GET_ENTITY_COORDS( PLAYER_PED_ID() ) ) < 8*8
bSaidSecondSpeech = FALSE
bSaidThirdSpeech = FALSE
CPRINTLN( DEBUG_OR_RACES, "Moving from LGS_INIT to LGS_FACING_PLAYER" )
eChallengerState = CGS_FACING_PLAYER
ENDIF
BREAK
CASE CGS_FACING_PLAYER
SEQUENCE_INDEX siChallenge
OPEN_SEQUENCE_TASK(siChallenge)
TASK_LOOK_AT_ENTITY(NULL, PLAYER_PED_ID(), -1)
TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID())
// TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID(), -1)
// TASK_PLAY_ANIM(NULL, "random@street_race", "_streetracer_challenge")
// TASK_PLAY_ANIM(NULL, "random@street_race", "_streetracer_wait_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT | AF_LOOPING | AF_NOT_INTERRUPTABLE)
CLOSE_SEQUENCE_TASK(siChallenge)
TASK_PERFORM_SEQUENCE(piCrowd[iChallengeGuy], siChallenge)
CLEAR_SEQUENCE_TASK(siChallenge)
CPRINTLN( DEBUG_OR_RACES, "Moving from LGS_FACING_PLAYER to LGS_FACING_PLAYER_WAIT" )
eChallengerState = CGS_FACING_PLAYER_WAIT
BREAK
CASE CGS_FACING_PLAYER_WAIT
IF GET_SCRIPT_TASK_STATUS(piCrowd[iChallengeGuy], SCRIPT_TASK_PERFORM_SEQUENCE) <> PERFORMING_TASK
OR IS_PED_FACING_PED(piCrowd[iChallengeGuy], PLAYER_PED_ID(), 20.0)
TASK_TURN_PED_TO_FACE_ENTITY(piCrowd[iChallengeGuy], PLAYER_PED_ID(), -1)
IF NOT bSaidThirdSpeech
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(piCrowd[iChallengeGuy], "PRERACE_CHAT", "A_M_Y_RACER_01_WHITE_MINI_01", SPEECH_PARAMS_FORCE_SHOUTED_CRITICAL)
ELSE
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(piCrowd[iChallengeGuy], "PRERACE_TAUNT", "A_M_Y_RACER_01_WHITE_MINI_01", SPEECH_PARAMS_FORCE_SHOUTED_CRITICAL)
ENDIF
//PLAY_SINGLE_LINE_FROM_CONVERSATION( dialoguePedsStruct, "SPR_OR", "OR_LAUNCH", "OR_LAUNCH_2", CONV_PRIORITY_LOW )
CPRINTLN( DEBUG_OR_RACES, "Moving from LGS_FACING_PLAYER_WAIT to LGS_GREETING_PLAYER" )
eChallengerState = CGS_CHALLENGING_PLAYER
ENDIF
BREAK
CASE CGS_CHALLENGING_PLAYER
IF NOT IS_AMBIENT_SPEECH_PLAYING(piCrowd[iChallengeGuy])
RESTART_TIMER_NOW( greetTimer )
TASK_PLAY_ANIM(piCrowd[iChallengeGuy], "random@street_race", "_streetracer_wait_loop", SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_DEFAULT | AF_LOOPING | AF_NOT_INTERRUPTABLE)
eChallengerState = CGS_GREETING_PLAYER
ENDIF
BREAK
CASE CGS_GREETING_PLAYER
IF VDIST2( GET_ENTITY_COORDS( piCrowd[iChallengeGuy] ), GET_ENTITY_COORDS( PLAYER_PED_ID() ) ) > 15*15
eChallengerState = CGS_INIT
ENDIF
IF GET_TIMER_IN_SECONDS(greetTimer) >= 5.0
AND NOT bSaidSecondSpeech
bSaidSecondSpeech = TRUE
eChallengerState = CGS_FACING_PLAYER
ELIF GET_TIMER_IN_SECONDS(greetTimer) >= 10.0
AND NOT bSaidThirdSpeech
bSaidThirdSpeech = TRUE
eChallengerState = CGS_FACING_PLAYER
ENDIF
BREAK
CASE CGS_GREETING_PLAYER_WAIT
BREAK
ENDSWITCH
ENDIF
ENDPROC
/// PURPOSE:
/// Checks for the player pressing the context button to trigger the race
PROC RACELAUNCH_WAIT_FOR_TRIGGER()
// Is the player within range and is allowed to start race
IF IS_PLAYER_IN_RACE_ACTIVATION_RANGE()
IF CAN_PLAYER_LAUNCH_RACE()
// Make the lookout guy challenge the player
INT iChallengeGuy = 6
IF raceData.eRaceType = RACETYPE_BIKE
iChallengeGuy = 4
ENDIF
HANDLE_HINT_CAM(iChallengeGuy)
IF IS_PED_UNINJURED(piCrowd[iChallengeGuy])
IF bStartPedSixTurning //IS_ENTITY_PLAYING_ANIM(piCrowd[6], sAnimDict, "_car_b_lookout")
IF IS_ENTITY_PLAYING_ANIM(piCrowd[iChallengeGuy], sAnimDict, sAnimName[iChallengeGuy])
STOP_ANIM_TASK(piCrowd[iChallengeGuy], sAnimDict, sAnimName[iChallengeGuy])
/*ELSE
STOP_SYNCHRONIZED_ENTITY_ANIM(piCrowd[iChallengeGuy], NORMAL_BLEND_OUT, TRUE)*/
ENDIF
//CLEAR_PED_TASKS_IMMEDIATELY(piCrowd[iChallengeGuy])
// SEQUENCE_INDEX siChallenge
// OPEN_SEQUENCE_TASK(siChallenge)
// TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID())
// TASK_PLAY_ANIM(NULL, sAnimDict, "_streetracer_challenge")
// TASK_PLAY_ANIM(NULL, sAnimDict, "_streetracer_wait_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT | AF_LOOPING | AF_NOT_INTERRUPTABLE)
// CLOSE_SEQUENCE_TASK(siChallenge)
// TASK_PERFORM_SEQUENCE(piCrowd[iChallengeGuy], siChallenge)
// CLEAR_SEQUENCE_TASK(siChallenge)
// FORCE_PED_AI_AND_ANIMATION_UPDATE(piCrowd[iChallengeGuy], TRUE)
// PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(piCrowd[iChallengeGuy], "PRERACE_TAUNT", "A_M_Y_RACER_01_WHITE_MINI_01", SPEECH_PARAMS_FORCE_SHOUTED_CRITICAL)
// CPRINTLN(DEBUG_MISSION, "Triggered Ped ", iChallengeGuy, " turning to the player")
// bStartPedSixTurning = FALSE
RACELAUNCH_HANDLE_GREETING(iChallengeGuy)
ENDIF
ENDIF
/*IF bHintCamReady
IF IS_PED_UNINJURED(piCrowd[6])
SET_GAMEPLAY_ENTITY_HINT(piCrowd[6], <<0,0,0>>)
bHintCamReady = FALSE
ENDIF
ENDIF*/
// Pressed context button to enter SP/MP race menu
SET_INPUT_EXCLUSIVE(PLAYER_CONTROL, INPUT_CONTEXT)
//IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_CONTEXT)
IF IS_CONTROL_JUST_RELEASED(PLAYER_CONTROL, INPUT_CONTEXT)
// Important, need to enable control in the cleanup only if the player cleans up from inside the menu
bTriggeredMenu = TRUE
CLEAR_HELP(TRUE)
// Player is online
/*
IF IS_PLAYER_ONLINE() AND NETWORK_HAVE_ONLINE_PRIVILEGES()
CPRINTLN(DEBUG_MISSION, "Race Launcher: Player is online...")
PLAYER_INDEX pId = GET_PLAYER_INDEX()
SET_EVERYONE_IGNORE_PLAYER(pId, TRUE)
SET_PLAYER_CONTROL(pId, FALSE)
SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE)
eState = STATE_RACE_MENU
ELSE
*/
CPRINTLN(DEBUG_MISSION, "Race Launcher: Player is offline...")
eState = STATE_LAUNCH_RACE
//ENDIF
ENDIF
ELSE
IF NOT bHintCamReady
STOP_GAMEPLAY_HINT()
bHintCamReady = TRUE
ENDIF
ENDIF
ELSE
MANAGE_RACE_HELP()
IF NOT bHintCamReady
STOP_GAMEPLAY_HINT()
bHintCamReady = TRUE
ENDIF
ENDIF
// remove anchor from seashark if this is a sea race
/*IF bAnchored AND raceData.eRaceType = RACETYPE_SEA
//CPRINTLN(DEBUG_MISSION, "seashark is anchored")
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viCar)
CPRINTLN(DEBUG_MISSION, "Player is in seashark")
SET_BOAT_ANCHOR(viCar, FALSE)
bAnchored = FALSE
ENDIF
ENDIF*/
ENDPROC
/// PURPOSE:
/// Creates the SP/MP menu
PROC BUILD_RACE_MENU()
CPRINTLN(DEBUG_MISSION, "Race Launcher: Building Race Menu...")
CLEAR_MENU_DATA()
SET_MENU_ITEM_LAYOUT(MENU_ITEM_TEXT)
SET_MENU_ITEM_JUSTIFICATION(FONT_LEFT)
// Set menu title
IF raceData.eRaceType = RACETYPE_SEA
SET_MENU_TITLE("SEA_MENU")
ELSE
SET_MENU_TITLE("STREET_MENU")
ENDIF
// Add menu options
ADD_MENU_ITEM_TEXT(0, "RACES_OPT_SP")
ADD_MENU_ITEM_TEXT(1, "RACES_OPT_MP")
// Add help text
ADD_MENU_HELP_KEY_INPUT( INPUT_FRONTEND_ACCEPT, "ITEM_SELECT")
ADD_MENU_HELP_KEY_INPUT( INPUT_FRONTEND_CANCEL, "ITEM_EXIT")
ADD_MENU_HELP_KEY_GROUP( INPUTGROUP_FRONTEND_GENERIC_UD, "ITEM_SCROLL")
// Initialise first option
SET_TOP_MENU_ITEM(0)
SET_CURRENT_MENU_ITEM(0)
iCurrentMenuItem = 0
ENDPROC
/// PURPOSE:
/// Detects player input and updates race menu
FUNC BOOL PROCESS_RACE_MENU()
// Grab the current analogue stick positions
INT iLeftX, iLeftY, iRightX, iRightY
GET_CONTROL_VALUE_OF_ANALOGUE_STICKS(iLeftX, iLeftY, iRightX, iRightY)
// Only allow menu to use these inputs
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_FRONTEND_UP)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_FRONTEND_DOWN)
// When using the analogue stick, wait for the timer to pass or the analogue stick
// to be reset before we can use the stick again.
IF iMenuInputTimer != 0
IF (TIMERA() > 800)
OR ((iLeftY > -64) AND (iLeftY < 64) AND (iLeftX > -64) AND (iLeftX < 64))
iMenuInputTimer = 0
ELSE
iLeftX = 0
iLeftY = 0
ENDIF
ENDIF
BOOL bUp = ((iLeftY < -64) OR IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_UP))
BOOL bDown = ((iLeftY > 64) OR IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_DOWN))
BOOL bAccept = (IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT))
BOOL bCancel = (IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL))
BOOL bUsingLeftStick = ((iLeftY < -64) OR (iLeftY > 64))
// Handle user input...
IF bAccept
// Check for SP/MP
IF iCurrentMenuItem = 1
bPlayOnline = TRUE
ELSE
bPlayOnline = FALSE
ENDIF
// Launch race
bLaunchRace = TRUE
RETURN TRUE
ELIF bCancel
// Return to gameplay
bTriggeredMenu = FALSE
bLaunchRace = FALSE
RETURN TRUE
ELSE
// Update menu position
IF bDown
// Menu down
IF (iCurrentMenuItem = 0)
iCurrentMenuItem = 1
ELIF
iCurrentMenuItem = 0
ENDIF
ELIF bUp
// Menu up
IF (iCurrentMenuItem = 1)
iCurrentMenuItem = 0
ELIF
iCurrentMenuItem = 1
ENDIF
ENDIF
// Current menu item needs to be updated
IF bDown OR bUp
// Require the analogue stick to be reset
IF bUsingLeftStick
SETTIMERA(0)
iMenuInputTimer = 1
ENDIF
// Set new menu item
SET_CURRENT_MENU_ITEM(iCurrentMenuItem)
ENDIF
ENDIF
DRAW_MENU()
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Handles the player selecting whether to trigger the race in SP or multiplayer
PROC RACELAUNCH_UPDATE_RACE_MENU()
SWITCH eRaceMenu
CASE MENU_INIT
IF LOAD_MENU_ASSETS()
CLEAR_HELP(TRUE)
// Setup race menu
BUILD_RACE_MENU()
// Stop the player being able to change radio station
SET_USER_RADIO_CONTROL_ENABLED(FALSE)
bRadioSwitchDisabled = TRUE
// Init vars
bLaunchRace = FALSE
bPlayOnline = FALSE
eRaceMenu = MENU_UPDATE
ENDIF
BREAK
CASE MENU_UPDATE
IF PROCESS_RACE_MENU()
eRaceMenu = MENU_CLEANUP
ENDIF
BREAK
CASE MENU_CLEANUP
// Cleanup race menu
PLAYER_INDEX pID
pId = GET_PLAYER_INDEX()
SET_EVERYONE_IGNORE_PLAYER(pId, FALSE)
SET_PLAYER_CONTROL(pId, TRUE)
SET_SCRIPTS_SAFE_FOR_CUTSCENE(FALSE)
CLEANUP_MENU_ASSETS()
eRaceMenu = MENU_INIT
// Launch race or return to gameplay
IF bLaunchRace
eState = STATE_LAUNCH_RACE
ELSE
// Allow the player to change radio station
SET_USER_RADIO_CONTROL_ENABLED(TRUE)
eState = STATE_WAIT_FOR_TRIGGER
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Loads mission script for single player or updates globals for MP
PROC RACELAUNCH_LAUNCH_RACE()
IF NOT bPlayOnline
DO_RACE_LAUNCH_SP()
ELSE
DO_RACE_LAUNCH_MP()
ENDIF
ENDPROC
/// Main script thread
SCRIPT(coords_struct in_coords)
// Launcher priority for streaming requests
SET_THIS_IS_A_TRIGGER_SCRIPT(TRUE)
// Get world point info for street race
vInCoords = in_coords.vec_coord[0]
CPRINTLN(DEBUG_MISSION, "Race Launcher: Activated at location ", vInCoords)
// Setup callback when player is killed, arrested or goes to multiplayer
IF (HAS_FORCE_CLEANUP_OCCURRED(DEFAULT_FORCE_CLEANUP_FLAGS|FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_REPEAT_PLAY))
CPRINTLN(DEBUG_MISSION, "Race Launcher: FORCE_CLEANUP [TERMINATING]")
SCRIPT_CLEANUP(FALSE)
ENDIF
// Detect whether we have launched from debug
#IF IS_DEBUG_BUILD
// Wait for game flow to update
IF g_flowUnsaved.bUpdatingGameflow
WAIT(0)
ENDIF
// Notify that we have launched from the debug menu
IF g_RaceLaunchedFromDebug = TRUE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Triggered from debug menu")
ENDIF
#ENDIF
// Establish race info from world point
GET_RACE_LOCATION()
// Have races been unlocked?
SWITCH raceData.eRaceType
CASE RACETYPE_BIKE
CASE RACETYPE_CAR
// Have races been unlocked in flow?
IF NOT GET_MISSION_FLOW_BITSET_BIT_STATE(FLOWBITSET_MINIGAME_ACTIVE, ENUM_TO_INT(MINIGAME_STREET_RACES))
CPRINTLN(DEBUG_MISSION, "Race Launcher: Street Races aren't unlocked in flow yet. Cleaning up.")
SCRIPT_CLEANUP(FALSE)
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Street Races unlocked in flow. Allowing to proceed.")
ENDIF
// Has this specific race been unlocked yet?
IF NOT IS_RACE_UNLOCKED(raceData.eRaceTrack)
CPRINTLN(DEBUG_MISSION, "Race Launcher: This race hasn't been unlocked yet. Cleaning up.")
SCRIPT_CLEANUP(FALSE)
ENDIF
BREAK
CASE RACETYPE_SEA
// Have races been unlocked in flow?
IF NOT GET_MISSION_FLOW_BITSET_BIT_STATE(FLOWBITSET_MINIGAME_ACTIVE, ENUM_TO_INT(MINIGAME_SEA_RACES))
CPRINTLN(DEBUG_MISSION, "Race Launcher: Sea Races aren't unlocked in flow yet. Cleaning up.")
SCRIPT_CLEANUP(FALSE)
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Sea Races unlocked in flow. Allowing to proceed.")
ENDIF
BREAK
CASE RACETYPE_UNDEFINED
// Have races been unlocked in flow?
CPRINTLN(DEBUG_MISSION, "Race Launcher: Undefined race type. Cleaning up.")
SCRIPT_CLEANUP(FALSE)
BREAK
ENDSWITCH
// Initial setup.
CPRINTLN(DEBUG_MISSION, "Race Launcher: Initialising...")
RACELAUNCH_INIT()
// Check conditions for racing not being allowed to launch and exit early if found
IF NOT IS_RACE_ALLOWED_TO_LAUNCH()
CPRINTLN(DEBUG_MISSION, "Race Launcher: Races not allowed to launch")
SCRIPT_CLEANUP(FALSE)
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Races allowed to launch")
ENDIF
// Create initial scene
CPRINTLN(DEBUG_MISSION, "Race Launcher: Creating initial scene...")
SETUP_INITIAL_SCENE()
// Main loop
WHILE (TRUE)
UPDATE_LOAD_QUEUE_MEDIUM(sLoadQueue)
// Check conditions for racing not being allowed to launch, exit if not
IF IS_RACE_ALLOWED_TO_LAUNCH()
// Check debug widgets
#IF IS_DEBUG_BUILD
MAINTAIN_RACE_WIDGET(raceData)
#ENDIF
// Are we still within range of this launcher?
IF IS_WORLD_POINT_WITHIN_BRAIN_ACTIVATION_RANGE()
//HANDLE_HINT_CAM()
SWITCH eState
CASE STATE_INACTIVE
eState = STATE_WAIT_FOR_TRIGGER
BREAK
// Has player entered race corona?
CASE STATE_WAIT_FOR_TRIGGER
CREATE_INITIAL_SCENE()
RACELAUNCH_WAIT_FOR_TRIGGER()
BREAK
// Player is selecting
CASE STATE_RACE_MENU
RACELAUNCH_UPDATE_RACE_MENU()
BREAK
// Player is selecting
CASE STATE_LAUNCH_RACE
RACELAUNCH_LAUNCH_RACE()
BREAK
ENDSWITCH
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Player out of range.")
SCRIPT_CLEANUP(FALSE)
ENDIF
ELSE
CPRINTLN(DEBUG_MISSION, "Race Launcher: Races not allowed to launch")
SCRIPT_CLEANUP(FALSE)
ENDIF
WAIT(0)
ENDWHILE
ENDSCRIPT