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

2685 lines
89 KiB
Scheme
Executable File

// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// SCRIPT NAME : SPTT_Race.sch
// AUTHOR : Nicholas Zippmann
// DESCRIPTION : Single Player Races - Race procs/functions file
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
USING "globals.sch"
USING "SPTT_Head.sch"
USING "SPTT_Helpers.sch"
USING "SPTT_Gate.sch"
USING "chase_hint_cam.sch" // CHASE_HINT_CAM_STRUCT localChaseHintCamStruct
USING "SPTT_Racer.sch"
USING "minigame_stats_tracker_helpers.sch"
USING "CompletionPercentage_public.sch"
USING "SPTT_SC_Leaderboard_lib.sch"
//structTimer taxiTime
structTimer resetTimer
structTimer manualResetTimer
//structTimer tShutdownTimer
BOOL bDebugFailure = FALSE
BOOL bTriggerFirstMusicEvent = FALSE
BOOL bEndTracking = TRUE
BOOL bEndShake = TRUE
BLIP_INDEX returnToVehBlip //only used in off-road but may need for bike in Tris
BOOL SPTT_USE_WAYPOINT_RECORDING = TRUE
INT iButtonSounds
//#IF IS_DEBUG_BUILD
// VECTOR vAIGoto[20]
//#ENDIF
#IF NOT DEFINED(GET_HUD_STUNT_STRING)
FUNC STRING GET_HUD_STUNT_STRING()
RETURN NULL_STRING()
ENDFUNC
#ENDIF
#IF NOT DEFINED(iSPRStuntFinishCam)
CAMERA_INDEX iSPRStuntFinishCam
#ENDIF
#IF NOT DEFINED(GET_HUD_STUNT_FLOAT)
FUNC FLOAT GET_HUD_STUNT_FLOAT()
RETURN -1.0
ENDFUNC
#ENDIF
#IF NOT DEFINED(GET_HUD_STUNT_INT)
FUNC INT GET_HUD_STUNT_INT()
RETURN ENUM_TO_INT(HUD_COLOUR_WHITE)
ENDFUNC
#ENDIF
#IF NOT DEFINED(RUN_OFFROAD_AUDIO)
PROC RUN_OFFROAD_AUDIO(SPTT_RACE_STRUCT& Race)
IF (Race.iRacerCnt = -1)
PRINTINT(Race.iRacerCnt)
PRINTNL()
ENDIF
ENDPROC
#ENDIF
#IF NOT DEFINED(stop_vehicle_recordings)
PROC stop_vehicle_recordings(SPTT_RACE_STRUCT& Race)
Race.iGateCnt = Race.iGateCnt
ENDPROC
#ENDIF
#IF NOT DEFINED(Disable_Airport_Icons)
PROC Disable_Airport_Icons()
/* IF SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE
DEBUG_MESSAGE("Inside dummy Disable_Airport_Icons proc")
ENDIF */
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Gate_Reward)
PROC SPTT_Gate_Reward(SPTT_RACER_STRUCT& Racer, SPTT_RACE_GATE_STATUS status)
Racer.fPlsMnsTot = Racer.fPlsMnsTot
status = status
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Racer_ClockTime_Penalty)
PROC SPTT_Racer_ClockTime_Penalty(SPTT_RACER_STRUCT& Racer, FLOAT fPenalty)
Racer.fPlsMnsTot = Racer.fPlsMnsTot
fPenalty = fPenalty
ENDPROC
#ENDIF
#IF NOT DEFINED(runGateTimers)
PROC runGateTimers(SPTT_RACER_STRUCT& Racer, BOOL bRacerIsPlayer, INT iGateCheck)
Racer.fPlsMnsTot = Racer.fPlsMnsTot
bRacerIsPlayer = bRacerIsPlayer
iGateCheck = iGateCheck
ENDPROC
#ENDIF
#IF NOT DEFINED(rewardPlayer)
PROC rewardPlayer()
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Race_Racer_AutoPilot)
PROC SPTT_Race_Racer_AutoPilot(SPTT_RACE_STRUCT& Race)
Race.fBestClockTime = Race.fBestClockTime
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Race_Racer_AutoCircle)
PROC SPTT_Race_Racer_AutoCircle(SPTT_RACE_STRUCT& Race)
Race.fBestClockTime = Race.fBestClockTime
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Racer_AutoPilot)
PROC SPTT_Racer_AutoPilot(SPTT_RACER_STRUCT& Racer, FLOAT fSpeed, BOOL bRotInterp)
Racer.fStartHead = Racer.fStartHead
fSpeed = fSpeed
bRotInterp = bRotInterp
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Racer_AutoCircle)
PROC SPTT_Racer_AutoCircle(SPTT_RACER_STRUCT& Racer, FLOAT fSpeed, BOOL bRotInterp)
Racer.fStartHead = Racer.fStartHead
fSpeed = fSpeed
bRotInterp= bRotInterp
ENDPROC
#ENDIF
#IF NOT DEFINED(Tri_Showing_Player_Finished_Race)
FUNC BOOL Tri_Showing_Player_Finished_Race()
RETURN FALSE
ENDFUNC
#ENDIF
#IF NOT DEFINED(SET_TRI_RACERS_ONCE_RACE_ENDS)
PROC SET_TRI_RACERS_ONCE_RACE_ENDS(SPTT_RACE_STRUCT& Race)
Race.iGateCnt = Race.iGateCnt
ENDPROC
#ENDIF
#IF NOT DEFINED(SET_CUTSCENE_CAMERA_AT_END_OF_RACE)
PROC SET_CUTSCENE_CAMERA_AT_END_OF_RACE(BOOL bActivateCam)
bActivateCam = bActivateCam
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Init_Scorecard)
PROC SPTT_Init_Scorecard(SPTT_RACE_STRUCT &Race)
Race.iGateCheck = Race.iGateCheck
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Draw_Scorecard)
PROC SPTT_Draw_Scorecard(SPTT_RACE_STRUCT &Race, INT &iPlayerIndex)
Race.iGateCheck = Race.iGateCheck
iPlayerIndex = iPlayerIndex
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Setup_Leaderboard)
PROC SPTT_Setup_Leaderboard(SPTT_RACE_STRUCT &Race)
UNUSED_PARAMETER(Race)
ENDPROC
#ENDIF
#IF NOT DEFINED(Cleanup_Finish_Camera)
PROC Cleanup_Finish_Camera()
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Race_Stunt_Manage_Finish_Camera)
PROC SPTT_Race_Stunt_Manage_Finish_Camera(VEHICLE_INDEX& iPlayersPlane)
iPlayersPlane = iPlayersPlane
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_UPDATING_END_SCREEN)
PROC SPTT_UPDATING_END_SCREEN()
//nothing
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Race_Manage_Race_Beats)
PROC SPTT_Race_Manage_Race_Beats(INT iGateCur, BOOL bFailChecking)
iGateCur = iGateCur
bFailChecking = bFailChecking
ENDPROC
#ENDIF
#IF NOT DEFINED(SPTT_Race_Cleanup_Stunt_Beats)
PROC SPTT_Race_Cleanup_Stunt_Beats()
ENDPROC
#ENDIF
#IF NOT DEFINED(FINISH_AI_RACERS)
PROC FINISH_AI_RACERS(SPTT_RACER_STRUCT& Racer)
PRINTFLOAT(Racer.fStartHead)
PRINTNL()
ENDPROC
#ENDIF
#IF NOT DEFINED(RELEASE_AI_RACERS)
PROC RELEASE_AI_RACERS(SPTT_RACE_STRUCT& Race)
PRINTINT(Race.iRacerCnt)
PRINTNL()
ENDPROC
#ENDIF
// -----------------------------------
// HELPER PROCS/FUNCTIONS
// -----------------------------------
PROC SPTT_Race_FakeRacer_Populate(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_FakeRacer_Populate")
TEXT_LABEL_31 szRacerName[SPTT_UI_LB_RACER_LIMIT - 1]
SPTT_RacerName_Populate(szRacerName)
FLOAT fBestClockTime = Race.fBestClockTime
IF (fBestClockTime > Race.Racer[0].fClockTime)
fBestClockTime = Race.Racer[0].fClockTime
ENDIF
WHILE (Race.iRacerCnt < SPTT_UI_LB_RACER_LIMIT)
Race.Racer[Race.iRacerCnt].szName = szRacerName[Race.iRacerCnt - 1]
Race.Racer[Race.iRacerCnt].fClockTime = GET_RANDOM_FLOAT_IN_RANGE(fBestClockTime, fBestClockTime * 1.25)
++Race.iRacerCnt
ENDWHILE
ENDPROC
PROC SPTT_Race_ClockTime_SimAI(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_ClockTime_SimAI")
INT i
REPEAT Race.iRacerCnt i
IF (Race.Racer[i].iGateCur <> Race.iGateCnt)
Race.Racer[i].fClockTime = Race.Racer[0].fClockTime + ((Race.iGateCnt - Race.Racer[i].iGateCur) * GET_RANDOM_FLOAT_IN_RANGE(0.5, 2.5))
ENDIF
ENDREPEAT
ENDPROC
PROC SPTT_Race_Rank_CalcFinal(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Rank_CalcFinal")
INT i, j, iRank
REPEAT Race.iRacerCnt i
iRank = 1
REPEAT Race.iRacerCnt j
IF (i <> j)
IF (Race.Racer[i].fClockTime > Race.Racer[j].fClockTime)
++iRank
// TODO: Should be doing something to offset tied ranks for leaderboard.
// TODO: Also make sure if 2 guys share a rank, the next rank is 1 higher.
//ELIF (Race.Racer[i].iGateCur = Race.Racer[j].iGateCur)
// ++iRank
ENDIF
ENDIF
ENDREPEAT
Race.Racer[i].iRank = iRank
ENDREPEAT
ENDPROC
// TODO: My method of finding player racer here is different from above.
// May want to come up with a safe way we know which racer is player.
PROC SPTT_Race_RankClock_FindPlayerBest(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_FindPlayerBest")
INT i
REPEAT Race.iRacerCnt i
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
IF (Race.Racer[i].Driver = PLAYER_PED_ID())
INT iBestRank = SPTT_Global_BestRank_Get(SPTT_Master.iRaceCur)
IF (iBestRank <= 0) OR (iBestRank > Race.Racer[i].iRank)
SPTT_Global_BestRank_Set(SPTT_Master.iRaceCur, Race.Racer[i].iRank)
ENDIF
FLOAT fBestTime = SPTT_Global_BestTime_Get(SPTT_Master.iRaceCur)
SPTT_LastTime_Set(SPTT_Master.iRaceCur, TO_FLOAT(CEIL(Race.Racer[0].fClockTime)))
IF (fBestTime = 0.0) OR (fBestTime > Race.Racer[0].fClockTime)
SPTT_Global_BestTime_Set(SPTT_Master.iRaceCur, TO_FLOAT(CEIL(Race.Racer[0].fClockTime)))
ENDIF
EXIT
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC SPTT_Race_Leaderboard_Init_Scorecard(SPTT_RACE_STRUCT& Race)
SPTT_Init_Scorecard(Race)
SETTIMERA(0)
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
ENDPROC
FUNC BOOL SPTT_Race_Draw_Scorecard(SPTT_RACE_STRUCT& Race)
//delay scorecard
IF TIMERA() < 2000
RETURN FALSE
ENDIF
Race.Racer[0].Driver = Race.Racer[0].Driver
// INT iPlayerIndex = 0
// INT i
// REPEAT Race.iRacerCnt i
// IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
// IF (Race.Racer[i].Driver = PLAYER_PED_ID())
// iPlayerIndex = i
// ENDIF
// ENDIF
// ENDREPEAT
//show medal toast.
IF NOT IS_RADAR_HIDDEN()
DISPLAY_RADAR(FALSE)
ENDIF
IF TIMERA() > 5000
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
// -----------------------------------
// GATE PROCS/FUNCTIONS
// -----------------------------------
FUNC BOOL SPTT_Race_Gate_Activate(SPTT_RACE_STRUCT& Race, INT iGate, BOOL bGateCur)
VECTOR vNextGate
//DEBUG_MESSAGE("SPTT_Race_Gate_Activate")
IF (iGate < 0) OR (iGate > (SPTT_GATE_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Gate_Activate: Gate index out of range!")
RETURN FALSE
ENDIF
BLIP_SPRITE eBlipSprite = RADAR_TRACE_INVALID
IF (iGate = (Race.iGateCnt - 1))
eBlipSprite = RADAR_TRACE_RACEFLAG
ENDIF
FLOAT fBlipScale = SPTT_GATE_BLIPCUR_SCL
IF NOT bGateCur
fBlipScale = SPTT_GATE_BLIPNXT_SCL
ENDIF
IF NOT SPTT_Gate_Blip_Create(Race.sGate[iGate], eBlipSprite, fBlipScale, iGate, Race.iGateCnt)
DEBUG_MESSAGE("SPTT_Race_Gate_Activate: Failed to create gate blip!")
RETURN FALSE
ENDIF
IF bGateCur
VECTOR vNextGatePos = Race.sGate[iGate].vPos
VECTOR vPrevGatePos = <<0,0,0>>
IF (iGate < (Race.iGateCnt - 1))
IF NOT ARE_VECTORS_ALMOST_EQUAL(Race.sGate[iGate].vPos, Race.sGate[iGate + 1].vPos)
vNextGatePos = Race.sGate[iGate + 1].vPos
ENDIF
ENDIF
IF SPTT_Master.eRaceType = SPTT_RACE_TYPE_OFFROAD
IF (SPTT_Master.iRaceCur = 1) // 1 for Ridgerun)
IF IS_BITMASK_AS_ENUM_SET(Race.sGate[8].iGateFlags, SPTT_RACE_GATE_FLAG_DO_NOT_SNAP_TO_GROUND)
CLEAR_BITMASK_AS_ENUM(Race.sGate[8].iGateFlags, SPTT_RACE_GATE_FLAG_DO_NOT_SNAP_TO_GROUND)
PRINTLN("SPTT_Race_Gate_Activate: Cleared Bitmask as Enum for sGate[8]")
PRINTNL()
ENDIF
ENDIF
ENDIF
IF (iGate > 0)
vPrevGatePos = Race.sGate[iGate-1].vPos
ENDIF
IF NOT SPTT_Gate_Chkpnt_Create(vPrevGatePos, Race.sGate[iGate], vNextGatePos, SPTT_GATE_CHKPNT_SCL)
DEBUG_MESSAGE("SPTT_Race_Gate_Activate: Failed to create gate checkpoint!")
RETURN FALSE
ENDIF
//turn on the next checkpoint and make it tiny
IF iGate+1 < Race.iGateCnt
IF (iGate+2 >= SPTT_GATE_MAX)
vNextGate = Race.sGate[0].vPos
ELSE
vNextGate = Race.sGate[iGate+2].vPos
ENDIF
//just set the nextgatepos to the origin because we can't even see the arrow anyways
IF NOT SPTT_Gate_Chkpnt_Create(Race.sGate[iGate].vPos, Race.sGate[iGate+1], vNextGate, SPTT_GATE_CHKPNT_SCL)//SPTT_GATE_CHKPNTNXT_SCL)
DEBUG_MESSAGE("SPTT_Race_Gate_Activate: Failed to create gate checkpoint!")
RETURN FALSE
ENDIF
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
FUNC BOOL SPTT_Race_Gate_Activate_All(SPTT_RACE_STRUCT& Race, BOOL bGateCur)
//DEBUG_MESSAGE("SPTT_Race_Gate_Activate_All")
INT i
BOOL bAllDone = TRUE
REPEAT Race.iGateCnt i
IF NOT SPTT_Race_Gate_Activate(Race, i, bGateCur)
bAllDone = FALSE
ENDIF
ENDREPEAT
RETURN bAllDone
ENDFUNC
PROC SPTT_Race_Gate_Deactivate(SPTT_RACE_STRUCT& Race, INT iGate)
//DEBUG_MESSAGE("SPTT_Race_Gate_Deactivate")
IF (iGate < 0) OR (iGate > (SPTT_GATE_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Gate_Deactivate: Gate index out of range!")
EXIT
ENDIF
SPTT_Gate_Blip_Destroy(Race.sGate[iGate])
SPTT_Chkpnt_BeginFade(Race.sGate[iGate].Chkpnt, Race.fadeCheckpoint, Race.iFadeAlpha, (Race.sGate[iGate].eChkpntType = SPTT_CHKPT_STUNT_FINISH))
// SPTT_Gate_Chkpnt_Destroy(Race.sGate[iGate])
//turn off our extra checkpoint
IF iGate+1 < Race.iGateCnt
SPTT_Gate_Blip_Destroy(Race.sGate[iGate+1])
SPTT_Gate_Chkpnt_Destroy(Race.sGate[iGate+1])
ENDIF
ENDPROC
PROC SPTT_Race_Gate_Deactivate_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Gate_Deactivate_All")
INT i
REPEAT Race.iGateCnt i
SPTT_Race_Gate_Deactivate(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Gate_Init(SPTT_RACE_STRUCT& Race, INT iGate)
//DEBUG_MESSAGE("SPTT_Race_Gate_Init")
IF (iGate < 0) OR (iGate > (SPTT_GATE_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Gate_Init: Gate index out of range!")
EXIT
ENDIF
SPTT_Gate_Blip_Destroy(Race.sGate[iGate])
SPTT_Gate_Chkpnt_Destroy(Race.sGate[iGate])
SPTT_Gate_Init(Race.sGate[iGate])
ENDPROC
PROC SPTT_Race_Gate_Init_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Gate_Init_All")
INT i
REPEAT Race.iGateCnt i
SPTT_Race_Gate_Init(Race, i)
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER DRIVER PROCS/FUNCTIONS
// -----------------------------------
PROC SPTT_Race_Racer_Driver_Request(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Request")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Request: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Driver_Request(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Driver_Request_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Request_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Driver_Request(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Driver_Stream(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Stream")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Stream: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN SPTT_Racer_Driver_Stream(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Driver_Stream_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Stream_All")
INT i
BOOL bStreamDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Racer_Driver_Stream(Race, i)
bStreamDone = FALSE
ENDIF
ENDREPEAT
RETURN bStreamDone
ENDFUNC
PROC SPTT_Race_Racer_Driver_Evict(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Evict")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Evict: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Driver_Evict(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Driver_Evict_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Evict_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Driver_Evict(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Driver_Create(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Create")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Create: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN SPTT_Racer_Driver_Create(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Driver_Create_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Race_Racer_Driver_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC SPTT_Race_Racer_Driver_Freeze(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Freeze")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Freeze: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Driver_Freeze(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Driver_Freeze_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Freeze_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Driver_Freeze(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Driver_UnFreeze(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_UnFreeze")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_UnFreeze: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Driver_UnFreeze(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Driver_UnFreeze_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_UnFreeze_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Driver_UnFreeze(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Driver_Release(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Release")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Release: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Driver_Release(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Driver_Release_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Release_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Driver_Release(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Driver_Destroy(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Destroy")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Destroy: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Driver_Destroy(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Driver_Destroy_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Driver_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Driver_Destroy(Race, i)
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER VEHICLE PROCS/FUNCTIONS
// -----------------------------------
PROC SPTT_Race_Racer_Vehicle_Request(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Request")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Request: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Vehicle_Request(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Request_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Request_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Vehicle_Request(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Vehicle_Stream(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Stream")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Stream: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN SPTT_Racer_Vehicle_Stream(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Vehicle_Stream_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Stream_All")
INT i
BOOL bStreamDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Racer_Vehicle_Stream(Race, i)
bStreamDone = FALSE
ENDIF
ENDREPEAT
RETURN bStreamDone
ENDFUNC
PROC SPTT_Race_Racer_Vehicle_Evict(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Evict")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Evict: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Vehicle_Evict(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Evict_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Evict_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Vehicle_Evict(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Vehicle_Create(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Create")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Create: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN SPTT_Racer_Vehicle_Create(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Vehicle_Create_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Race_Racer_Vehicle_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC SPTT_Race_Racer_Vehicle_Freeze(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Freeze")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Freeze: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Vehicle_Freeze(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Freeze_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Freeze_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Vehicle_Freeze(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Vehicle_UnFreeze(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_UnFreeze")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_UnFreeze: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Vehicle_UnFreeze(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Vehicle_UnFreeze_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_UnFreeze_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Vehicle_UnFreeze(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Release(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Release")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Release: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Vehicle_Release(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Release_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Release_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Vehicle_Release(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Destroy(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Destroy")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Destroy: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Vehicle_Destroy(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Vehicle_Destroy_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Vehicle_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Vehicle_Destroy(Race, i)
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER MAIN PROCS/FUNCTIONS
// -----------------------------------
PROC SPTT_Race_Racer_Request(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Request")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Request: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Request(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Request_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Request_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Request(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Stream(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Stream")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Stream: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN SPTT_Racer_Stream(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Stream_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Stream_All")
INT i
BOOL bStreamDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Race_Racer_Stream(Race, i)
bStreamDone = FALSE
ENDIF
ENDREPEAT
RETURN bStreamDone
ENDFUNC
PROC SPTT_Race_Racer_Evict(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Evict")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Evict: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Evict(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Evict_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Evict_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Evict(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Blip_Create(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Blip_Create")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Blip_Create: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN SPTT_Racer_Blip_Create(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Blip_Create_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Blip_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Race_Racer_Blip_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC SPTT_Race_Racer_Blip_Destroy(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Blip_Destroy")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Blip_Destroy: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Blip_Destroy(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Blip_Destroy_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Blip_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Blip_Destroy(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL SPTT_Race_Racer_Create(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Create")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Create: Racer index out of range!")
RETURN FALSE
ENDIF
IF (iRacer > 0)
RETURN SPTT_Racer_Create(Race.Racer[iRacer], TRUE)
ELSE
RETURN SPTT_Racer_Create(Race.Racer[iRacer], FALSE)
ENDIF
ENDFUNC
FUNC BOOL SPTT_Race_Racer_Create_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT SPTT_Race_Racer_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC SPTT_Race_Racer_Freeze(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Freeze")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Freeze: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Freeze(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Freeze_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Freeze_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Freeze(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_UnFreeze(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_UnFreeze")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_UnFreeze: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_UnFreeze(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_UnFreeze_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_UnFreeze_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_UnFreeze(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Release(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Release")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Release: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Release(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Release_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Release_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Release(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Destroy(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Destroy")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Destroy: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Destroy(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Destroy_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Destroy(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Init(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Init")
IF (iRacer < 0) OR (iRacer > (SPTT_RACER_MAX - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Init: Racer index out of range!")
EXIT
ENDIF
SPTT_Racer_Destroy(Race.Racer[iRacer])
SPTT_Racer_Init(Race.Racer[iRacer])
ENDPROC
PROC SPTT_Race_Racer_Init_All(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Init_All")
INT i
REPEAT Race.iRacerCnt i
SPTT_Race_Racer_Init(Race, i)
ENDREPEAT
ENDPROC
PROC SPTT_RACE_TELL_AUDIENCE_TO_LOOK_AT_PLAYER()
PED_INDEX pedArray[10]
GET_PED_NEARBY_PEDS(PLAYER_PED_ID(), pedArray, PEDTYPE_INVALID | PEDTYPE_MISSION)
INT i = 0
REPEAT COUNT_OF(pedArray) i
IF DOES_ENTITY_EXIST(pedArray[i]) AND NOT IS_PED_INJURED(pedArray[i])
SET_ENTITY_AS_MISSION_ENTITY(pedArray[i])
TASK_TURN_PED_TO_FACE_ENTITY(pedArray[i], PLAYER_PED_ID(), -1)
TASK_LOOK_AT_ENTITY(pedArray[i], PLAYER_PED_ID(), -1, SLF_USE_TORSO | SLF_EXTEND_YAW_LIMIT)
ENDIF
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER HELPER PROCS/FUNCTIONS
// -----------------------------------
// TODO: Make following Racer function follow above scheme...
PROC SPTT_Race_Racer_Start(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Racer_Start")
TEXT_LABEL OffroadRecording = "Offroad_"
OffroadRecording += (SPTT_Master.iRaceCur+1)
// Start race clock.
RESTART_TIMER_NOW(Race.tClock)
Race.Racer[0].fPlsMnsTot = 0//no bonus time!
iHUDDisplayBonusTracker = 0
// Give back player control.
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
IF (SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE)
SET_PLAYER_INVINCIBLE(PLAYER_ID(), TRUE)
ENDIF
Race.bFailChecking = TRUE
DEBUG_MESSAGE("SPTT_Race_Racer_Start: Race.bFailChecking set to TRUE")
RESTART_TIMER_NOW(manualResetTimer)
DEBUG_MESSAGE("RACE_RACER_START: FAILCHECKING: ON")
// Loop through all racers and start them.
INT i
REPEAT Race.iRacerCnt i
// Start racer.
SPTT_Racer_Start(Race.Racer[i])
IF SPTT_Master.eRaceType <> SPTT_RACE_TYPE_OFFROAD
// TODO: Put any player specific logic here...
IF i != 0 //not the player!?
SPTT_Race_Racer_Task_Go_To_Next_Gate(Race, Race.Racer[i].Driver, Race.Racer[i].Vehicle, Race.sGate[Race.Racer[i].iGateCur].vPos, Race.sGate[Race.Racer[i].iGateCur].eChkpntType, i)
ENDIF
ELSE
IF SPTT_USE_WAYPOINT_RECORDING
// Task AI to follow waypoint recording for offroad race
// Pick random waypoint recording to start
IF i > 0
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
AND NOT IS_ENTITY_DEAD(Race.Racer[i].Vehicle)
IF i = 1 AND SPTT_Master.iRaceCur = 0
OffroadRecording += "a"
ENDIF
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(Race.Racer[i].Driver, Race.Racer[i].Vehicle, OffroadRecording, DRIVINGMODE_PLOUGHTHROUGH, 0, EWAYPOINT_START_FROM_CLOSEST_POINT, -1, GET_VEHICLE_ESTIMATED_MAX_SPEED(Race.Racer[i].Vehicle))
ENDIF
ENDIF
ELSE
IF i != 0 //not the player!?
SPTT_Race_Racer_Task_Go_To_Next_Gate(Race, Race.Racer[i].Driver, Race.Racer[i].Vehicle, Race.sGate[Race.Racer[i].iGateCur].vPos, Race.sGate[Race.Racer[i].iGateCur].eChkpntType, i)
ENDIF
ENDIF
ENDIF
ENDREPEAT
IF IS_VEHICLE_DRIVEABLE(Race.Racer[0].Vehicle)
SET_VEHICLE_RADIO_ENABLED(Race.Racer[0].Vehicle, TRUE)
IF NOT IS_STRING_NULL_OR_EMPTY(sRadStation)
SET_RADIO_TO_STATION_NAME(sRadStation)
SET_VEH_RADIO_STATION(Race.Racer[0].Vehicle, sRadStation)
DEBUG_MESSAGE("SPTT_Race_Racer_Start: SET_VEH_RADIO_STATION")
ENDIF
ENDIF
ENDPROC
PROC AI_End_Of_Race_Stop(SPTT_RACE_STRUCT& Race)
INT i
REPEAT Race.iRacerCnt i
IF i > 0
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
AND NOT IS_ENTITY_DEAD(Race.Racer[i].Vehicle)
IF SPTT_Master.eRaceType <> SPTT_RACE_TYPE_TRIATHLON
TASK_VEHICLE_TEMP_ACTION(Race.Racer[i].Driver,Race.Racer[i].Vehicle, TEMPACT_HANDBRAKETURNRIGHT, 5000)
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Finish(SPTT_RACE_STRUCT& Race)
//PRINTLN("[SPTT_Race.sch->SPTT_Race_Racer_Finish] Procedure started.")
// Pause race clock, if needed.
IF NOT IS_TIMER_PAUSED(Race.tClock)
PAUSE_TIMER(Race.tClock)
ENDIF
SET_ENTITY_INVINCIBLE(Race.Racer[0].Vehicle, TRUE)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
SPTT_Race_ClockTime_SimAI(Race)
// Calculate final race ranks.
IF SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE
SPTT_Race_Rank_CalcFinal(Race)
ENDIF
// Find player best rank and clock time.
SPTT_Race_RankClock_FindPlayerBest(Race)
// Loop through all racers and finish them.
INT iLoopCounter
REPEAT Race.iRacerCnt iLoopCounter
SPTT_Racer_Finish(Race.Racer[iLoopCounter])
IF iLoopCounter <> 0
FINISH_AI_RACERS(Race.Racer[iLoopCounter])
ENDIF
ENDREPEAT
ENDPROC
PROC SPTT_Race_Racer_Gate_Jump(SPTT_RACE_STRUCT& Race, INT iRacer, INT iGate, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump")
IF (iGate < 0) OR (iGate > (Race.iGateCnt - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump: Gate index out of range!")
EXIT
ENDIF
IF (iRacer < 0) OR (iRacer > (Race.iRacerCnt - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump: Racer index out of range!")
EXIT
ENDIF
// TODO: Decide if this is the right error checking needed...
IF IS_ENTITY_DEAD(Race.Racer[iRacer].Driver)
EXIT
ENDIF
IF (Race.Racer[iRacer].eVehicleModel <> DUMMY_MODEL_FOR_SCRIPT)
IF IS_ENTITY_DEAD(Race.Racer[iRacer].Vehicle)
EXIT
ENDIF
ENDIF
VECTOR vFwd = Race.sGate[iGate + 1].vPos - Race.sGate[iGate].vPos
FLOAT fHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
FLOAT fSpeed = 0.0
IF IS_THIS_MODEL_A_BIKE(Race.Racer[iRacer].eVehicleModel)
fSpeed = 0.0
ELIF IS_THIS_MODEL_A_CAR(Race.Racer[iRacer].eVehicleModel)
fSpeed = 25.0
ELIF IS_THIS_MODEL_A_PLANE(Race.Racer[iRacer].eVehicleModel)
fSpeed = SPTT_PLANE_SPD_MAX
ENDIF
IF bBlockLoad
PRINTLN("[SPTT_Race_Racer_Gate_Jump] Loading scene from gate jumping. This is NOT a new load scene.")
//LOAD_SCENE(Race.sGate[iGate].vPos)
ENDIF
SPTT_Racer_Teleport(Race.Racer[iRacer], Race.sGate[iGate].vPos, fHeading, fSpeed)
ENDPROC
PROC SPTT_Race_Racer_Gate_Jump_Cur(SPTT_RACE_STRUCT& Race, INT iRacer, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump_Cur")
SPTT_Race_Racer_Gate_Jump(Race, iRacer, Race.Racer[iRacer].iGateCur, bBlockLoad)
ENDPROC
PROC SPTT_Race_Racer_Gate_Jump_Nxt(SPTT_RACE_STRUCT& Race, INT iRacer, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump_Nxt")
SPTT_Race_Racer_Gate_Jump(Race, iRacer, Race.Racer[iRacer].iGateCur - 1, bBlockLoad)
ENDPROC
PROC SPTT_Race_Racer_Gate_Jump_Last(SPTT_RACE_STRUCT& Race, INT iRacer, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump_Last")
Race.Racer[iRacer].iGateCur = Race.iGateCnt-1
SPTT_Race_Racer_Gate_Jump(Race, iRacer, Race.iGateCnt-1, bBlockLoad)
ENDPROC
PROC SPTT_Race_Racer_Gate_Jump_Penultimate(SPTT_RACE_STRUCT& Race, INT iRacer, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("SPTT_Race_Racer_Gate_Jump_Last")
Race.Racer[iRacer].iGateCur = Race.iGateCnt-3
SPTT_Race_Racer_Gate_Jump(Race, iRacer, Race.iGateCnt-3, bBlockLoad)
ENDPROC
PROC SPTT_Race_Racer_Rank_Calc(SPTT_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("SPTT_Race_Racer_Rank_Calc")
IF (iRacer < 0) OR (iRacer > (Race.iRacerCnt - 1))
DEBUG_MESSAGE("SPTT_Race_Racer_Rank_Calc: Racer index out of range!")
EXIT
ENDIF
INT nRank = Race.iRacerCnt
INT i
SPTT_RACER_STRUCT tmpRacer = Race.Racer[iRacer]
REPEAT Race.iRacerCnt i
//skip ourselves
IF tmpRacer.Driver <> Race.Racer[i].Driver
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver) AND NOT IS_ENTITY_DEAD(tmpRacer.Driver)
IF tmpRacer.iGateCur > Race.Racer[i].iGateCur
nRank--
ELIF tmpRacer.iGateCur = Race.Racer[i].iGateCur
//same checkpoint lets get the distance to the next checkpoint
FLOAT ourRacer, evilRacer
ourRacer = GET_ENTITY_DISTANCE_FROM_LOCATION(tmpRacer.Driver, Race.sGate[tmpRacer.iGateCur].vPos)
evilRacer = GET_ENTITY_DISTANCE_FROM_LOCATION(Race.Racer[i].Driver, Race.sGate[Race.Racer[i].iGateCur].vPos)
IF ourRacer < evilRacer
nRank--
ENDIF
ENDIF
ELSE
nRank--
ENDIF
ENDIF
ENDREPEAT
Race.Racer[iRacer].iRank=nRank
ENDPROC
PROC SPTT_Race_Racer_Fix_Up_Start(VECTOR vCurGatePos1, VEHICLE_INDEX iPlaneIndex, VECTOR vCurGatePos, BOOL bIsStart)
PRINTLN("[SPTT_Race_Racer_Fix_Up_Start] Procedure called.")
IF NOT IS_ENTITY_DEAD(iPlaneIndex)
FLOAT fHeading
FLOAT fPitch
// FLOAT fPitchRad
VECTOR vRotation
VECTOR vPlayersPlaneCurrentPos
VECTOR vGateDiff
// Stuntplane minimum hard deck check
FLOAT fHardDeckGround
VECTOR vHardDeckProbe
//1524715
//special case for bridge binge because it doesn't teleport player at beginning
//...first gate in bad restart position
IF bIsStart
AND INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge
SET_ENTITY_COORDS(iPlaneIndex, <<1705.0386, 3251.1299, 40.0016>>)
PRINTLN("Resetting at the beginning of bridge binge so using special coords")
ENDIF
vHardDeckProbe = GET_ENTITY_COORDS(iPlaneIndex)
REQUEST_COLLISION_AT_COORD(vHardDeckProbe)
GET_GROUND_Z_FOR_3D_COORD(vHardDeckProbe, fHardDeckGround)
PRINTSTRING("Ground Height is: ")
PRINTFLOAT(fHardDeckGround)
PRINTNL()
vPlayersPlaneCurrentPos = GET_ENTITY_COORDS(iPlaneIndex)
// PRINTSTRING("vPlayersPlaneCurrentPos is: ")
// PRINTVECTOR(vPlayersPlaneCurrentPos)
// PRINTNL()
IF bIsStart
DEBUG_MESSAGE("iGateCur = 0 using vCurGatePos for vGateDiff")
vGateDiff = vCurGatePos1 - vCurGatePos
ELSE
DEBUG_MESSAGE("iGateCur != 0 using regular diff")
vGateDiff = vCurGatePos - vPlayersPlaneCurrentPos
ENDIF
fHeading = GET_HEADING_FROM_VECTOR_2D(vGateDiff.x, vGateDiff.y)
// PRINTSTRING("fHeading is: ")
// PRINTFLOAT(fHeading)
// PRINTNL()
fPitch = GET_HEADING_FROM_VECTOR_2D(vGateDiff.x, vGateDiff.z)-270
PRINTSTRING("fPitch is: ")
PRINTFLOAT(fPitch)
PRINTNL()
WHILE fPitch > 180
fPitch -= 360
ENDWHILE
WHILE fPitch < -180
fPitch += 360
ENDWHILE
IF fPitch < -90
fPitch = -(180-ABSF(fPitch))
ENDIF
IF fPitch > 90
fPitch = (180-ABSF(fPitch))
ENDIF
PRINTSTRING("fPitch is: ")
PRINTFLOAT(fPitch)
PRINTNL()
IF ( ABSF(vHardDeckProbe.z - fHardDeckGround) < 25.0 )
AND ( (fPitch > 15) OR (fPitch < -15) )
vHardDeckProbe.z = fHardDeckGround + 25.0
SET_ENTITY_COORDS(iPlaneIndex, vHardDeckProbe)
PRINTSTRING("MOVING PLAYER'S PLANE 25 METERS ABOVE THE GROUND")
PRINTNL()
// ELSE
// PRINTSTRING("Player is already this many meters above the ground: !")
// PRINTFLOAT(ABSF(vHardDeckProbe.z - fHardDeckGround))
// PRINTNL()
ENDIF
FREEZE_ENTITY_POSITION(iPlaneIndex, TRUE)
vRotation = GET_ENTITY_ROTATION(iPlaneIndex)
vRotation.x = fPitch //we may not want to set this if the next gate is lower than the restart position and is close (hit the ground a lot)...that or set it to a portion of the pitch, using height delta and distance delta as the ratio
vRotation.z = fHeading
SET_ENTITY_ROTATION(iPlaneIndex, vRotation)
FREEZE_ENTITY_POSITION(iPlaneIndex, FALSE)
PRINTSTRING("GET_ENTITY_PITCH is: ")
PRINTFLOAT(GET_ENTITY_PITCH(iPlaneIndex))
PRINTNL()
NEW_LOAD_SCENE_START(vHardDeckProbe, GET_ENTITY_FORWARD_VECTOR(iPlaneIndex), 500.0)
PRINTLN("[SPTT_Race_Racer_Fix_Up_Start] Starting new load scene at hard deck probe: ", vHardDeckProbe)
ENDIF
ENDPROC
/// PURPOSE:
/// Reset SPR Race Racer.
/// RETURNS:
/// TRUE if resetting SPR Race Racer.
FUNC BOOL SPTT_Race_Racer_Reset(SPTT_RACE_STRUCT& Race, SPTT_RACER_STRUCT& Racer, BOOL bRacerIsPlayer)
//PRINTLN("[SPTT_Race_Racer_Reset] Function started.")
// Reset Racer State Machine.
SWITCH (Racer.eReset)
// Failcase PLAYER HAS FORFEITED RACE
CASE SPTT_RACER_RESET_FAIL_OVER
SPTT_Race_Gate_Deactivate_All(Race)
SPTT_RACE_CLEANUP_FINISH_STREAMVOL()
INIT_SIMPLE_USE_CONTEXT(SPTT_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(SPTT_Master.uiInput, "IB_RETRY", FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
ADD_SIMPLE_USE_CONTEXT_INPUT(SPTT_Master.uiInput, "FE_HLP16", FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
SET_MINIGAME_SPLASH_SHOWING(TRUE)
TRIGGER_MUSIC_EVENT("MGSP_FAIL")
Racer.eReset = SPTT_RACER_RESET_FAIL_EFFECTS
BREAK
CASE SPTT_RACER_RESET_FAIL_EFFECTS
IF MG_UPDATE_FAIL_FADE_EFFECT(SPTT_Master.failFadeEffect, SPTT_Master.failSplash, Race.bigMessageUI, spttFailString, spttFailStrapline, Race.bRestarting)
bTriggerFirstMusicEvent = FALSE
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
SET_VEHICLE_DOORS_LOCKED(Race.Racer[0].Vehicle, VEHICLELOCK_LOCKED_PLAYER_INSIDE)
ENDIF
IF IS_THIS_PRINT_BEING_DISPLAYED("SPR_HELP_DAMG")
CLEAR_THIS_PRINT("SPR_HELP_DAMG")
ENDIF
PRINTLN("SPTT_RACER_RESET_FAIL_OVER Race.bFailChecking = FALSE ")
Race.bFailChecking = FALSE
MG_INIT_FAIL_FADE_EFFECT(SPTT_Master.failFadeEffect, TRUE)
// Setup Scaleform UI for reset/restart.
// SHOULDN'T BE CALLING SETUP AND UPDATE EVERY FRAME. SETUP ONCE, UPDATE EVERY FRAME.
//SET_SCALEFORM_BIG_MESSAGE(Race.bigMessageUI, spttFailString, spttFailStrapline, -1, HUD_COLOUR_RED, DEFAULT, TRUE, 0.15)
//Racer.eReset = SPTT_RACER_RESET_FAIL_SELECT_RETRY
IF Race.bRestarting
//cleanup fail effects
MG_DO_FAIL_EFFECT(FALSE)
MG_DO_FAIL_OUT_EFFECT(FALSE)
MG_RESET_FAIL_EFFECT_VARS()
//iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_02", iButtonSounds, FALSE)
//PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
//kill the chase came so if we were looking at
//it when we reset the camera is still not looking at it.
IF IS_THIS_PRINT_BEING_DISPLAYED("SPR_RETR_DES")
CLEAR_THIS_PRINT("SPR_RETR_DES")
ENDIF
// This command also sets the cinematic cam back to true, so turning off for Tri.
// KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
SET_MINIGAME_SPLASH_SHOWING(FALSE)
Race.bRestarting = TRUE
Racer.eReset = SPTT_RACER_RESET_FADE_OUT
ELSE
//cleanup fail effects
MG_DO_FAIL_EFFECT(FALSE)
MG_DO_FAIL_OUT_EFFECT(FALSE)
MG_RESET_FAIL_EFFECT_VARS()
//iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_03", iButtonSounds, FALSE)
//PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_03", "HUD_MINIGAME_SOUNDSET")
// Kill the chase cam in case it's being used.
// This command also sets the cinematic cam back to true, so turning off for Tri.
// KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
DEBUG_MESSAGE("[SPTT_Race->SPTT_Race_Racer_Reset] CASE SPTT_RACER_RESET_FAIL_OVER: CASE GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_Y): eReset = SPTT_RACER_QUIT_FADE_OUT")
ADJUST_TIMER(exitTimer, 10.0)
SET_MINIGAME_SPLASH_SHOWING(FALSE)
Race.bRestarting = FALSE
Racer.eReset = SPTT_RACER_QUIT_FADE_OUT
ENDIF
ENDIF
BREAK
// DEPRECATED. New fail screen handles this in the SPTT_RACER_RESET_FAIL_EFFECTS, just above.
CASE SPTT_RACER_RESET_FAIL_SELECT_RETRY
PRINTLN("updating retry screen")
/*
SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_FADE)
UPDATE_SCALEFORM_BIG_MESSAGE(Race.bigMessageUI)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_CIN_CAM)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_NEXT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_PREV_WEAPON)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_STREET_NAME)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_AREA_NAME)
*/
UPDATE_SIMPLE_USE_CONTEXT(SPTT_Master.uiInput, DEFAULT, GFX_ORDER_AFTER_FADE, TRUE)
IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
//cleanup fail effects
MG_DO_FAIL_EFFECT(FALSE)
MG_DO_FAIL_OUT_EFFECT(FALSE)
MG_RESET_FAIL_EFFECT_VARS()
iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_02", iButtonSounds, FALSE)
PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
//kill the chase came so if we were looking at
//it when we reset the camera is still not looking at it.
IF IS_THIS_PRINT_BEING_DISPLAYED("SPR_RETR_DES")
CLEAR_THIS_PRINT("SPR_RETR_DES")
ENDIF
// This command also sets the cinematic cam back to true, so turning off for Tri.
// KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
SET_MINIGAME_SPLASH_SHOWING(FALSE)
Race.bRestarting = TRUE
Racer.eReset = SPTT_RACER_RESET_FADE_OUT
ELIF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
//cleanup fail effects
MG_DO_FAIL_EFFECT(FALSE)
MG_DO_FAIL_OUT_EFFECT(FALSE)
MG_RESET_FAIL_EFFECT_VARS()
iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_03", iButtonSounds, FALSE)
PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_03", "HUD_MINIGAME_SOUNDSET")
// Kill the chase cam in case it's being used.
// This command also sets the cinematic cam back to true, so turning off for Tri.
// KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
DEBUG_MESSAGE("[SPTT_Race->SPTT_Race_Racer_Reset] CASE SPTT_RACER_RESET_FAIL_OVER: CASE GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_Y): eReset = SPTT_RACER_QUIT_FADE_OUT")
ADJUST_TIMER(exitTimer, 10.0)
SET_MINIGAME_SPLASH_SHOWING(FALSE)
Race.bRestarting = FALSE
Racer.eReset = SPTT_RACER_QUIT_FADE_OUT
ENDIF
BREAK
// Reset racer (init). NOTE: Check if this ever used.
CASE SPTT_RACER_RESET_INIT
IF Race.bRestarting = TRUE
Race.bFailChecking = FALSE
DEBUG_MESSAGE("SPTT_RACER_RESET_INIT: Race.bFailChecking set to FALSE")
ENDIF
// Overwrite racer start pos with current gate pos.
IF Racer.iGateCur > 0
Racer.vStartPos = Race.sGate[Racer.iGateCur].vPos
ENDIF
// Setup Scaleform UI for reset/restart.
IF bRacerIsPlayer
// Write something to put the player into the vehicle
IF IS_VEHICLE_DRIVEABLE(Race.Racer[0].Vehicle)
SET_PLAYER_INVINCIBLE(PLAYER_ID(), TRUE)
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
INIT_SIMPLE_USE_CONTEXT(SPTT_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(SPTT_Master.uiInput, "SPR_UI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
ADD_SIMPLE_USE_CONTEXT_INPUT(SPTT_Master.uiInput, "IB_NO", FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
ENDIF
ENDIF
// If racer is player, go to choose state.
IF bRacerIsPlayer
// Write something to put the player into the vehicle
IF IS_VEHICLE_DRIVEABLE(Race.Racer[0].Vehicle)//NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
//IF NOT IS_PED_IN_VEHICLE(Race.Racer[0].Driver, Race.Racer[0].Vehicle)
// SET_PED_INTO_VEHICLE(Race.Racer[0].Driver, Race.Racer[0].Vehicle, VS_DRIVER)
// SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)//, SPC_ALLOW_PLAYER_DAMAGE)
DEBUG_MESSAGE("Moving to SPTT_RACER_RESET_CHOOSE")
Racer.eReset = SPTT_RACER_RESET_CHOOSE
//ENDIF
ENDIF
ELSE // Otherwise, racer is ai, go to create state.
DEBUG_MESSAGE("Moving to SPTT_RACER_RESET_CREATE")
Racer.eReset = SPTT_RACER_RESET_CREATE
ENDIF
BREAK
// Choose reset/restart.
CASE SPTT_RACER_RESET_CHOOSE
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
SET_VEHICLE_DOORS_LOCKED(Race.Racer[0].Vehicle, VEHICLELOCK_LOCKED_PLAYER_INSIDE)
ENDIF
Race.bFailChecking = FALSE
// DEBUG_MESSAGE("SPTT_RACER_RESET_CHOOSE - Race.bFailChecking = FALSE")
IF (GET_TIMER_IN_SECONDS(exitTimer) <= 10.0)
// If racer is player, display reset/restart options.
IF bRacerIsPlayer
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_STREET_NAME)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_AREA_NAME)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_NEXT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_PREV_WEAPON)
UPDATE_SIMPLE_USE_CONTEXT(SPTT_Master.uiInput)
IF IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
Race.bRestarting = TRUE
DEBUG_MESSAGE("Moving to SPTT_RACER_RESET_FADE_OUT")
iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_02", iButtonSounds, FALSE)
PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
Racer.eReset = SPTT_RACER_RESET_FADE_OUT
//kill the chase came so if we were looking at
//it when we reset the camera is still not looking at it.
ELIF IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
Race.bRestarting = FALSE
//kill the chase came so if we were looking at
//it when we reset the camera is still not looking at it.
// KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
DEBUG_MESSAGE("Moving to SPTT_RACER_QUIT_FADE_OUT")
ADJUST_TIMER(exitTimer, 10.0)
iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_03", iButtonSounds, FALSE)
PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_03", "HUD_MINIGAME_SOUNDSET")
Racer.eReset = SPTT_RACER_RESET_FADE_OUT
ENDIF
ENDIF
ELSE
CLEAR_PRINTS()
//changing big message for b* 1366955
spttFailStrapline = "SPR_RETR_DES"
MG_INIT_FAIL_FADE_EFFECT(SPTT_Master.failFadeEffect, TRUE)
//SET_SCALEFORM_BIG_MESSAGE(Race.bigMessageUI, spttFailString, spttFailStrapline, -1, HUD_COLOUR_RED, DEFAULT, TRUE, 0.15)
Racer.eReset = SPTT_RACER_QUIT_EXIT
ENDIF
BREAK
// Fade out screen to black.
CASE SPTT_RACER_RESET_FADE_OUT
IF SPTT_FadeOut_Safe(SPTT_FADE_QUICK_TIME)
CLEAR_PRINTS()
CLEAR_HELP()
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_FADE_OUT: Screen done fading OUT. Racer.eReset = SPTT_RACER_RESET_CREATE.")
Racer.eReset = SPTT_RACER_RESET_CREATE
ELSE
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_FADE_OUT: Fading out screen...")
ENDIF
BREAK
// Fade out from quitting race.
CASE SPTT_RACER_QUIT_FADE_OUT
IF IS_TIMER_STARTED(Race.tClock)
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_QUIT_FADE_OUT: Cancel the clock timer.")
CANCEL_TIMER(Race.tClock)
ENDIF
IF MG_DO_FAIL_BLUR_EFFECT()
IF IS_SCREEN_FADED_OUT()
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_QUIT_FADE_OUT: The screen has faded out. Disabling player control and deactivating all gates.")
SPTT_Race_Gate_Deactivate_All(Race)
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
IF DOES_ENTITY_EXIST(Race.Racer[0].Vehicle)
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_QUIT_FADE_OUT: Stop the plane and replenish its health.")
SET_ENTITY_VELOCITY(Race.Racer[0].Vehicle, <<0, 0, 0>>)
SET_ENTITY_HEALTH(Race.Racer[0].Vehicle, GET_ENTITY_MAX_HEALTH(Race.Racer[0].Vehicle))
ENDIF
DEBUG_MESSAGE("[SPTT_Race_Racer_Reset] SPTT_RACER_QUIT_FADE_OUT: Racer.eReset = SPTT_RACER_QUIT_PLACE.")
Racer.eReset = SPTT_RACER_QUIT_PLACE
ENDIF
ENDIF
BREAK
// Create the racer's driver and vehicle.
CASE SPTT_RACER_RESET_CREATE
IF SPTT_Racer_Create(Racer, TRUE)
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_CREATE: Racer created.")
IF Race.bRestarting
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_CREATE: Trial is restarting. Race.eUpdate = SPTT_RACE_UPDATE_CLEANUP.")
Race.eUpdate = SPTT_RACE_UPDATE_CLEANUP
ELSE
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_CREATE: Trial is NOT restarting.")
// ???: I wonder if we need to enable control this early since the screen is still faded out. And do we need to check bRacerIsPlayer?
//give back the player control here so they don't drop out of the sky
IF bRacerIsPlayer
// Give back player control.
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
IF (SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE)
SET_PLAYER_INVINCIBLE(PLAYER_ID(), TRUE)
ENDIF
ENDIF
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_CREATE: Racer.eReset = SPTT_RACER_RESET_PLACE.")
Racer.eReset = SPTT_RACER_RESET_PLACE
ENDIF
ELSE
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_CREATE: Racer not yet created.")
ENDIF
BREAK
// Place racer during fade out.
CASE SPTT_RACER_RESET_PLACE
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_PLACE: Case entered.")
// ???: Why are we doing this?
INT i
REPEAT Race.iRacerCnt i
IF (Race.Racer[i].Driver = Racer.Driver)
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_PLACE: Teleport this racer to the next checkpoint... because YES?")
SPTT_Race_Racer_Gate_Jump_Nxt(Race, i)
ENDIF
ENDREPEAT
IF bRacerIsPlayer
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
AND (Race.Racer[0].iGateCur != -1)
SPTT_Race_Racer_Fix_Up_Start(Race.sGate[Race.Racer[0].iGateCur+1].vPos, Race.Racer[0].Vehicle, Race.sGate[Race.Racer[0].iGateCur].vPos, (Race.Racer[0].iGateCur = 0))
ENDIF
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
PRINTLN("[SPTT_Race.sch->SPTT_Race_Racer_Reset] From SPTT_RACER_RESET_PLACE to SPTT_RACER_RESET_FADE_IN.")
RESTART_TIMER_NOW(manualResetTimer)
Racer.eReset = SPTT_RACER_RESET_FADE_IN
ELSE // Otherwise, racer is ai, go to wait state.
PRINTLN("[SPTT_Race.sch->SPTT_Race_Racer_Reset] From SPTT_RACER_RESET_PLACE to SPTT_RACER_RESET_WAIT.")
Racer.eReset = SPTT_RACER_RESET_WAIT
ENDIF
BREAK
// Return the player and vehicle to the main menu.
CASE SPTT_RACER_QUIT_PLACE
// Cleanup fail effects.
MG_DO_FAIL_EFFECT(FALSE)
MG_DO_FAIL_OUT_EFFECT(FALSE)
// Reset vehicle here.
SPTT_Racer_Vehicle_Create(Racer, TRUE)
// Return the player to the hangar, where the main menu will be.
SPTT_Racer_Teleport(Racer, SPTT_Master.vDefRcrPos, SPTT_Master.fDefRcrHead, 0.0)
SETTIMERA(0)
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_QUIT_PLACE: Racer.eReset=SPTT_RACER_QUIT_FADE_IN")
Racer.eReset=SPTT_RACER_QUIT_FADE_IN
BREAK
// Fade in.
CASE SPTT_RACER_RESET_FADE_IN
IF NOT IS_NEW_LOAD_SCENE_ACTIVE()
OR IS_NEW_LOAD_SCENE_LOADED()
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_FADE_IN: NEW_LOAD_SCENE_START has loaded.")
Race.bFailChecking = TRUE
DEBUG_MESSAGE("SPTT_RACER_RESET_FADE_IN: Race.bFailChecking set to TRUE")
RESTART_TIMER_NOW(manualResetTimer)
SPTT_Racer_AutoPilot(Race.Racer[i], SPTT_PLANE_SPD_MAX, FALSE)
IF SPTT_FadeIn_Safe(SPTT_FADE_QUICK_TIME)
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_FADE_IN: Faded in, so stop scene from loading.")
NEW_LOAD_SCENE_STOP()
DEBUG_MESSAGE("RACER_RESET_FADE_IN: FAILCHECKING: ON")
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
SET_PED_INTO_VEHICLE(Race.Racer[0].Driver, Race.Racer[0].Vehicle, VS_DRIVER)
ENDIF
DEBUG_MESSAGE("Going to RESET_WAIT from QUIT_FADE_IN")
IF bRacerIsPlayer AND SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE
SPTT_Racer_ClockTime_Penalty(Race.Racer[0], SPTT_GATE_MISS_PENALTY)
ENDIF
Racer.eReset = SPTT_RACER_RESET_WAIT
ENDIF
// Reset SPR Racer waiting.
RETURN FALSE
ELSE
IF IS_NEW_LOAD_SCENE_ACTIVE()
IF Race.Racer[0].iGateCur < Race.iGateCnt
IF IS_TIMER_STARTED(manualResetTimer)
IF GET_TIMER_IN_SECONDS_SAFE(manualResetTimer) >= 3.0
NEW_LOAD_SCENE_STOP()
ENDIF
ELSE
START_TIMER_NOW_SAFE(manualResetTimer)
ENDIF
PRINTLN("GET_TIMER_IN_SECONDS_SAFE(manualResetTimer) is...", GET_TIMER_IN_SECONDS_SAFE(manualResetTimer))
ENDIF
ENDIF
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_RESET_FADE_IN: New scene is active or new scene has not loaded. Waiting otherwise.")
ENDIF
BREAK
CASE SPTT_RACER_QUIT_FADE_IN
PRINTLN("[SPTT_Race_Racer_Reset] SPTT_RACER_QUIT_FADE_IN: Race.eUpdate = SPTT_RACE_UPDATE_CLEANUP. Returning FALSE.")
Race.eUpdate = SPTT_RACE_UPDATE_CLEANUP
RETURN FALSE
BREAK
// Reset racer (wait).
CASE SPTT_RACER_RESET_WAIT
// If racer crashed, go to init state.
IF Racer.eVehicleModel <> DUMMY_MODEL_FOR_SCRIPT
IF NOT IS_ENTITY_DEAD(Racer.Driver)
IF SPTT_Racer_Stuck_Check(Racer)
// OR ( NOT IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) AND (SPTT_Master.eRaceType != SPTT_RACE_TYPE_OFFROAD) )
DEBUG_MESSAGE("Player isn't in the vehicle, moving to SPTT_RACER_RESET_INIT")
RESTART_TIMER_NOW(exitTimer)
spttFailStrapline = "SPR_RETR_STUK"
Racer.eReset = SPTT_RACER_RESET_FAIL_OVER
RETURN TRUE
ENDIF
ENDIF
ENDIF
// Reset SPR Racer waiting.
RETURN FALSE
CASE SPTT_RACER_QUIT_EXIT
SPTT_Race_Gate_Deactivate_All(Race)
CANCEL_TIMER(Race.tClock)
Race.eUpdate = SPTT_RACE_UPDATE_CLEANUP
BREAK
ENDSWITCH
// Reset SPR Racer running.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Update SPR Race Racers.
/// RETURNS:
/// TRUE if still updating SPR Race Racers.
FUNC BOOL SPTT_Race_Racer_Update(SPTT_RACE_STRUCT& Race, SPTT_RACE_TYPE_ENUM eRaceType)
//DEBUG_MESSAGE("SPTT_Race_Racer_Update")
// TODO: Break this into a function called for each racer,
// then make this function call that in a loop......
// Local variables.
FLOAT fClockTime
INT i
IF INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge
//if we're on bridge binge, dont update until after the first gate
IF Race.Racer[0].iGateCur = 0
RESTART_TIMER_NOW(Race.tClock)
IF IS_BITMASK_AS_ENUM_SET(SPTT_HELP_BIT, SPTT_RESET_INFO)
RESET_VEHICLE_STUCK_TIMER(Race.Racer[0].Vehicle, VEH_STUCK_RESET_ALL)
CLEAR_BITMASK_AS_ENUM(SPTT_HELP_BIT, SPTT_RESET_INFO)
ENDIF
ELIF Race.Racer[0].iGateCur = 1 AND NOT IS_BITMASK_AS_ENUM_SET(SPTT_HELP_BIT, SPTT_RESET_INFO)
PRINT_HELP("SPR_INFO_BON", DEFAULT_HELP_TEXT_TIME)
SET_BITMASK_AS_ENUM(SPTT_HELP_BIT, SPTT_RESET_INFO)
IF IS_BITMASK_AS_ENUM_SET(SPTT_HELP_BIT, SPTT_TIME_INFO)
CLEAR_BITMASK_AS_ENUM(SPTT_HELP_BIT, SPTT_TIME_INFO)
ENDIF
ELIF Race.Racer[0].iGateCur = 4 AND NOT IS_BITMASK_AS_ENUM_SET(SPTT_HELP_BIT, SPTT_TIME_INFO)
PRINT_HELP("SPR_INFO_RESET", DEFAULT_HELP_TEXT_TIME)
SET_BITMASK_AS_ENUM(SPTT_HELP_BIT, SPTT_TIME_INFO)
ENDIF
ENDIF
// Cache current race clock time.
IF IS_TIMER_STARTED(Race.tClock)
fClockTime = GET_TIMER_IN_SECONDS(Race.tClock)
ENDIF
SPTT_Race_Manage_Race_Beats(Race.Racer[0].iGateCur, Race.bFailChecking)
//IF Race.bFailChecking
//CDEBUG3LN(DEBUG_MISSION, " - sptt_race - SPPT_Race_Racer_Update - SET_INPUT_EXCLUSIVE (PLAYER_CONTROL, INPUT_SCRIPT_RUP)")
//SET_INPUT_EXCLUSIVE (PLAYER_CONTROL, INPUT_SCRIPT_RUP) // B*2259751 // INPUT_SCRIPT_RUP
//ELSE
//CDEBUG3LN(DEBUG_MISSION, " - sptt_race - SPPT_Race_Racer_Update - Race.bFailChecking = FALSE")
//ENDIF
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT) // B* 2259751 & 2275136
// Loop through all racers and update them.
REPEAT Race.iRacerCnt i
// Don't update racers that already finished the race. (or racers that are dead)
IF (Race.Racer[i].iGateCur < Race.iGateCnt)
SPTT_GATE_STRUCT GateCur, GateNxt
INT iGateCur
// Check if racer is player and update Scaleform UI, if needed.
BOOL bRacerIsPlayer = FALSE
IF (Race.Racer[i].Driver = PLAYER_PED_ID())
bRacerIsPlayer = TRUE
ENDIF
// Cache current index and cur/next gates.
iGateCur = Race.Racer[i].iGateCur
IF (Race.Racer[i].iGateCur >= Race.iGateCnt)
GateCur = Race.sGate[Race.iGateCnt-1]
ELSE
GateCur = Race.sGate[iGateCur]
ENDIF
IF (iGateCur < (Race.iGateCnt-1))
GateNxt = Race.sGate[iGateCur + 1]
ELSE
GateNxt = GateCur
ENDIF
// Udpate racer clock time (account for plus/minus) (clamp negatives).
IF iGateCur <> Race.iGateCnt
Race.Racer[i].fClockTime = fClockTime - Race.Racer[i].fPlsMnsTot
IF (Race.Racer[i].fClockTime < 0.0)
Race.Racer[i].fClockTime = 0.0
ENDIF
ENDIF
// Make sure racer isn't resetting before continuing.
IF NOT SPTT_Race_Racer_Reset(Race, Race.Racer[i], bRacerIsPlayer)
// Moved this RESET stuff here so it's only checked when we're not already resetting
// Vehicle water check
IF bRacerIsPlayer
AND Race.bFailChecking
AND (INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) != SPTT_BridgeBinge OR Race.Racer[0].iGateCur > 0)
/// RACE RESET CHECK
IF NOT IS_TIMER_STARTED(resetTimer)
START_TIMER_NOW(resetTimer)
DEBUG_MESSAGE("Started reset Timer")
ENDIF
// Manual Reset
IF (GET_TIMER_IN_SECONDS(manualResetTimer) >= 6.5)
IF NOT IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_SCRIPT_RUP)
RESTART_TIMER_NOW(resetTimer)
ELIF (GET_TIMER_IN_SECONDS(resetTimer) >= 1.5)
Race.bFailChecking = FALSE
DEBUG_MESSAGE("Player pressed down, resetting...")
CLEAR_BITMASK_AS_ENUM(SPTT_HELP_BIT, SPTT_RESET_HELP)
Race.Racer[0].eReset = SPTT_RACER_RESET_FADE_OUT
ENDIF
ELSE
// Player has restarted recently, tell them why they cant restart
IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_SCRIPT_RUP)
DEBUG_MESSAGE("Race clock is currently: ")
PRINTFLOAT(GET_TIMER_IN_SECONDS(Race.tClock))
PRINTNL()
IF (GET_TIMER_IN_SECONDS(Race.tClock) < 6.5)
// do race start message
PRINT_HELP_ONCE("SPR_HELP_RST1", SPTT_HELP_BIT, SPTT_RESET_HELP1)
DEBUG_MESSAGE("You have restarted recently and must wait to restart: ")
PRINTFLOAT(GET_TIMER_IN_SECONDS(manualResetTimer))
PRINTNL()
ELSE
// Do normal message
PRINT_HELP_ONCE("SPR_HELP_RST", SPTT_HELP_BIT, SPTT_RESET_HELP)
DEBUG_MESSAGE("You have restarted recently and must wait to restart: ")
PRINTFLOAT(GET_TIMER_IN_SECONDS(manualResetTimer))
PRINTNL()
ENDIF
ENDIF
ENDIF
ENDIF
IF NOT IS_PED_INJURED(Race.Racer[i].Driver)
// Calculate racer rank.
SPTT_Race_Racer_Rank_Calc(Race, i)
///if we're doing a vehicle fail, that means the race is ending and we should stop updating gates
IF SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE AND IS_TIMER_STARTED(ExitVehicleTimer)
RETURN TRUE
ENDIF
// Check if racer is player.
IF bRacerIsPlayer
// If it's time to display plus/minus, start timer.
IF (Race.Racer[i].fPlsMnsLst <> 0.0)
START_TIMER_NOW(Race.Display.tCnt)
ENDIF
IF IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_FORCE_GATE_ACTIVATION)
SPTT_Race_Gate_Activate(Race, iGateCur, TRUE)
IF (iGateCur < (Race.iGateCnt - 1))
SPTT_Race_Gate_Activate(Race, iGateCur + 1, FALSE)
ENDIF
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_FORCE_GATE_ACTIVATION)
ENDIF
ENDIF
// Check if racer has passed/missed their current gate.
//SPTT_RACE_GATE_STATUS
IF Race.bFailChecking
Race.iGateCheck = ENUM_TO_INT(SPTT_Racer_Gate_Check(Race, GateCur, GateNxt, Race.Racer[i].Driver))
SPTT_RACE_MANAGE_CHECKPOINT_ALPHAS(GateCur, GateNxt)
ENDIF
IF (Race.iGateCheck <> ENUM_TO_INT(SPTT_RACE_GATE_STATUS_INVALID))
// Run Stunt Timers here
IF (eRaceType = SPTT_RACE_TYPE_PLANE)
runGateTimers(Race.Racer[i], bRacerIsPlayer, Race.iGateCheck)
ENDIF
bMissedStuntGate = SPTT_Stunt_Gate_Missed(INT_TO_ENUM(SPTT_RACE_GATE_STATUS , Race.iGateCheck))
// Increment racer current gate and re-cache it.
++Race.Racer[i].iGateCur
iGateCur = Race.Racer[i].iGateCur
IF (iGateCur >= Race.iGateCnt-1)
GateCur = Race.sGate[Race.iGateCnt-1]
ELSE
GateCur = Race.sGate[iGateCur]
ENDIF
// Check if racer is player.
IF bRacerIsPlayer
// If we're at the last gate, end the race.
SPTT_Race_Gate_Deactivate(Race, iGateCur - 1)
IF (iGateCur = Race.iGateCnt)
INT iRank = 0
IF IS_TIMER_STARTED(Race.tClock)
IF NOT IS_TIMER_PAUSED(Race.tClock)
PAUSE_TIMER(Race.tClock)
ENDIF
IF Race.Racer[0].fClockTime > 0
PRINTLN("Race.Racer[0].fClockTime is ", Race.Racer[0].fClockTime, " and SPTT_Master.fTimeGold[SPTT_Master.iRaceCur] is ", SPTT_Master.fTimeGold[SPTT_Master.iRaceCur])
IF Race.Racer[0].fClockTime <= SPTT_Master.fTimeGold[SPTT_Master.iRaceCur]
PRINTLN("gold because Race.Racer[0].fClockTime is ", Race.Racer[0].fClockTime, " and SPTT_Master.fTimeGold[SPTT_Master.iRaceCur] is ", SPTT_Master.fTimeGold[SPTT_Master.iRaceCur])
iRank = 1
ELIF Race.Racer[0].fClockTime <= ((SPTT_Master.fTimeBronze[SPTT_Master.iRaceCur]-SPTT_Master.fTimeGold[SPTT_Master.iRaceCur])/2)+SPTT_Master.fTimeGold[SPTT_Master.iRaceCur]
PRINTLN("silver because Race.Racer[0].fClockTime is ", Race.Racer[0].fClockTime, " and SPTT_Master.fTimeGold[SPTT_Master.iRaceCur] is ", SPTT_Master.fTimeGold[SPTT_Master.iRaceCur])
iRank = 2
ELIF Race.Racer[0].fClockTime <= SPTT_Master.fTimeBronze[SPTT_Master.iRaceCur]
PRINTLN("bronze because Race.Racer[0].fClockTime is ", Race.Racer[0].fClockTime, " and SPTT_Master.fTimeGold[SPTT_Master.iRaceCur] is ", SPTT_Master.fTimeGold[SPTT_Master.iRaceCur])
iRank = 3
ENDIF
ENDIF
ENDIF
IF iRank = 0
CDEBUG1LN( DEBUG_OR_RACES, "rank is 0! Failing!")
ENDIF
IF iRank > 0
RETURN FALSE
ELSE
Race.bFailChecking = FALSE
Race.Racer[i].iGateCur--
DEBUG_MESSAGE("Idle Failure Race.bFailChecking set to FALSE")
CLEAR_PRINTS()
spttFailStrapline = "SPR_TIME_FAIL"
Race.Racer[0].eReset = SPTT_RACER_RESET_FAIL_OVER
ENDIF
// Otherwise, activate new current/next gates.
ELSE
SPTT_Race_Gate_Activate(Race, iGateCur, TRUE)
IF (iGateCur < (Race.iGateCnt - 1))
SPTT_Race_Gate_Activate(Race, iGateCur + 1, FALSE)
ENDIF
ENDIF
// If split is still displaying since last gate, cancel it.
IF (Race.Racer[i].fPlsMnsLst = 0.0)
IF IS_TIMER_STARTED(Race.Display.tCnt)
CANCEL_TIMER(Race.Display.tCnt)
ENDIF
ENDIF
// If it's time to display split, calculate it and restart timer.
IF Race.iGateCnt > 0
IF (Race.fBestSplitTime > 0.0)
IF (iGateCur = ROUND(Race.iGateCnt / 2.0))
Race.Racer[i].fPlsMnsLst = 0.0
RESTART_TIMER_NOW(Race.Display.tCnt)
ENDIF
ENDIF
ENDIF
// Otherwise, racer is ai controlled.
ELSE
IF (Race.Racer[i].iGateCur >= Race.iGateCnt)
IF SPTT_Master.eRaceType <> SPTT_RACE_TYPE_TRIATHLON
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
FINISH_AI_RACERS(Race.Racer[i])
ENDIF
ENDIF
ELSE
IF SPTT_Master.eRaceType <> SPTT_RACE_TYPE_OFFROAD
// TODO: Put any player specific logic here...
IF i != 0 //not the player!?
SPTT_Race_Racer_Task_Go_To_Next_Gate(Race, Race.Racer[i].Driver, Race.Racer[i].Vehicle, Race.sGate[Race.Racer[i].iGateCur].vPos, Race.sGate[Race.Racer[i].iGateCur].eChkpntType, i)
ENDIF
ELSE
TEXT_LABEL OffroadRecording = "Offroad_"
OffroadRecording += (SPTT_Master.iRaceCur+1)
IF i = 1
OffroadRecording += "a"
ENDIF
// Task AI to follow waypoint recording for offroad race
// Pick random waypoint recording to start
IF i > 0
IF SPTT_USE_WAYPOINT_RECORDING
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
AND NOT IS_ENTITY_DEAD(Race.Racer[i].Vehicle)
IF (GET_SCRIPT_TASK_STATUS(Race.Racer[i].Driver, SCRIPT_TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING) = PERFORMING_TASK)
DEBUG_MESSAGE("AI on waypoint recording")
ELSE
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(Race.Racer[i].Driver, Race.Racer[i].Vehicle, OffroadRecording, DRIVINGMODE_PLOUGHTHROUGH, 0, EWAYPOINT_START_FROM_CLOSEST_POINT, -1, GET_VEHICLE_ESTIMATED_MAX_SPEED(Race.Racer[i].Vehicle))
ENDIF
ENDIF
ELSE
IF i != 0 //not the player!?
SPTT_Race_Racer_Task_Go_To_Next_Gate(Race, Race.Racer[i].Driver, Race.Racer[i].Vehicle, Race.sGate[Race.Racer[i].iGateCur].vPos, Race.sGate[Race.Racer[i].iGateCur].eChkpntType, i)
ENDIF
ENDIF
ENDIF
ENDIF
// Triathlon has its own rubber-banding system, so avoid updating this in Tri.
IF SPTT_Master.eRaceType <> SPTT_RACE_TYPE_TRIATHLON
SPTT_Race_Racer_Update_Rubberband_Speed(Race, i)
ENDIF
ENDIF
ENDIF
ENDIF
// Run rewards here
IF (eRaceType = SPTT_RACE_TYPE_PLANE)
IF bRacerIsPlayer
rewardPlayer()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
IF Race.bFailChecking = TRUE
// PRINTLN("ACTIVELY CHECKING FAIL CASES")
RESET_TUTORIAL(Race)
EXIT_VEHICLE_FAILURE(Race, returnToVehBlip)
Dead_Race_Vehicle(Race, returnToVehBlip)
wantedFailure()
//waterFailure(Race)
idleFailure(Race)
Disable_Airport_Icons()
RUN_OFFROAD_AUDIO(Race)
IF Race.Racer[0].eReset != SPTT_RACER_RESET_FAIL_OVER //make sure we dont draw on the same frame we fail.
IF INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge
//if we're on bridge binge, done draw until after ze first gate
IF Race.Racer[0].iGateCur > 0
SPTT_Race_Draw_HUD(Race)
ENDIF
ELSE
SPTT_Race_Draw_HUD(Race)
ENDIF
ENDIF
ELSE
// PRINTLN("NOT ACTIVELY CHECKING FAIL CASES ------")
ENDIF
// Update SPR Race Racers still running.
RETURN TRUE
ENDFUNC
// -----------------------------------
// FILE I/O PROCS/FUNCTIONS
// -----------------------------------
/// PURPOSE:
/// Init SPR Race.
PROC SPTT_Race_Init(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Init")
CANCEL_TIMER(Race.tClock)
// TEMP: Pulling in best clock/split times from master.
// TODO: Might want to put this into it's own function.
IF (SPTT_Master.iRaceCur <> -1)
FLOAT fBestClockTime = SPTT_Global_BestTime_Get(SPTT_Master.iRaceCur)
IF (fBestClockTime <= 0.0)
OR (fBestClockTime > SPTT_Master.fRaceTime[SPTT_Master.iRaceCur])
fBestClockTime = SPTT_Master.fRaceTime[SPTT_Master.iRaceCur]
ENDIF
Race.fBestClockTime = fBestClockTime
Race.fBestSplitTime = Race.fBestClockTime / 2.0
ENDIF
SPTT_Race_Gate_Init_All(Race)
Race.iGateCnt = 0
SPTT_Race_Racer_Init_All(Race)
Race.iRacerCnt = 0
// TODO: Should I be resetting state machine data here?
ENDPROC
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Load SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully loaded.
FUNC BOOL SPTT_Race_Load(SPTT_RACE_STRUCT& Race, STRING sRaceFileName)
DEBUG_MESSAGE("SPTT_Race_Load")
sRaceFileName = sRaceFileName
UNUSED_PARAMETER(Race)
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Save SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully saved.
FUNC BOOL SPTT_Race_Save(SPTT_RACE_STRUCT& Race, STRING sRaceFileName)
DEBUG_MESSAGE("SPTT_Race_Save")
UNUSED_PARAMETER(Race)
sRaceFileName = sRaceFileName
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Export SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully exported.
FUNC BOOL SPTT_Race_Export(SPTT_RACE_STRUCT& Race, STRING sRaceFileName)
DEBUG_MESSAGE("SPTT_Race_Export")
UNUSED_PARAMETER(Race)
sRaceFileName = sRaceFileName
// Race successfully exported.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Create SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully created.
FUNC BOOL SPTT_Race_Create(SPTT_RACE_STRUCT& Race, STRING sRaceFileName)
//DEBUG_MESSAGE("SPTT_Race_Create")
SPTT_Race_Init(Race)
IF SPTT_Race_Save(Race, sRaceFileName)
RETURN SPTT_Race_Export(Race, sRaceFileName)
ENDIF
RETURN FALSE
ENDFUNC
#ENDIF
// -----------------------------------
// MAIN PROCS/FUNCTIONS
// -----------------------------------
/// PURPOSE:
/// Setup SPR Race.
/// RETURNS:
/// TRUE if still setting up SPR Race.
FUNC BOOL SPTT_Race_Setup(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Setup")
// Setup SPR Race State Machine.
SWITCH (Race.eSetup)
// Setup (init).
CASE SPTT_RACE_SETUP_INIT
DEBUG_MESSAGE("SPTT_RACE_SETUP - INIT")
// Disable cellphone.
DISABLE_CELLPHONE(TRUE)
REQUEST_STREAMED_TEXTURE_DICT("MPHUD")
SPTT_Master.uiLeaderboard = REQUEST_SC_LEADERBOARD_UI()
// Request the appropriate race textures.
SWITCH (SPTT_Master.eRaceType)
CASE SPTT_RACE_TYPE_PLANE
REQUEST_STREAMED_TEXTURE_DICT("SPRRaces")
REQUEST_STREAMED_TEXTURE_DICT("MPMedals_FEED")
BREAK
CASE SPTT_RACE_TYPE_OFFROAD
REQUEST_STREAMED_TEXTURE_DICT("SPROffroad")
BREAK
CASE SPTT_RACE_TYPE_TRIATHLON
REQUEST_STREAMED_TEXTURE_DICT("Triathlon")
REQUEST_STREAMED_TEXTURE_DICT("MPMedals_FEED")
BREAK
ENDSWITCH
DEBUG_MESSAGE("SPTT_RACE_SETUP - LOAD_INIT")
Race.eSetup = SPTT_RACE_SETUP_LOAD_INIT
BREAK
// Setup Load (init).
CASE SPTT_RACE_SETUP_LOAD_INIT
SPTT_Race_Racer_Request_All(Race)
// Request Countdown UI scaleform movie.
// SPTT_COUNTDOWN_UI = REQUEST_SCALEFORM_MOVIE("COUNTDOWN")
DEBUG_MESSAGE("SPTT_RACE_SETUP - LOAD_WAIT")
Race.eSetup = SPTT_RACE_SETUP_LOAD_WAIT
BREAK
// Setup Load (wait).
CASE SPTT_RACE_SETUP_LOAD_WAIT
IF SPTT_Race_Racer_Stream_All(Race)
IF HAS_STREAMED_TEXTURE_DICT_LOADED("MPHUD")
IF HAS_SCALEFORM_MOVIE_LOADED(SPTT_Master.uiLeaderboard)
// IF HAS_MINIGAME_COUNTDOWN_UI_LOADED(SPTT_CountDownUI)
// Check the appropriate race textures have loaded.
SWITCH (SPTT_Master.eRaceType)
CASE SPTT_RACE_TYPE_PLANE
IF HAS_STREAMED_TEXTURE_DICT_LOADED("SPRRaces")
AND HAS_STREAMED_TEXTURE_DICT_LOADED("MPMedals_FEED")
DEBUG_MESSAGE("SPTT_RACE_SETUP - CREATE_INIT")
Race.eSetup = SPTT_RACE_SETUP_CREATE_INIT
ENDIF
BREAK
CASE SPTT_RACE_TYPE_OFFROAD
IF HAS_STREAMED_TEXTURE_DICT_LOADED("SPROffroad")
DEBUG_MESSAGE("SPTT_RACE_SETUP - CREATE_INIT")
Race.eSetup = SPTT_RACE_SETUP_CREATE_INIT
ENDIF
BREAK
CASE SPTT_RACE_TYPE_TRIATHLON
IF HAS_STREAMED_TEXTURE_DICT_LOADED("Triathlon")
AND HAS_STREAMED_TEXTURE_DICT_LOADED("MPMedals_FEED")
DEBUG_MESSAGE("SPTT_RACE_SETUP - CREATE_INIT")
Race.eSetup = SPTT_RACE_SETUP_CREATE_INIT
ENDIF
BREAK
ENDSWITCH
// ENDIF
ENDIF
ENDIF
ENDIF
BREAK
// Setup Create (init).
CASE SPTT_RACE_SETUP_CREATE_INIT
//clear this so we dont set off fail checks immediately
CLEAR_PLAYER_HAS_DAMAGED_AT_LEAST_ONE_PED(PLAYER_ID())
IF INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge AND NOT Race.bDidWeRestart
//do nothing
ELSE
SPTT_Race_Racer_Create_All(Race)
ENDIF
DEBUG_MESSAGE("SPTT_RACE_SETUP - CREATE_WAIT")
Race.eSetup = SPTT_RACE_SETUP_CREATE_WAIT
BREAK
// Setup Create (wait).
CASE SPTT_RACE_SETUP_CREATE_WAIT
//if we're on the first race and we're not restarting
//set plane to taxi
//otherwise autopilot
IF INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge// AND NOT Race.bDidWeRestart
RETURN FALSE
ELSE
// Auto-pilot race racers.
IF DOES_ENTITY_EXIST(Race.Racer[0].Vehicle)
FREEZE_ENTITY_POSITION(Race.Racer[0].Vehicle, TRUE)
ENDIF
IF NOT IS_NEW_LOAD_SCENE_ACTIVE()
REQUEST_COLLISION_AT_COORD(Race.Racer[0].vStartPos)
// Load the scene at the player's race start position.
NEW_LOAD_SCENE_START(Race.Racer[0].vStartPos, GET_ENTITY_FORWARD_VECTOR(Race.Racer[0].Vehicle), 5000.0)
PRINTLN("[SPTT_Race_Setup] SPTT_RACE_SETUP_CREATE_WAIT: New load scene started at player's position.")
#IF IS_DEBUG_BUILD
PRINTLN(GET_THIS_SCRIPT_NAME(), ": Calling NEW_LOAD_SCENE_START().")
#ENDIF
ENDIF
IF IS_NEW_LOAD_SCENE_LOADED()
#IF IS_DEBUG_BUILD
PRINTLN(GET_THIS_SCRIPT_NAME(), ": Calling NEW_LOAD_SCENE_STOP() due to IS_NEW_LOAD_SCENE_LOADED() returning TRUE.")
#ENDIF
NEW_LOAD_SCENE_STOP()
IF DOES_ENTITY_EXIST(Race.Racer[0].Vehicle)
FREEZE_ENTITY_POSITION(Race.Racer[0].Vehicle, FALSE)
ENDIF
SPTT_Race_Racer_AutoPilot(Race)
RETURN FALSE
ENDIF
ENDIF
BREAK
// Setup (wait).
CASE SPTT_RACE_SETUP_WAIT
RETURN FALSE
BREAK
// Setup (cleanup).
CASE SPTT_RACE_SETUP_CLEANUP
RETURN FALSE
BREAK
ENDSWITCH
// Setup SPR Race still running.
RETURN TRUE
ENDFUNC
FUNC BOOL UPDATE_TAXI_INTRO(SPTT_RACE_STRUCT& Race)
SPTT_RACE_GATE_STATUS thisGateStatus
thisGateStatus = SPTT_Racer_Gate_Check(Race, Race.sGate[0], Race.sGate[1], Race.Racer[0].Driver)
IF thisGateStatus = SPTT_RACE_GATE_STATUS_INVALID OR thisGateStatus = SPTT_RACE_GATE_STATUS_INCOMPLETE
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Update SPR Race.
/// RETURNS:
/// TRUE if still updating SPR Race.
FUNC BOOL SPTT_Race_Update(SPTT_RACE_STRUCT& Race)
//DEBUG_MESSAGE("SPTT_Race_Update")
//VECTOR vCurCamRotation
// Update SPR Race State Machine.
#IF IS_DEBUG_BUILD
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_1, KEYBOARD_MODIFIER_NONE, "")
SPTT_Race_Racer_Gate_Jump_Penultimate(Race, 0, TRUE)
ELIF IS_DEBUG_KEY_JUST_PRESSED(KEY_E, KEYBOARD_MODIFIER_SHIFT, "")
bEndTracking = !bEndTracking
ELIF IS_DEBUG_KEY_JUST_PRESSED(KEY_E, KEYBOARD_MODIFIER_CTRL, "")
bEndShake = !bEndShake
ENDIF
#ENDIF
SWITCH (Race.eUpdate)
// Update (init).
CASE SPTT_RACE_UPDATE_INIT
DEBUG_MESSAGE("SPTT_RACE_UPDATE - INIT")
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_PLAYED_STINGER)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
stop_vehicle_recordings(Race)
Race.bigMessageUI.siMovie = REQUEST_MG_BIG_MESSAGE()
// Auto-pilot race racers.
IF INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge// AND NOT Race.bDidWeRestart
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
// Activate first/second race gates.
SPTT_Race_Gate_Activate(Race, 0, TRUE)
SPTT_Race_Gate_Activate(Race, 1, FALSE)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
ENDIF
ELSE
SPTT_Race_Racer_AutoPilot(Race)
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
// Activate first/second race gates.
SPTT_Race_Gate_Activate(Race, 0, TRUE)
SPTT_Race_Gate_Activate(Race, 1, FALSE)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
ENDIF
ENDIF
// Setup countdown display.
CANCEL_TIMER(Race.Display.tCnt)
eCountdownStage = SPTT_COUNTDOWN_STAGE_INIT
DEBUG_MESSAGE("SPTT_RACE_UPDATE - COUNTDOWN")
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
PRINTLN("setting player control false")
Race.eUpdate = SPTT_RACE_UPDATE_COUNTDOWN
BREAK
// Update Countdown.
CASE SPTT_RACE_UPDATE_COUNTDOWN
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
// Auto-pilot race racers.
IF INT_TO_ENUM(SPTT_Races_ENUM, SPTT_Master.iRaceCur) = SPTT_BridgeBinge// AND NOT Race.bDidWeRestart
// clear one shot first checkpoints drawn bits
PRINTLN("SPTT_RACE_UPDATE_COUNTDOWN - skipping countdown since we're taxi-ing out.")
IF IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
ENDIF
SPTT_Race_Racer_Start(Race)
DEBUG_MESSAGE("SPTT_RACE_UPDATE - WAIT")
Race.eUpdate = SPTT_RACE_UPDATE_WAIT
ELSE
SPTT_Race_Racer_AutoPilot(Race)
// Display countdown until done, then start race.
IF NOT SPTT_Countdown_Display(Race.Display)
// failsafe backup to switch to cutscene cam
IF NOT IS_INTERPOLATING_FROM_SCRIPT_CAMS()
RENDER_SCRIPT_CAMS(FALSE, TRUE)
ENDIF
// clear one shot first checkpoints drawn bits
IF IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
ENDIF
// Start race racers.
DISPLAY_HUD(TRUE)
SPTT_Race_Racer_Start(Race)
IF SPTT_Master.iRaceCur = ENUM_TO_INT(SPTT_BridgeBinge) AND ((g_savedGlobals.sSPTTData.fBestTime[SPTT_BridgeBinge] > SPTT_Master.fTimeBronze[SPTT_BridgeBinge]) OR (g_savedGlobals.sSPTTData.fBestTime[SPTT_BridgeBinge] = 0))
PRINT_HELP("SPR_HELP_GATE", 10000)
ENDIF
DEBUG_MESSAGE("SPTT_RACE_UPDATE - WAIT")
Race.eUpdate = SPTT_RACE_UPDATE_WAIT
ENDIF
ENDIF
BREAK
// Update Finish.
CASE SPTT_RACE_UPDATE_FINISH
// In the case of Triathlon, immediately show the celebrating/tired triatheles.
// show player controls after 1 second
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_SCORECARD_INIT)
SETTIMERA(0)
SPTT_Race_Leaderboard_Init_Scorecard(Race)
INIT_SIMPLE_USE_CONTEXT(SPTT_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(SPTT_Master.uiInput, "SPR_CONT2", FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
SET_SIMPLE_USE_CONTEXT_MINIGAME_ATTACHED(SPTT_Master.uiInput)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_SCORECARD_INIT)
ENDIF
// manage pre-results camera pan
IF IS_HELP_MESSAGE_BEING_DISPLAYED()
CLEAR_HELP(TRUE)
ENDIF
IF IS_THIS_PRINT_BEING_DISPLAYED("SPR_RETR_FAIL")
CLEAR_PRINTS()
ENDIF
IF IS_HELP_MESSAGE_BEING_DISPLAYED()
CLEAR_HELP(TRUE)
ENDIF
IF IS_THIS_PRINT_BEING_DISPLAYED("SPR_RETR_FAIL")
CLEAR_PRINTS()
ENDIF
DEBUG_MESSAGE("SPTT_RACE_UPDATE - LEADERBOARD")
SETTIMERA(0)
SPTT_KILL_HINT_CAM()
SPTT_SET_HINT_CAM_ACTIVE(FALSE)
SPECIAL_ABILITY_DEACTIVATE(PLAYER_ID())
ENABLE_SPECIAL_ABILITY(PLAYER_ID(), FALSE)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
SET_MINIGAME_SPLASH_SHOWING(TRUE)
Race.eUpdate = SPTT_RACE_UPDATE_LEADERBOARD
BREAK
// Update Leaderboard.
CASE SPTT_RACE_UPDATE_LEADERBOARD
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
// Auto-circle race racers.
REPLAY_PREVENT_RECORDING_AND_UI_THIS_FRAME()
// freeze plane location, and transition camera off plane while scorecard is up
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
IF NOT IS_ENTITY_ON_SCREEN(Race.Racer[0].Vehicle) AND DOES_CAM_EXIST(iSPRStuntFinishCam1)
GET_CAM_ROT(iSPRStuntFinishCam1)
//SET_ENTITY_COORDS(Race.Racer[0].Vehicle, GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(GET_CAM_COORD(iSPRStuntFinishCam1), vCurCamRotation.z, <<-10, 0, 10>>))
SET_ENTITY_VISIBLE(Race.Racer[0].Vehicle, FALSE)
FREEZE_ENTITY_POSITION(Race.Racer[0].Vehicle, TRUE)
SPTT_RACE_CLEANUP_FINISH_STREAMVOL()
ENDIF
ENDIF
#IF COMPILE_WIDGET_OUTPUT
EXPORT_SCREEN_MEGA_PLACEMENT(Race.uiScorecard)
#ENDIF
// Wait for player to exit leaderboard.
IF NOT SPTT_UPDATING_END_SCREEN(Race, bEndTracking, bEndShake)
SPTT_RACE_CLEANUP_FINISH_STREAMVOL()
// SET_MINIGAME_SPLASH_SHOWING(FALSE)
SET_RESULT_SCREEN_DISPLAYING_STATE(FALSE)
CLEAR_HELP()
IF IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_SCORECARD_INIT)
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_SCORECARD_INIT)
ENDIF
DEBUG_MESSAGE("SPTT_RACE_UPDATE - CLEANUP")
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(FALSE)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CLEAR_PED_TASKS(PLAYER_PED_ID())
ENDIF
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
STOP_SCRIPTED_CONVERSATION(FALSE)
iButtonSounds = GET_SOUND_ID()
//ODDJOB_PLAY_SOUND("Phone_Generic_Key_02", iButtonSounds, FALSE)
PLAY_SOUND_FRONTEND(iButtonSounds, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
CANCEL_TIMER(exitTimer)
Race.eUpdate = SPTT_RACE_UPDATE_FADE_OUT_BEFORE_FINISH
//ELSE
// DEBUG_MESSAGE("Waiting for tracker thread to die")
ENDIF
BREAK
// Fade out right before cleaning and killing the script.
CASE SPTT_RACE_UPDATE_FADE_OUT_BEFORE_FINISH
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
// AsD TODO:
SET_ENTITY_COORDS(Race.Racer[0].Vehicle, SPTT_MENU_PLAYER_COORDS)
SET_ENTITY_ROTATION(Race.Racer[0].Vehicle, SPTT_MENU_PLAYER_ROTATION)
SET_ENTITY_VISIBLE(Race.Racer[0].Vehicle, TRUE)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
SET_VEHICLE_ON_GROUND_PROPERLY(Race.Racer[0].Vehicle)
SET_ENTITY_INVINCIBLE(Race.Racer[0].Vehicle, FALSE)
ENDIF
// AsD TODO:
//LOAD_SCENE(SPTT_MENU_PLAYER_COORDS)
bTriggerFirstMusicEvent = FALSE
Race.eUpdate = SPTT_RACE_UPDATE_FADE_IN_BEFORE_FINISH
Race.Racer[0].eReset = SPTT_RACER_QUIT_FADE_OUT
BREAK
// Fade in after cleaning and killing the script. Currently only used in Tri.
CASE SPTT_RACE_UPDATE_FADE_IN_BEFORE_FINISH
Race.eUpdate = SPTT_RACE_UPDATE_CLEANUP
BREAK
// Update (wait).
CASE SPTT_RACE_UPDATE_WAIT
// need to draw it for a bit longer after the GO! first appears
// think about adding a proper timer so we don't call this every frame afterwards
DRAW_SCALEFORM_MOVIE(SPTT_CountDownUI.uiCountdown, 0.5, 0.5, 1.0, 1.0, 255, 255, 255, 100)
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
// Activate first/second race gates.
SPTT_Race_Gate_Activate(Race, 0, TRUE)
SPTT_Race_Gate_Activate(Race, 1, FALSE)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, SPTT_FIRST_GATE_ACTIVATION)
SPTT_SET_HINT_CAM_ACTIVE(TRUE)
SPTT_SET_HINT_CAM_COORD(Race.sGate[Race.Racer[0].iGateCur].vPos)
ENDIF
IF Race.bFailChecking //if we're checking it means we havent failed yet
SPTT_UPDATE_HINT_CAM(Race)
SPTT_RACE_CREATE_FINISH_STREAMVOL(Race)
ELSE
KILL_RACE_HINT_CAM(localChaseHintCamStruct)
SPTT_RACE_CLEANUP_FINISH_STREAMVOL()
SET_CINEMATIC_BUTTON_ACTIVE(FALSE)
ENDIF
// Update race racers and auto-restart race.
IF NOT SPTT_Race_Racer_Update(Race, SPTT_Master.eRaceType)
TRIGGER_MUSIC_EVENT("MGSP_END")
PRINTLN("TRIGGERING MUSIC EVENT - MGSP_END")
// Finish race racers.
SPTT_Race_Racer_Finish(Race)
// Setup finish display.
CANCEL_TIMER(Race.Display.tCnt)
DEBUG_MESSAGE("SPTT_RACE_UPDATE - FINISH")
Race.eUpdate = SPTT_RACE_UPDATE_FINISH
CANCEL_TIMER(Race.tUpdate)
ENDIF
BREAK
// Update (cleanup).
CASE SPTT_RACE_UPDATE_CLEANUP
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
CLEANUP_MG_BIG_MESSAGE(Race.bigMessageUI)
SPTT_RACE_CLEANUP_FINISH_STREAMVOL()
PRINTLN("SPTT_RACE_UPDATE_CLEANUP")
SPTT_Race_Cleanup_Stunt_Beats()
// SET_PLAYER_INVINCIBLE(PLAYER_ID(), FALSE)
RETURN FALSE
BREAK
ENDSWITCH
// Update SPR Race still running.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Cleanup SPR Race.
PROC SPTT_Race_Cleanup(SPTT_RACE_STRUCT& Race, BOOL bDefault)
//DEBUG_MESSAGE("SPTT_Race_Cleanup")
IF bDefault
DEBUG_MESSAGE("SPTT_RACE_CLEANUP: Default bool hit, doing race init")
// Init race data.
SPTT_Race_Init(Race)
ELSE
DEBUG_MESSAGE("SPTT_RACE_CLEANUP: False bool hit, releasing offroad AI")
// Release AI
RELEASE_AI_RACERS(Race)
ENDIF
// Enable cellphone.
DISABLE_CELLPHONE(FALSE)
CLEANUP_MG_BIG_MESSAGE(Race.bigMessageUI)
CLEAR_HELP()
CLEAR_PRINTS()
IF bDebugFailure
DEBUG_MESSAGE("SPTT_Main_Debug: Debug Fail: before message")
PRINT_NOW("SPR_MOVE_FAIL", 5000, 0)
DEBUG_MESSAGE("SPTT_Main_Debug: Debug Fail: after message")
bDebugFailure = FALSE
ENDIF
// Cleanup countdown scaleform UI.
//SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(SPTT_COUNTDOWN_UI)
//SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("MPHUD")
//SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("SRange")
//SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("SPROffroad")
//SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("SPRRaces")
// TODO: Probably need more stuff in here...
ENDPROC
// END OF FILE! DO NOT ADD ANYTHING BELOW THIS LINE!