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

3601 lines
125 KiB
Scheme
Executable File

// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// SCRIPT NAME : TRI_Race.sch
// AUTHOR : Nicholas Zippmann
// DESCRIPTION : Single Player Races - Race procs/functions file
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
USING "TRI_Head.sch"
USING "TRI_Helpers.sch"
USING "TRI_Gate.sch"
USING "chase_hint_cam.sch" // CHASE_HINT_CAM_STRUCT localChaseHintCamStruct
USING "TRI_Racer.sch"
USING "minigame_stats_tracker_helpers.sch"
USING "CompletionPercentage_public.sch"
USING "TRI_SC_Leaderboard_lib.sch"
USING "tri_dialogue.sch"
USING "tri_cutscenes.sch"
BOOL bIsJustOnline = FALSE
VECTOR vDestinationPosOfStoredPlayerVehicle
FLOAT fDestinationHeadingOfStoredPlayerVehicle
//Clear Area For Race Start
PROC CLEAR_AREA_AROUND_TRI_POS(VECTOR vRacePos)
CPRINTLN(DEBUG_TRIATHLON, "Clearing this area of vehicles: ", vRacePos)
REMOVE_ALL_SHOCKING_EVENTS(FALSE)
CLEAR_AREA(vRacePos, 100, TRUE)
CLEAR_AREA_OF_PEDS(vRacePos, 100)
CLEAR_AREA_OF_VEHICLES(vRacePos, 100, FALSE, FALSE, TRUE, TRUE)
CLEAR_AREA_OF_PROJECTILES( vRacePos, 100)
STOP_FIRE_IN_RANGE(vRacePos, 100)
ENDPROC
structTimer taxiTime
structTimer resetTimer
//structTimer manualResetTimer
structTimer tShutdownTimer
structTimer tReadLeaderboardTimer
MG_FAIL_SPLASH splashState
CONST_FLOAT TRI_RACER_BLIP_SCALE 0.5
BOOL bCatchupActive = FALSE
// Rank prediction flags.
BOOL bIsLBDContextSet = FALSE
BOOL bRankPredictReady = FALSE
//really should consolidate all of these bits into a single INT
ENUM TRI_HELP
TRI_RESET_HELP = BIT0,
TRI_RESET_HELP1 = BIT1
ENDENUM
ENUM TRI_RETURN_VALUES_ENUM
TRV_FALSE = 0,
TRV_TRUE,
TRV_RESET
ENDENUM
//#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(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(TRI_RACE_STRUCT& Race)
IF (Race.iRacerCnt = -1)
PRINTINT(Race.iRacerCnt)
PRINTNL()
ENDIF
ENDPROC
#ENDIF
#IF NOT DEFINED(stop_vehicle_recordings)
PROC stop_vehicle_recordings(TRI_RACE_STRUCT& Race)
Race.iGateCnt = Race.iGateCnt
ENDPROC
#ENDIF
#IF NOT DEFINED(Disable_Airport_Icons)
PROC Disable_Airport_Icons()
/* IF TRI_Master.eRaceType = TRI_RACE_TYPE_PLANE
DEBUG_MESSAGE("Inside dummy Disable_Airport_Icons proc")
ENDIF */
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Gate_Reward)
PROC TRI_Gate_Reward(TRI_RACER_STRUCT& Racer, TRI_RACE_GATE_STATUS status)
Racer.fPlsMnsTot = Racer.fPlsMnsTot
status = status
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Racer_ClockTime_Penalty)
PROC TRI_Racer_ClockTime_Penalty(TRI_RACER_STRUCT& Racer, FLOAT fPenalty)
Racer.fPlsMnsTot = Racer.fPlsMnsTot
fPenalty = fPenalty
ENDPROC
#ENDIF
#IF NOT DEFINED(runGateTimers)
PROC runGateTimers(TRI_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(TRI_Race_Racer_AutoPilot)
PROC TRI_Race_Racer_AutoPilot(TRI_RACE_STRUCT& Race)
Race.fBestClockTime = Race.fBestClockTime
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Race_Racer_AutoCircle)
PROC TRI_Race_Racer_AutoCircle(TRI_RACE_STRUCT& Race)
Race.fBestClockTime = Race.fBestClockTime
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Racer_AutoPilot)
PROC TRI_Racer_AutoPilot(TRI_RACER_STRUCT& Racer, FLOAT fSpeed, BOOL bRotInterp)
Racer.fStartHead = Racer.fStartHead
fSpeed = fSpeed
bRotInterp = bRotInterp
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Racer_AutoCircle)
PROC TRI_Racer_AutoCircle(TRI_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(TRI_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(TRI_Init_Scorecard)
PROC TRI_Init_Scorecard(TRI_RACE_STRUCT &Race)
Race.iGateCheck = Race.iGateCheck
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Draw_Scorecard)
PROC TRI_Draw_Scorecard(TRI_RACE_STRUCT &Race, INT &iPlayerIndex)
Race.iGateCheck = Race.iGateCheck
iPlayerIndex = iPlayerIndex
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Setup_Leaderboard)
PROC TRI_Setup_Leaderboard(TRI_RACE_STRUCT &Race)
UNUSED_PARAMETER(Race)
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Draw_Leaderboard)
PROC TRI_Draw_Leaderboard(TRI_RACE_STRUCT &Race)
Race = Race
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Cleanup_Leaderboard)
PROC TRI_Cleanup_Leaderboard(TRI_RACE_STRUCT &Race)
Race = Race
ENDPROC
#ENDIF
#IF NOT DEFINED(Cleanup_Finish_Camera)
PROC Cleanup_Finish_Camera()
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Race_Stunt_Manage_Finish_Camera)
PROC TRI_Race_Stunt_Manage_Finish_Camera(VEHICLE_INDEX& iPlayersPlane)
UNUSED_PARAMETER(iPlayersPlane)
ENDPROC
#ENDIF
#IF NOT DEFINED(TRI_Race_Manage_Race_Beats)
PROC TRI_Race_Manage_Race_Beats(INT iGateCur, BOOL bFailChecking)
iGateCur = iGateCur
bFailChecking = bFailChecking
ENDPROC
#ENDIF
#IF NOT DEFINED(FINISH_AI_RACERS)
PROC FINISH_AI_RACERS(TRI_RACER_STRUCT& Racer)
PRINTFLOAT(Racer.fStartHead)
PRINTNL()
ENDPROC
#ENDIF
#IF NOT DEFINED(RELEASE_AI_RACERS)
PROC RELEASE_AI_RACERS(TRI_RACE_STRUCT& Race)
PRINTINT(Race.iRacerCnt)
PRINTNL()
ENDPROC
#ENDIF
// -----------------------------------
// HELPER PROCS/FUNCTIONS
// -----------------------------------
PROC TRI_Race_FakeRacer_Populate(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_FakeRacer_Populate")
TEXT_LABEL_31 szRacerName[TRI_UI_LB_RACER_LIMIT - 1]
TRI_RacerName_Populate(szRacerName)
FLOAT fBestClockTime = Race.fBestClockTime
IF (fBestClockTime > Race.Racer[0].fClockTime)
fBestClockTime = Race.Racer[0].fClockTime
ENDIF
WHILE (Race.iRacerCnt < TRI_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 TRI_Race_ClockTime_SimAI(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_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 TRI_Race_Rank_CalcFinal(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_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 TRI_Race_RankClock_FindPlayerBest(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_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 = TRI_Global_BestRank_Get(TRI_Master.iRaceCur)
IF (iBestRank <= 0) OR (iBestRank > Race.Racer[i].iRank)
TRI_Global_BestRank_Set(TRI_Master.iRaceCur, Race.Racer[i].iRank)
ENDIF
FLOAT fBestTime = TRI_Global_BestTime_Get(TRI_Master.iRaceCur)
IF (fBestTime <= 0.0) OR (fBestTime > Race.Racer[i].fClockTime)
TRI_Global_BestTime_Set(TRI_Master.iRaceCur, Race.Racer[i].fClockTime)
#IF IS_DEBUG_BUILD
IF IS_CHEATING_ENABLED
Race.Racer[i].fClockTime += 1000
ENDIF
#ENDIF
IF NOT bCheated
//INT iMedalToWrite = CLAMP_INT((4 - Race.Racer[i].iRank), 0, 3)
//WRITE_TRI_TRI_TIME_TO_LEADERBOARD(INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur), Race.Racer[i].fClockTime, iMedalToWrite)
ENDIF
ENDIF
EXIT
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC TRI_Race_Leaderboard_Init_Scorecard(TRI_RACE_STRUCT& Race)
TRI_Init_Scorecard(Race)
TRI_Setup_Leaderboard(Race)
SETTIMERA(0)
ENDPROC
FUNC TRI_RETURN_VALUES_ENUM TRI_Race_Draw_Scorecard(TRI_RACE_STRUCT& Race, TRIATHLON_RACE_INDEX eRace)
IF NOT IS_RADAR_HIDDEN()
DISPLAY_RADAR(FALSE)
ENDIF
DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE_ALTERNATE) // B*2239651 - Disabling pause_alternate during end screens (to avoid clash when exiting leaderboards)
// If in the leaderboard screen, wait for the player to access the scorecard screen.
IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) AND IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_SCLB)
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Player is in leaderboard screen and pressed CANCEL.")
PLAY_SOUND_FRONTEND(-1, "BACK", "HUD_MINI_GAME_SOUNDSET")
CLEAR_TRI_CONTROL_FLAG(TCF_SHOW_SCLB)
CLEANUP_SIMPLE_USE_CONTEXT( TRI_Master.uiInput )
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "TRI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
IF NOT IS_PLAYER_ONLINE()
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_SCLB", FRONTEND_CONTROL, INPUT_FRONTEND_LEADERBOARD)
bIsLBDContextSet = TRUE
ENDIF
ENDIF
IF IS_PLAYER_ONLINE()
AND NOT bIsJustOnline
bIsJustOnline = TRUE
bIsLBDContextSet = FALSE
CLEANUP_SIMPLE_USE_CONTEXT( TRI_Master.uiInput )
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "TRI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
ELIF NOT IS_PLAYER_ONLINE()
AND bIsJustOnline
bIsJustOnline = FALSE
ENDIF
IF IS_PLAYER_ONLINE()
IF bIsJustOnline
AND NOT sclb_rank_predict.bFinishedRead
TRI_LOAD_SOCIAL_CLUB_LEADERBOARD(INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur))
ENDIF
IF NOT IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_SCLB)
IF NOT bIsLBDContextSet
AND sclb_rank_predict.bFinishedRead
AND sclb_rank_predict.bFinishedWrite
AND bRankPredictReady
bIsLBDContextSet = TRUE
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Leaderboard is ready to be seen. bIsLBDContextSet set to TRUE." )
CLEANUP_SIMPLE_USE_CONTEXT( TRI_Master.uiInput )
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "TRI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_SCLB", FRONTEND_CONTROL, INPUT_FRONTEND_LEADERBOARD)
ENDIF
ELSE
IF NOT sclb_rank_predict.bFinishedRead
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Not reading." )
ENDIF
IF NOT sclb_rank_predict.bFinishedWrite
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Not written yet." )
ENDIF
IF NOT bRankPredictReady
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Rank not yer ready." )
ENDIF
ENDIF
IF sclb_rank_predict.bFinishedRead
AND NOT sclb_rank_predict.bFinishedWrite
IF NOT bCheated
INT iMedalToWrite = CLAMP_INT((4 - Race.Racer[0].iRank), 0, 3)
WRITE_TRI_TRI_TIME_TO_LEADERBOARD(INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur), Race.Racer[0].fClockTime, iMedalToWrite)
ENDIF
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Writing to leaderboard." )
sclb_rank_predict.bFinishedWrite = TRUE
ENDIF
IF NOT bRankPredictReady
bRankPredictReady = GET_RANK_PREDICTION_DETAILS( triLBControl )
IF bRankPredictReady
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Rank prediction is complete." )
sclb_useRankPrediction = TRUE
ENDIF
ENDIF
ENDIF
IF IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_SCLB)
IF TRI_SHOULD_SCLB_SHOW_PROFILE_BUTTON() AND NOT IS_TRI_RACE_UI_FLAG_SET(Race, TUIF_SCLB_PROFILE_BUTTON_SHOWN)
SET_TRI_RACE_UI_FLAG(Race, TUIF_SCLB_PROFILE_BUTTON_SHOWN)
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "FE_HLP3", FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SCLB_PROFILE", FRONTEND_CONTROL, INPUT_FRONTEND_SELECT)
ELIF NOT TRI_SHOULD_SCLB_SHOW_PROFILE_BUTTON() AND IS_TRI_RACE_UI_FLAG_SET(Race, TUIF_SCLB_PROFILE_BUTTON_SHOWN)
CLEAR_TRI_RACE_UI_FLAG(Race, TUIF_SCLB_PROFILE_BUTTON_SHOWN)
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "FE_HLP3", FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
ENDIF
ENDIF
// If in the scorecard screen, wait for the player to access the leaderboard.
IF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_LEADERBOARD) AND NOT IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_SCLB)
AND bIsLBDContextSet
CDEBUG1LN( DEBUG_TRIATHLON, "[TRI_Race_Draw_Scorecard] Leaderboard screen is NOT active, player press RB, and bIsLBDContextSet is TRUE. Setting bIsLBDContextSet FALSE.")
bIsLBDContextSet = FALSE
PLAY_SOUND_FRONTEND(-1, "LEADERBOARD", "HUD_MINI_GAME_SOUNDSET")
SET_TRI_CONTROL_FLAG(TCF_SHOW_SCLB)
CLEANUP_SIMPLE_USE_CONTEXT( TRI_Master.uiInput )
IF IS_PLAYER_ONLINE()
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "FE_HLP3", FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
IF TRI_SHOULD_SCLB_SHOW_PROFILE_BUTTON()
SET_TRI_RACE_UI_FLAG(Race, TUIF_SCLB_PROFILE_BUTTON_SHOWN)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SCLB_PROFILE", FRONTEND_CONTROL, INPUT_FRONTEND_SELECT)
ENDIF
ENDIF
ENDIF
UPDATE_SIMPLE_USE_CONTEXT(TRI_Master.uiInput)
// If in the leaderboard screen, and the player is not online, do a SIGN OUT warning. Otherwise, draw the leaderboard.
IF IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_SCLB)
IF NOT IS_PLAYER_ONLINE()
IF DO_SIGNED_OUT_WARNING(TRI_Master.iBS)
CLEAR_TRI_CONTROL_FLAG(TCF_SHOW_SCLB)
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "TRI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_SCLB", FRONTEND_CONTROL, INPUT_FRONTEND_LEADERBOARD)
bIsLBDContextSet = TRUE
ENDIF
ELIF HAS_SCALEFORM_MOVIE_LOADED(Race.uiLeaderboard)
TRI_Draw_Leaderboard(Race, eRace)
ENDIF
RETURN TRV_FALSE
ELIF IS_TRI_END_SCREEN_READY()
DISPLAY_TRI_END_SCREEN()
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, TRI_PLAYED_STINGER)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_PLAYED_STINGER)
IF Race.Racer[0].iRank < 4
PLAY_SOUND_FRONTEND(-1, "MEDAL_UP", "HUD_MINI_GAME_SOUNDSET")
ELSE
PLAY_SOUND_FRONTEND (-1, "RACE_PLACED", "HUD_AWARDS")
ENDIF
ENDIF
ENDIF
IF IS_AUTOSAVE_REQUEST_IN_PROGRESS()
SETTIMERA(2000)
ELSE
IF TIMERA() > 3000
// When the player presses CONTINUE, or if he's wanted, we move on.
IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0) OR IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
PLAY_SOUND_FRONTEND(-1, "SELECT", "HUD_MINI_GAME_SOUNDSET")
RETURN TRV_TRUE
ELSE
RETURN TRV_FALSE
ENDIF
RETURN TRV_TRUE
ENDIF
ENDIF
RETURN TRV_FALSE
ENDFUNC
// -----------------------------------
// GATE PROCS/FUNCTIONS
// -----------------------------------
FUNC BOOL TRI_Race_Gate_Activate(TRI_RACE_STRUCT& Race, INT iGate, BOOL bGateCur)
VECTOR vNextGate
//DEBUG_MESSAGE("TRI_Race_Gate_Activate")
IF (iGate < 0) OR (iGate > (TRI_GATE_MAX - 1))
DEBUG_MESSAGE("TRI_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 = TRI_GATE_BLIPCUR_SCL
IF NOT bGateCur
fBlipScale = TRI_GATE_BLIPNXT_SCL
ENDIF
IF NOT TRI_Gate_Blip_Create(Race.sGate[iGate], eBlipSprite, fBlipScale, iGate, Race.iGateCnt)
DEBUG_MESSAGE("TRI_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)
//update chase cam
IF NOT (TRI_Master.eRaceType = TRI_RACE_TYPE_TRIATHLON)
TRI_SET_HINT_CAM_COORD(Race.sGate[iGate].vPos)
ENDIF
vNextGatePos = Race.sGate[iGate + 1].vPos
ENDIF
ENDIF
IF TRI_Master.eRaceType = TRI_RACE_TYPE_OFFROAD
IF (TRI_Master.iRaceCur = 1) // 1 for Ridgerun)
IF IS_BITMASK_AS_ENUM_SET(Race.sGate[8].iGateFlags, TRI_RACE_GATE_FLAG_DO_NOT_SNAP_TO_GROUND)
CLEAR_BITMASK_AS_ENUM(Race.sGate[8].iGateFlags, TRI_RACE_GATE_FLAG_DO_NOT_SNAP_TO_GROUND)
CPRINTLN(DEBUG_TRIATHLON, "TRI_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 TRI_Gate_Chkpnt_Create(vPrevGatePos, Race.sGate[iGate], vNextGatePos, TRI_GATE_CHKPNT_SCL)
DEBUG_MESSAGE("TRI_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 >= TRI_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 TRI_Gate_Chkpnt_Create(Race.sGate[iGate].vPos, Race.sGate[iGate+1], vNextGate, TRI_GATE_CHKPNT_SCL)//TRI_GATE_CHKPNTNXT_SCL)
DEBUG_MESSAGE("TRI_Race_Gate_Activate: Failed to create gate checkpoint!")
RETURN FALSE
ENDIF
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
FUNC BOOL TRI_Race_Gate_Activate_All(TRI_RACE_STRUCT& Race, BOOL bGateCur)
//DEBUG_MESSAGE("TRI_Race_Gate_Activate_All")
INT i
BOOL bAllDone = TRUE
REPEAT Race.iGateCnt i
IF NOT TRI_Race_Gate_Activate(Race, i, bGateCur)
bAllDone = FALSE
ENDIF
ENDREPEAT
RETURN bAllDone
ENDFUNC
PROC TRI_Race_Gate_Deactivate(TRI_RACE_STRUCT& Race, INT iGate, BOOL bDeleteCheckpoint = TRUE)
//DEBUG_MESSAGE("TRI_Race_Gate_Deactivate")
IF (iGate < 0) OR (iGate > (TRI_GATE_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Gate_Deactivate: Gate index out of range!")
EXIT
ENDIF
TRI_Gate_Blip_Destroy(Race.sGate[iGate])
IF bDeleteCheckpoint
CDEBUG1LN(DEBUG_TRIATHLON, "[TRI_Race_Gate_Deactivate] bDeleteCheckpoint is TRUE, so deleting checkpoint.")
TRI_Gate_Chkpnt_Destroy(Race.sGate[iGate])
ELSE
CDEBUG1LN(DEBUG_TRIATHLON, "[TRI_Race_Gate_Deactivate] bDeleteCheckpoint is FALSE, so skipping deletion of checkpoint. Likely due to checkpoint being deleted after fade.")
ENDIF
//turn off our extra checkpoint
IF iGate+1 < Race.iGateCnt
TRI_Gate_Blip_Destroy(Race.sGate[iGate+1])
TRI_Gate_Chkpnt_Destroy(Race.sGate[iGate+1])
ENDIF
ENDPROC
PROC TRI_Race_Gate_Deactivate_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Gate_Deactivate_All")
INT i
REPEAT Race.iGateCnt i
TRI_Race_Gate_Deactivate(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Gate_Init(TRI_RACE_STRUCT& Race, INT iGate)
//DEBUG_MESSAGE("TRI_Race_Gate_Init")
IF (iGate < 0) OR (iGate > (TRI_GATE_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Gate_Init: Gate index out of range!")
EXIT
ENDIF
TRI_Gate_Blip_Destroy(Race.sGate[iGate])
TRI_Gate_Chkpnt_Destroy(Race.sGate[iGate])
TRI_Gate_Init(Race.sGate[iGate])
ENDPROC
PROC TRI_Race_Gate_Init_All(TRI_RACE_STRUCT& Race)
INT i
REPEAT Race.iGateCnt i
CDEBUG1LN(DEBUG_TRIATHLON, "[TRI_Race_Gate_Init_All] Calling TRI_Race_Gate_Init on gate ", i)
TRI_Race_Gate_Init(Race, i)
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER DRIVER PROCS/FUNCTIONS
// -----------------------------------
PROC TRI_Race_Racer_Driver_Request(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Request")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Request: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Driver_Request(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Driver_Request_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Request_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Driver_Request(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Driver_Stream(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Stream")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Stream: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN TRI_Racer_Driver_Stream(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL TRI_Race_Racer_Driver_Stream_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Stream_All")
INT i
BOOL bStreamDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT TRI_Racer_Driver_Stream(Race, i)
bStreamDone = FALSE
ENDIF
ENDREPEAT
RETURN bStreamDone
ENDFUNC
PROC TRI_Race_Racer_Driver_Evict(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Evict")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Evict: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Driver_Evict(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Driver_Evict_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Evict_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Driver_Evict(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Driver_Create(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Create")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Create: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN TRI_Racer_Driver_Create(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL TRI_Race_Racer_Driver_Create_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF i <> 0
IF NOT TRI_Race_Racer_Driver_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC TRI_Race_Racer_Driver_Freeze(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Freeze")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Freeze: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Driver_Freeze(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Driver_Freeze_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Freeze_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Driver_Freeze(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Driver_UnFreeze(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_UnFreeze")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_UnFreeze: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Driver_UnFreeze(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Driver_UnFreeze_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_UnFreeze_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Driver_UnFreeze(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Driver_Release(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Release")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Release: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Driver_Release(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Driver_Release_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Release_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Driver_Release(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Driver_Destroy(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Destroy")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Driver_Destroy: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Driver_Destroy(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Driver_Destroy_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Driver_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Driver_Destroy(Race, i)
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER VEHICLE PROCS/FUNCTIONS
// -----------------------------------
PROC TRI_Race_Racer_Vehicle_Request(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Request")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Request: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Vehicle_Request(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Vehicle_Request_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Request_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Vehicle_Request(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Vehicle_Stream(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Stream")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Stream: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN TRI_Racer_Vehicle_Stream(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL TRI_Race_Racer_Vehicle_Stream_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Stream_All")
INT i
BOOL bStreamDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT TRI_Racer_Vehicle_Stream(Race, i)
bStreamDone = FALSE
ENDIF
ENDREPEAT
RETURN bStreamDone
ENDFUNC
PROC TRI_Race_Racer_Vehicle_Evict(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Evict")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Evict: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Vehicle_Evict(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Vehicle_Evict_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Evict_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Vehicle_Evict(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Vehicle_Create(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Create")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Create: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN TRI_Racer_Vehicle_Create(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL TRI_Race_Racer_Vehicle_Create_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT TRI_Race_Racer_Vehicle_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC TRI_Race_Racer_Vehicle_Freeze(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Freeze")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Freeze: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Vehicle_Freeze(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Vehicle_Freeze_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Freeze_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Vehicle_Freeze(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Vehicle_UnFreeze(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_UnFreeze")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_UnFreeze: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Vehicle_UnFreeze(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Vehicle_UnFreeze_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_UnFreeze_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Vehicle_UnFreeze(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Vehicle_Release(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Release")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Release: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Vehicle_Release(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Vehicle_Release_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Release_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Vehicle_Release(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Vehicle_Destroy(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Destroy")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Destroy: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Vehicle_Destroy(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Vehicle_Destroy_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Vehicle_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Vehicle_Destroy(Race, i)
ENDREPEAT
ENDPROC
// -----------------------------------
// RACER MAIN PROCS/FUNCTIONS
// -----------------------------------
PROC TRI_Race_Racer_Request(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Request")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Request: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Request(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Request_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Request_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Request(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Stream(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Stream")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Stream: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN TRI_Racer_Stream(Race.Racer[iRacer])
ENDFUNC
FUNC BOOL TRI_Race_Racer_Stream_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Stream_All")
INT i
BOOL bStreamDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT TRI_Race_Racer_Stream(Race, i)
bStreamDone = FALSE
ENDIF
ENDREPEAT
RETURN bStreamDone
ENDFUNC
PROC TRI_Race_Racer_Evict(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Evict")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Evict: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Evict(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Evict_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Evict_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Evict(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Blip_Create(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Blip_Create")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Blip_Create: Racer index out of range!")
RETURN FALSE
ENDIF
RETURN TRI_Racer_Blip_Create(Race.Racer[iRacer], TRI_RACER_BLIP_SCALE)
ENDFUNC
FUNC BOOL TRI_Race_Racer_Blip_Create_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Blip_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF NOT TRI_Race_Racer_Blip_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC TRI_Race_Racer_Blip_Destroy(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Blip_Destroy")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Blip_Destroy: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Blip_Destroy(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Blip_Destroy_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Blip_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Blip_Destroy(Race, i)
ENDREPEAT
ENDPROC
FUNC BOOL TRI_Race_Racer_Create(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Create")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Create: Racer index out of range!")
RETURN FALSE
ENDIF
IF (iRacer > 0)
RETURN TRI_Racer_Create(Race.Racer[iRacer], TRUE)
ELSE
RETURN TRI_Racer_Create(Race.Racer[iRacer], FALSE)
ENDIF
ENDFUNC
FUNC BOOL TRI_Race_Racer_Create_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Create_All")
INT i
BOOL bCreateDone = TRUE
REPEAT Race.iRacerCnt i
IF i <> 0
IF NOT TRI_Race_Racer_Create(Race, i)
bCreateDone = FALSE
ENDIF
ENDIF
ENDREPEAT
RETURN bCreateDone
ENDFUNC
PROC TRI_Race_Racer_Freeze(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Freeze")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Freeze: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Freeze(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Freeze_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Freeze_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Freeze(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_UnFreeze(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_UnFreeze")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_UnFreeze: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_UnFreeze(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_UnFreeze_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_UnFreeze_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_UnFreeze(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Release(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Release")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Release: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Release(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Release_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Release_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Release(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Destroy(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Destroy")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Destroy: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Destroy(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Destroy_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Destroy_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Destroy(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Init(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Init")
IF (iRacer < 0) OR (iRacer > (TRI_RACER_MAX - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Init: Racer index out of range!")
EXIT
ENDIF
TRI_Racer_Destroy(Race.Racer[iRacer])
TRI_Racer_Init(Race.Racer[iRacer])
ENDPROC
PROC TRI_Race_Racer_Init_All(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Racer_Init_All")
INT i
REPEAT Race.iRacerCnt i
TRI_Race_Racer_Init(Race, i)
ENDREPEAT
ENDPROC
PROC TRI_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 TRI_Race_Racer_Start(TRI_RACE_STRUCT& Race)
// Start race clock.
RESTART_TIMER_NOW(Race.tClock)
// Give back player control.
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
IF (TRI_Master.eRaceType = TRI_RACE_TYPE_PLANE)
SET_PLAYER_INVINCIBLE(PLAYER_ID(), TRUE)
ENDIF
SET_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
DEBUG_MESSAGE("TRI_Race_Racer_Start: TCF_FAIL_CHECKING set")
//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.
TRI_Racer_Start(Race.Racer[i])
IF i != 0 //not the player!?
TRI_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
ENDREPEAT
ENDPROC
PROC AI_End_Of_Race_Stop(TRI_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 TRI_Master.eRaceType <> TRI_RACE_TYPE_TRIATHLON
TASK_VEHICLE_TEMP_ACTION(Race.Racer[i].Driver,Race.Racer[i].Vehicle, TEMPACT_HANDBRAKETURNRIGHT, 5000)
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Called immediately after the player finishes the race.
/// PARAMS:
/// Race - Contains all the data of the current race.
PROC TRI_Race_Racer_Finish(TRI_RACE_STRUCT& Race)
// Pause race clock, if needed.
IF NOT IS_TIMER_PAUSED(Race.tClock)
PAUSE_TIMER(Race.tClock)
ENDIF
TRI_Race_ClockTime_SimAI(Race)
// Find player best rank and clock time.
TRI_Race_RankClock_FindPlayerBest(Race)
// Loop through all racers and finish them.
INT iLoopCounter
REPEAT Race.iRacerCnt iLoopCounter
TRI_Racer_Finish(Race.Racer[iLoopCounter])
IF iLoopCounter <> 0
FINISH_AI_RACERS(Race.Racer[iLoopCounter])
ENDIF
ENDREPEAT
ENDPROC
PROC TRI_Race_Racer_Gate_Jump(TRI_RACE_STRUCT& Race, INT iRacer, INT iGate, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("TRI_Race_Racer_Gate_Jump")
IF (iGate < 0) OR (iGate > (Race.iGateCnt - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Gate_Jump: Gate index out of range!")
EXIT
ENDIF
IF (iRacer < 0) OR (iRacer > (Race.iRacerCnt - 1))
DEBUG_MESSAGE("TRI_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 = TRI_PLANE_SPD_MAX
ENDIF
IF bBlockLoad
LOAD_SCENE(Race.sGate[iGate].vPos)
CPRINTLN(DEBUG_TRIATHLON, "LOAD_SCENE :: TRI_Race_Racer_Gate_Jump")
ENDIF
TRI_Racer_Teleport(Race.Racer[iRacer], Race.sGate[iGate].vPos, fHeading, fSpeed)
ENDPROC
PROC TRI_Race_Racer_Gate_Jump_Cur(TRI_RACE_STRUCT& Race, INT iRacer, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("TRI_Race_Racer_Gate_Jump_Cur")
TRI_Race_Racer_Gate_Jump(Race, iRacer, Race.Racer[iRacer].iGateCur, bBlockLoad)
ENDPROC
PROC TRI_Race_Racer_Gate_Jump_Nxt(TRI_RACE_STRUCT& Race, INT iRacer, BOOL bBlockLoad = FALSE)
//DEBUG_MESSAGE("TRI_Race_Racer_Gate_Jump_Nxt")
TRI_Race_Racer_Gate_Jump(Race, iRacer, Race.Racer[iRacer].iGateCur - 1, bBlockLoad)
ENDPROC
/// PURPOSE:
/// Calculate placing
/// PARAMS:
/// Race -
/// iRacer -
PROC TRI_Race_Racer_Rank_Calc(TRI_RACE_STRUCT& Race, INT iRacer)
//DEBUG_MESSAGE("TRI_Race_Racer_Rank_Calc")
IF (iRacer < 0) OR (iRacer > (Race.iRacerCnt - 1))
DEBUG_MESSAGE("TRI_Race_Racer_Rank_Calc: Racer index out of range!")
EXIT
ENDIF
INT nRank = Race.iRacerCnt
INT i
TRI_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 TRI_Race_Racer_Fix_Up_Start(VECTOR vCurGatePos1, VEHICLE_INDEX iPlaneIndex, VECTOR vCurGatePos, BOOL bIsStart)
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
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()
ENDIF
ENDPROC
PROC DELETE_ALL_TRI_RACERS( TRI_RACE_STRUCT& Race )
INT iIndex
REPEAT Race.iRacerCnt iIndex
IF iIndex <> 0
IF DOES_ENTITY_EXIST( Race.Racer[iIndex].Driver )
DELETE_PED( Race.Racer[iIndex].Driver )
ENDIF
IF DOES_ENTITY_EXIST( Race.Racer[iIndex].Vehicle )
DELETE_VEHICLE( Race.Racer[iIndex].Vehicle )
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC REMOVE_ALL_BLIPS(TRI_RACE_STRUCT& Race)
INT idx
REPEAT COUNT_OF(Race.Racer) idx
IF DOES_BLIP_EXIST(Race.Racer[idx].Blip)
REMOVE_BLIP(Race.Racer[idx].Blip)
ENDIF
ENDREPEAT
TRI_Race_Gate_Deactivate_All(Race)
REMOVE_BLIP(blipPlayerVehicle)
REMOVE_BLIP(blipBikes)
REMOVE_BLIP(blipBikesEdge)
ENDPROC
/// PURPOSE:
/// Data func, switches on eCurrentRace
/// PARAMS:
/// vOutOfWayPos - by reference!
/// fOutOfWayHeading - by reference!
PROC TRI_GET_OUT_OF_WAY_POS_AND_HEADING( VECTOR & vOutOfWayPos, FLOAT & fOutOfWayHeading )
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_VESPUCCI
vOutOfWayPos = <<-1207.5099, -2026.7349, 12.9482>>
fOutOfWayHeading = 308.5434
BREAK
CASE TRIATHLON_RACE_ALAMO_SEA
vOutOfWayPos = <<2437.4600, 4296.9795, 35.6404>>
fOutOfWayHeading = 309.8143
BREAK
CASE TRIATHLON_RACE_IRONMAN
vOutOfWayPos = <<1608.7355, 3816.3923, 33.8315>>
fOutOfWayHeading = 310.0850
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Sets the player's vehicle out of the way near the origin of the race.
PROC TRI_POSITION_VEHICLE_AT_RACE_ORIGIN()
// set vehicle coords here.
VECTOR vOutOfWayPos
FLOAT fOutOfWayHeading
TRI_GET_OUT_OF_WAY_POS_AND_HEADING( vOutOfWayPos, fOutOfWayHeading )
SET_ENTITY_COORDS( vehPlayerDroveBeforeRace, vOutOfWayPos, FALSE )
SET_ENTITY_HEADING( vehPlayerDroveBeforeRace, fOutOfWayHeading )
CDEBUG2LN( DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_POSITION_VEHICLE_AT_RACE_ORIGIN], warping out of view" )
ENDPROC
/// PURPOSE:
/// Reset SPR Race Racer.
/// RETURNS:
/// TRUE if resetting SPR Race Racer.
FUNC BOOL TRI_Race_Racer_Reset(TRI_RACE_STRUCT& Race, TRI_RACER_STRUCT& Racer, BOOL bRacerIsPlayer)
//DEBUG_MESSAGE("[TRI_Race->TRI_Race_Racer_Reset] Starting function...")
//TEXT_LABEL_63 inputTest
// Reset Racer State Machine.
SWITCH (Racer.eReset)
// Failcase PLAYER HAS FORFEITED RACE
CASE TRI_RACER_RESET_FAIL_OVER
DEBUG_MESSAGE("TRI_RACER_RESET_FAIL_OVER")
CLEAR_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
REMOVE_ALL_BLIPS(Race)
CLEAR_PRINTS()
CLEAR_HELP()
TRI_Race_Gate_Deactivate_All(Race)
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
ENDIF
ELSE
IF NOT IS_ENTITY_DEAD(GET_PLAYERS_LAST_VEHICLE())
SET_VEHICLE_DOORS_LOCKED(GET_PLAYERS_LAST_VEHICLE(), VEHICLELOCK_UNLOCKED)
ENDIF
ENDIF
ENDIF
//SET_SCALEFORM_BIG_MESSAGE(Race.bigMessageUI, "SPR_UI_FAILD", Race.FailString, -1, HUD_COLOUR_RED, DEFAULT, TRUE, 0.15)
MG_INIT_FAIL_SPLASH_SCREEN(splashState)
Racer.eReset = TRI_RACER_RESET_FAIL_SELECT_RETRY
BREAK
CASE TRI_RACER_RESET_FAIL_SELECT_RETRY
DEBUG_MESSAGE("TRI_RACER_RESET_FAIL_SELECT_RETRY")
BOOL bRestart
TRI_Master.bQuitting = TRUE
IF MG_UPDATE_FAIL_SPLASH_SCREEN(Race.bigMessageUI, splashState, "SPR_UI_FAILD", Race.FailString, bRestart)
IF bRestart
//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
SET_MINIGAME_SPLASH_SHOWING(FALSE)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0)
ENDIF
Race.bRestarting = TRUE
TRI_Master.bQuitting = FALSE
SET_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
ANIMPOSTFX_STOP_ALL()
RESET_TRI_NEWS_EVENTS()
Racer.eReset = TRI_RACER_RESET_FADE_OUT
ELSE
DEBUG_MESSAGE("[TRI_Race->TRI_Race_Racer_Reset] CASE TRI_RACER_RESET_FAIL_OVER: CASE GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_Y): eReset = TRI_RACER_QUIT_FADE_OUT")
ADJUST_TIMER(exitTimer, 10.0)
SET_MINIGAME_SPLASH_SHOWING(FALSE)
Race.bRestarting = FALSE
CLEAR_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
ANIMPOSTFX_STOP_ALL()
Racer.eReset = TRI_RACER_QUIT_EXIT
ENDIF
ENDIF
BREAK
// Reset racer (init).
CASE TRI_RACER_RESET_INIT
IF IS_TRI_CONTROL_FLAG_SET(TCF_RACE_RESTARTING)
CLEAR_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
DEBUG_MESSAGE("TRI_RACER_RESET_INIT: TCF_FAIL_CHECKING cleared")
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)
CDEBUG2LN(DEBUG_TRIATHLON, "TRI_Race_Racer_Reset :: TRI_RACER_RESET_INIT SPR_UI_RESET")
SET_PLAYER_INVINCIBLE(PLAYER_ID(), TRUE)
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, TRUE, FALSE, FALSE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_UI_RESET", FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_UI_QUIT", FRONTEND_CONTROL, INPUT_FRONTEND_Y)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_UI_RESTART", FRONTEND_CONTROL, INPUT_FRONTEND_X)
SET_SIMPLE_USE_CONTEXT_FULLSCREEN(TRI_Master.uiInput, TRUE)
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 TRI_RACER_RESET_CHOOSE")
Racer.eReset = TRI_RACER_RESET_CHOOSE
//ENDIF
ENDIF
ELSE // Otherwise, racer is ai, go to create state.
DEBUG_MESSAGE("Moving to TRI_RACER_RESET_CREATE")
Racer.eReset = TRI_RACER_RESET_CREATE
ENDIF
BREAK
// Choose reset/restart.
CASE TRI_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
CLEAR_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
IF (GET_TIMER_IN_SECONDS(exitTimer) <= 10.0)
// If racer is player, display reset/restart options.
IF bRacerIsPlayer
UPDATE_SIMPLE_USE_CONTEXT(TRI_Master.uiInput)
IF IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_FRONTEND_RUP )
// Restart race.
SET_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
DEBUG_MESSAGE("Moving to TRI_RACER_RESET_FADE_OUT")
PLAY_SOUND_FRONTEND(-1, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
Racer.eReset = TRI_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.
IF NOT (TRI_Master.eRaceType = TRI_RACE_TYPE_TRIATHLON)
// This command also sets the cinematic cam back to true, so turning off for Tri.
KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
ENDIF
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
ENDIF
ENDIF
ENDIF
ELIF IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT )
// Reset vehicle.
DEBUG_MESSAGE("Moving to TRI_RACER_RESET_FADE_OUT")
PLAY_SOUND_FRONTEND(-1, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
Racer.eReset = TRI_RACER_RESET_FADE_OUT
ELIF IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_FRONTEND_RUP )
CLEAR_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
//kill the chase came so if we were looking at
//it when we reset the camera is still not looking at it.
IF NOT (TRI_Master.eRaceType = TRI_RACE_TYPE_TRIATHLON)
// This command also sets the cinematic cam back to true, so turning off for Tri.
KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
ENDIF
IF (TRI_Master.eRaceType = TRI_RACE_TYPE_OFFROAD)
TRI_Master.iRaceCur = -1 //forcing a quit here as there is no menu for offroad races
DEBUG_MESSAGE("Moving to TRI_RACER_QUIT_FADE_IN")
PLAY_SOUND_FRONTEND(-1, "Phone_Generic_Key_03", "HUD_MINIGAME_SOUNDSET")
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
ENDIF
ENDIF
ENDIF
Racer.eReset = TRI_RACER_QUIT_FADE_IN
ELSE
DEBUG_MESSAGE("Moving to TRI_RACER_QUIT_FADE_OUT")
ADJUST_TIMER(exitTimer, 10.0)
PLAY_SOUND_FRONTEND(-1, "Phone_Generic_Key_03", "HUD_MINIGAME_SOUNDSET")
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
ENDIF
ENDIF
ENDIF
Racer.eReset = TRI_RACER_QUIT_EXIT
ENDIF
ENDIF
ENDIF
ELSE
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Vehicle)
SET_VEHICLE_DOORS_LOCKED(Race.Racer[0].Vehicle, VEHICLELOCK_UNLOCKED)
ENDIF
Racer.eReset = TRI_RACER_QUIT_EXIT
ENDIF
BREAK
// Fade out.
CASE TRI_RACER_RESET_FADE_OUT
IF TRI_FadeOut_Safe(TRI_FADE_QUICK_TIME)
CLEAR_PRINTS()
CLEAR_HELP()
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race.sch->TRI_Race_Racer_Reset] eReset: From TRI_RACER_RESET_FADE_OUT to TRI_RACER_RESET_CREATE")
Racer.eReset = TRI_RACER_RESET_CREATE
ENDIF
BREAK
// Fade out from quitting race.
CASE TRI_RACER_QUIT_FADE_OUT
IF TRI_FadeOut_Safe(TRI_FADE_QUICK_TIME)
// Cleanup the race.
TRI_Race_Gate_Deactivate_All(Race)
CANCEL_TIMER(Race.tClock)
// Give back player control.
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)//, SPC_ALLOW_PLAYER_DAMAGE)
DEBUG_MESSAGE("[TRI_Race->TRI_Race_Racer_Reset] CASE TRI_RACER_QUIT_FADE_OUT: eReset = TRI_RACER_QUIT_PLACE")
Racer.eReset = TRI_RACER_QUIT_PLACE
ENDIF
BREAK
// Create racer.
CASE TRI_RACER_RESET_CREATE
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race.sch->TRI_Race_Racer_Reset] TRI_RACER_RESET_CREATE: Case started.")
// Was player in either a running or swimming checkpoint.
IF (Race.sGate[Race.Racer[0].iGateCur].eChkpntType = TRI_CHKPT_TRI_BIKE) OR (Race.sGate[Race.Racer[0].iGateCur].eChkpntType = TRI_CHKPT_TRI_SECOND_TRANS)
TRI_Racer_Tribike_Create(Racer)
// Otherwise, player was in a bike checkpoint.
ELSE
TRI_Racer_TriRacer_Create(Racer)
ENDIF
IF IS_TRI_CONTROL_FLAG_SET(TCF_RACE_RESTARTING)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race.sch->TRI_Race_Racer_Reset] From TRI_RACER_RESET_CREATE to TRI_RACE_UPDATE_CLEANUP.")
// Since we're restarting, let's ensure the player does not have an equipped weapon at the start of the race.
IF NOT IS_PED_INJURED(Race.Racer[0].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race_Racer_Reset] TRI_RACER_RESET_CREATE: Setting the player unarmed.")
SET_CURRENT_PED_WEAPON(Race.Racer[0].Driver, WEAPONTYPE_UNARMED, TRUE)
SET_PED_CURRENT_WEAPON_VISIBLE(Race.Racer[0].Driver, TRUE)
ENDIF
TRI_POSITION_VEHICLE_AT_RACE_ORIGIN()
Race.eUpdate = TRI_RACE_UPDATE_CLEANUP
ELSE
// 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)
ENABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_VEH_EXIT )
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race.sch->TRI_Race_Racer_Reset] From TRI_RACER_RESET_CREATE to TRI_RACER_RESET_PLACE.")
Racer.eReset = TRI_RACER_RESET_PLACE
ENDIF
BREAK
// Place racer during reset.
CASE TRI_RACER_RESET_PLACE
IF bRacerIsPlayer
// Check if the checkpoint the player was going to is not a bike checkpoint.
IF (Race.sGate[Race.Racer[0].iGateCur].eChkpntType = TRI_CHKPT_TRI_BIKE) OR (Race.sGate[Race.Racer[0].iGateCur].eChkpntType = TRI_CHKPT_TRI_SECOND_TRANS)
TRI_Racer_Tribike_Place(Race, Racer)
ELSE
TRI_Racer_Triracer_Place(Race, Racer)
ENDIF
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race.sch->TRI_Race_Racer_Reset] From TRI_RACER_RESET_PLACE to TRI_RACER_RESET_FADE_IN.")
Racer.eReset = TRI_RACER_RESET_FADE_IN
ELSE // Otherwise, racer is ai, go to wait state.
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Race.sch->TRI_Race_Racer_Reset] From TRI_RACER_RESET_PLACE to TRI_RACER_RESET_WAIT.")
Racer.eReset = TRI_RACER_RESET_WAIT
ENDIF
BREAK
CASE TRI_RACER_QUIT_PLACE
// TODO: We may have to update this later on to determine where the player is teleported
// based on the race location, or if teleporting him is even desired.
TRI_Racer_Teleport(Racer, TRI_Master.vDefRcrPos, TRI_Master.fDefRcrHead , 0.0)
NEW_LOAD_SCENE_START_SPHERE(TRI_Master.vDefRcrPos, 100)
DELETE_ALL_TRI_RACERS(Race)
DEBUG_MESSAGE("[TRI_Race->TRI_Race_Racer_Reset] CASE TRI_RACER_QUIT_PLACE: eReset = TRI_RACER_QUIT_FADE_IN")
Racer.eReset=TRI_RACER_QUIT_FADE_IN
BREAK
// Fade in.
CASE TRI_RACER_RESET_FADE_IN
IF NOT IS_NEW_LOAD_SCENE_ACTIVE()
OR IS_NEW_LOAD_SCENE_LOADED()
SET_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
DEBUG_MESSAGE("TRI_RACER_RESET_FADE_IN: TCF_FAIL_CHECKING set")
IF TRI_FadeIn_Safe(TRI_FADE_QUICK_TIME)
NEW_LOAD_SCENE_STOP()
PRINTLN("TRI_Race_Racer_Fix_Up_Start: NEW_LOAD_SCENE_STOP")
DEBUG_MESSAGE("RACER_RESET_FADE_IN: FAILCHECKING: ON")
DEBUG_MESSAGE("Going to RESET_WAIT from QUIT_FADE_IN")
Racer.eReset = TRI_RACER_RESET_WAIT
ENDIF
// Reset SPR Racer waiting.
RETURN FALSE
ELSE
PRINTLN("[tri_Race.sch->TRI_Race_Racer_Reset] Waiting on IS_NEW_LOAD_SCENE_LOADED")
ENDIF
BREAK
CASE TRI_RACER_QUIT_FADE_IN
// Auto-pilot racer while waiting for fade in.
//TRI_Racer_AutoPilot(Race.Racer[i], TRI_PLANE_SPD_MAX, FALSE)
IF TRI_FadeIn_Safe(TRI_FADE_QUICK_TIME)
// Clean Scaleform UI for reset/restart.
DEBUG_MESSAGE("[TRI_Race->TRI_Race_Racer_Reset] CASE TRI_RACER_QUIT_FADE_IN: eUpdate = TRI_RACE_UPDATE_CLEANUP")
Race.eUpdate = TRI_RACE_UPDATE_CLEANUP
ENDIF
// Reset SPR Racer waiting.
RETURN FALSE
BREAK
// Reset racer (wait).
CASE TRI_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 TRI_Racer_Crash_Check(Racer)
//// OR ( NOT IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) AND (TRI_Master.eRaceType != TRI_RACE_TYPE_OFFROAD) )
// DEBUG_MESSAGE("Player isn't in the vehicle, moving to TRI_RACER_RESET_INIT")
// RESTART_TIMER_NOW(exitTimer)
// Racer.eReset = TRI_RACER_RESET_INIT
// RETURN TRUE
// ENDIF
// ENDIF
// ENDIF
// Reset SPR Racer waiting.
RETURN FALSE
BREAK
CASE TRI_RACER_QUIT_EXIT
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
ENDIF
ENDIF
SET_PLAYER_INVINCIBLE(PLAYER_ID(), FALSE)
ENDIF
TRI_Race_Gate_Deactivate_All(Race)
CANCEL_TIMER(Race.tClock)
Race.eUpdate = TRI_RACE_UPDATE_CLEANUP
BREAK
ENDSWITCH
// Reset SPR Racer running.
RETURN TRUE
ENDFUNC
FUNC STRING GET_STRING_FROM_TRI_RACE_INDEX(TRIATHLON_RACE_INDEX eRace)
RETURN PICK_STRING(eRace = TRIATHLON_RACE_NONE, "TRIATHLON_RACE_NONE",
PICK_STRING(eRace = TRIATHLON_RACE_VESPUCCI, "TRIATHLON_RACE_VESPUCCI",
PICK_STRING(eRace = TRIATHLON_RACE_ALAMO_SEA, "TRIATHLON_RACE_ALAMO_SEA",
PICK_STRING(eRace = TRIATHLON_RACE_IRONMAN, "TRIATHLON_RACE_IRONMAN",
PICK_STRING(eRace = NUM_TRIATHLON_RACES, "NUM_TRIATHLON_RACES",
"Unknown Race Index")))))
ENDFUNC
PROC TRI_UPDATE_RACERS_OFF_BIKE( TRI_RACE_STRUCT& Race, TRI_RACER_STRUCT& Racer )
IF Tri_Get_Racer_Current_Race_Leg(Race, Racer) <> TRI_TRI_RACE_LEG_BIKE
EXIT
ENDIF
IF IS_ENTITY_DEAD( Racer.Driver ) OR IS_PED_INJURED( Racer.Driver )
EXIT
ENDIF
IF NOT DOES_ENTITY_EXIST( Racer.Vehicle ) OR IS_ENTITY_DEAD( Racer.Vehicle )
EXIT
ENDIF
IF NOT IS_PED_IN_ANY_VEHICLE( Racer.Driver, TRUE ) AND GET_SCRIPT_TASK_STATUS( Racer.Driver, SCRIPT_TASK_PERFORM_SEQUENCE ) <> PERFORMING_TASK
VECTOR vBikePos = GET_ENTITY_COORDS(Racer.Vehicle)
VECTOR vOffset = (GET_ENTITY_COORDS(Racer.Driver) - vBikePos) * 0.15
VECTOR vDest = vBikePos + vOffset
SEQUENCE_INDEX siSeq
OPEN_SEQUENCE_TASK(siSeq)
// Navigate the ped to the bike.
TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, vDest, PEDMOVE_SPRINT, DEFAULT_TIME_BEFORE_WARP, 3.0, ENAV_NO_STOPPING)
// Tell racer to get on bike.
TASK_ENTER_VEHICLE(NULL, Racer.Vehicle, DEFAULT_TIME_BEFORE_WARP, VS_DRIVER, PEDMOVEBLENDRATIO_SPRINT)
// Tell racer to follow waypoint recording.
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(NULL, Racer.Vehicle, Racer.szCurrentBikeRecordingName,
DRIVINGMODE_AVOIDCARS | DF_SteerAroundPeds,
0, EWAYPOINT_START_FROM_CLOSEST_POINT, -1, -1)
CLOSE_SEQUENCE_TASK(siSeq)
TASK_PERFORM_SEQUENCE(Racer.Driver, siSeq)
CLEAR_SEQUENCE_TASK( siSeq )
ENDIF
ENDPROC
/// PURPOSE:
/// Update SPR Race Racers.
/// RETURNS:
/// TRUE if still updating SPR Race Racers.
FUNC BOOL TRI_Race_Racer_Update(TRI_RACE_STRUCT& Race)
// Local variables.
FLOAT fClockTime
INT i
//INT iLightsOn, iFullBeam
// Cache current race clock time.
IF IS_TIMER_STARTED(Race.tClock)
fClockTime = GET_TIMER_IN_SECONDS(Race.tClock)
ENDIF
// Store our old bonus.
// FLOAT fOldBonus = Race.Racer[0].fPlsMnsTot
// 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 NOT IS_PED_INJURED(Race.Racer[i].Driver) AND (Race.Racer[i].iGateCur < Race.iGateCnt)
TRI_GATE_STRUCT GateCur
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 (Race.Racer[i].Driver = PLAYER_PED_ID())
IF Race.Racer[i].iGateCur > 0
IF Race.sGate[Race.Racer[i].iGateCur-1].bIsFading
CDEBUG1LN(DEBUG_TRIATHLON, "[TRI_Race_Racer_Update] Gate ", Race.Racer[i].iGateCur-1, " is fading.")
TRI_RACE_MANAGE_GATE_FADE_ON_PASS(Race, Race.Racer[i].iGateCur-1)
ENDIF
ENDIF
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
IF NOT bRacerIsPlayer
IF IS_TRI_AI_CONTROL_FLAG_SET(Race.Racer[i],TACF_BSETSPEED)
SET_PED_MIN_MOVE_BLEND_RATIO( Race.Racer[i].Driver, PEDMOVE_SPRINT )
ENDIF
ENDIF
IF bRacerIsPlayer
IF Race.ePlayerRespawnState = TRI_RESPAWN_CHECK
DRAW_GENERIC_METER( ROUND( GET_TIMER_IN_SECONDS( resetTimer ) * 1000 ), 1500, "RACES_RMETER", HUD_COLOUR_RED, 0, HUDORDER_EIGHTHBOTTOM, -1, -1, FALSE, TRUE )
ENDIF
ENDIF
// Make sure racer isn't resetting before continuing.
IF NOT TRI_Race_Racer_Reset(Race, Race.Racer[i], bRacerIsPlayer)
// Vehicle water check
IF bRacerIsPlayer
//AND IS_TRI_CONTROL_FLAG_SET(TCF_FAIL_CHECKING)
IF IS_CONTROL_ENABLED( PLAYER_CONTROL, INPUT_VEH_EXIT )
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_VEH_EXIT )
ENDIF
IF (IS_CONTROL_JUST_RELEASED( PLAYER_CONTROL, INPUT_VEH_EXIT )
OR IS_DISABLED_CONTROL_JUST_RELEASED( PLAYER_CONTROL, INPUT_VEH_EXIT ) )
AND NOT Race.bPlayerRespawning
Race.ePlayerRespawnState = TRI_RESPAWN_SET
IF IS_PED_IN_ANY_VEHICLE( PLAYER_PED_ID() )
TASK_LEAVE_ANY_VEHICLE( PLAYER_PED_ID() )
ENDIF
ELIF IS_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_VEH_EXIT )
OR IS_DISABLED_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_VEH_EXIT )
OR Race.bPlayerRespawning
SWITCH Race.eplayerRespawnState
CASE TRI_RESPAWN_SET
RESTART_TIMER_NOW( resetTimer )
CPRINTLN( DEBUG_TRIATHLON, "Switching respawn state to RESPAWN_INIT" )
Race.ePlayerRespawnState = TRI_RESPAWN_INIT
BREAK
CASE TRI_RESPAWN_INIT
IF GET_TIMER_IN_SECONDS( resetTimer ) > 0.4
RESTART_TIMER_NOW( resetTimer )
Race.ePlayerRespawnState = TRI_RESPAWN_CHECK
CPRINTLN( DEBUG_TRIATHLON, "Switching respawn state to RESPAWN_CHECK" )
ENDIF
BREAK
CASE TRI_RESPAWN_CHECK
IF GET_TIMER_IN_SECONDS( resetTimer ) > 1.5
Race.ePlayerRespawnState = TRI_RESPAWN_ACTIVE
Race.Racer[0].eReset = TRI_RACER_RESET_FADE_OUT
CLEAR_BITMASK_AS_ENUM( TRI_HELP_BIT, TRI_RESET_HELP )
SET_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
Race.bPlayerRespawning = TRUE
CPRINTLN( DEBUG_TRIATHLON, "Switching respawn state to RESPAWN_ACTIVE" )
ENDIF
BREAK
CASE TRI_RESPAWN_ACTIVE
Race.ePlayerRespawnState = TRI_RESPAWN_WAIT
BREAK
CASE TRI_RESPAWN_WAIT
IF NOT IS_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_VEH_EXIT )
AND NOT IS_DISABLED_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_VEH_EXIT )
ENABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_VEH_EXIT )
CPRINTLN( DEBUG_TRIATHLON, "Switching respawn state to RESPAWN_WAIT" )
Race.ePlayerRespawnState = TRI_RESPAWN_SET
Race.bPlayerRespawning = FALSE
ENDIF
BREAK
ENDSWITCH
ENDIF
ENDIF
// Calculate racer rank.
TRI_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 TRI_Master.eRaceType = TRI_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, TRI_FORCE_GATE_ACTIVATION)
TRI_Race_Gate_Activate(Race, iGateCur, TRUE)
IF (iGateCur < (Race.iGateCnt - 1))
TRI_Race_Gate_Activate(Race, iGateCur + 1, FALSE)
ENDIF
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_FORCE_GATE_ACTIVATION)
ENDIF
ENDIF
// Check if racer has passed/missed their current gate.
IF IS_TRI_CONTROL_FLAG_SET(TCF_FAIL_CHECKING)
Race.iGateCheck = ENUM_TO_INT(TRI_CHECK_RACER_GATE_STATUS(Race, GateCur, Race.Racer[i].Driver, i))
TRI_GATE_STRUCT GateNxt
IF (iGateCur < (Race.iGateCnt-1))
GateNxt = Race.sGate[iGateCur + 1]
ELSE
GateNxt = GateCur
ENDIF
TRI_RACE_MANAGE_CHECKPOINT_ALPHAS(GateCur, GateNxt)
ENDIF
IF NOT bRacerIsPlayer
TRI_UPDATE_RACERS_OFF_BIKE( Race, Race.Racer[i] )
ENDIF
IF Race.iGateCheck = ENUM_TO_INT(TRI_RACE_GATE_STATUS_PASS)
// 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 didn't clear the last gate, then fade out the checkpoint. If we just cleared the last gate, just delete it.
IF (iGateCur-1) < Race.iGateCnt-1
// Passing FALSE here to avoid deleting the checkpoint, as TRI_RACE_MANAGE_ALL_GATES_FADE_ON_PASS will handle deletion after fading.
TRI_Race_Gate_Deactivate(Race, iGateCur - 1, FALSE)
// Turn the checkpoint white with the same alpha used to create the checkpoint.
SET_CHECKPOINT_RGBA(Race.sGate[iGateCur-1].Chkpnt, 255, 255, 255, Race.sGate[iGateCur-1].iHUDAlphaAfterPass)
SET_CHECKPOINT_RGBA2(Race.sGate[iGateCur-1].Chkpnt, 255, 255, 255, Race.sGate[iGateCur-1].iHUDAlphaAfterPass)
// Set the checkpoint as can be faded.
Race.sGate[iGateCur-1].bIsFading = TRUE
ELSE
TRI_Race_Gate_Deactivate(Race, iGateCur - 1)
ENDIF
IF (iGateCur = Race.iGateCnt)
IF NOT IS_TIMER_PAUSED(Race.tClock)
PAUSE_TIMER(Race.tClock)
ENDIF
// RACE END.
TRIGGER_MUSIC_EVENT("MGTR_COMPLETE")
START_AUDIO_SCENE("TRI_END_SCENE")
STOP_AUDIO_SCENE("TRI_RUN_SCENE")
CPRINTLN(DEBUG_TRIATHLON, "[spr_race.sch->TRI_Race_Racer_Update] MGTR_COMPLETE triggered")
RETURN FALSE
// Otherwise, activate new current/next gates.
ELSE
TRI_Race_Gate_Activate(Race, iGateCur, TRUE)
IF (iGateCur < (Race.iGateCnt - 1))
TRI_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 TRI_Master.eRaceType <> TRI_RACE_TYPE_TRIATHLON
IF NOT IS_ENTITY_DEAD(Race.Racer[i].Driver)
FINISH_AI_RACERS(Race.Racer[i])
ENDIF
ENDIF
ELSE
IF i != 0 //not the player!?
TRI_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
ENDIF
ENDIF
ENDREPEAT
IF IS_TRI_CONTROL_FLAG_SET(TCF_FAIL_CHECKING)
DEBUG_MESSAGE("ACTIVELY CHECKING FAIL CASES")
RESET_TUTORIAL(Race)
EXIT_VEHICLE_FAILURE(Race, blipPlayerVehicle)
Dead_Race_Vehicle(Race, blipPlayerVehicle)
wantedFailure(Race)
waterFailure(Race)
vehicleFailure(Race)
// idleFailure(Race)
Disable_Airport_Icons()
RUN_OFFROAD_AUDIO(Race)
TRI_Race_Draw_HUD(Race)
ENDIF
// Update SPR Race Racers still running.
RETURN TRUE
ENDFUNC
// -----------------------------------
// FILE I/O PROCS/FUNCTIONS
// -----------------------------------
/// PURPOSE:
/// Init SPR Race.
PROC TRI_Race_Init(TRI_RACE_STRUCT& Race)
DEBUG_MESSAGE("TRI_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 (TRI_Master.iRaceCur <> -1)
FLOAT fBestClockTime = TRI_Global_BestTime_Get(TRI_Master.iRaceCur)
IF (fBestClockTime <= 0.0)
OR (fBestClockTime > TRI_Master.fRaceTime[TRI_Master.iRaceCur])
fBestClockTime = TRI_Master.fRaceTime[TRI_Master.iRaceCur]
ENDIF
Race.fBestClockTime = fBestClockTime
Race.fBestSplitTime = Race.fBestClockTime / 2.0
ENDIF
TRI_Race_Gate_Init_All(Race)
Race.iGateCnt = 0
TRI_Race_Racer_Init_All(Race)
Race.iRacerCnt = 0
//CLEAR_AREA_AROUND_TRI_POS(GET_ENTITY_COORDS(PLAYER_PED_ID(),FALSE))
// 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 TRI_Race_Load(TRI_RACE_STRUCT& Race, STRING sRaceFileName)
DEBUG_MESSAGE("TRI_Race_Load")
// Assemble filename for Race XML file.
TEXT_LABEL_63 szFileName
szFileName = TRI_Master.szTRIPath
szFileName += TRI_Master.szMainPath
szFileName += TRI_Master.szRacesPath
szFileName += sRaceFileName
szFileName += ".xml"
// Load Race XML file into memory.
DEBUG_MESSAGE("TRI_Race_Load: Opening filepath: ", TRI_Master.szXMLPath)
DEBUG_MESSAGE("TRI_Race_Load: Opening filename: ", szFileName)
IF NOT TRI_XML_Load(szFileName)
SCRIPT_ASSERT("TRI_Race_Load: Failed to load Race XML file!")
DELETE_XML_FILE()
RETURN FALSE
ENDIF
DEBUG_MESSAGE("TRI_Race_Load: Started reading Race XML file: ", sRaceFileName)
// Local variables.
INT iTempBuff
FLOAT fTempBuff
VECTOR vTempBuff
FLOAT fGateRadius
TRI_RACE_CHECKPOINT_TYPE eChkpntType
TEXT_LABEL_31 szRacerName
PED_TYPE eDriverType
MODEL_NAMES eDriverModel
MODEL_NAMES eVehicleModel
BOOL bDataLimitReached
INT iNodeCnt, iNodeName, iAttrCnt
// Init race data.
TRI_Race_Init(Race)
// Start at root node of Race XML file.
TRI_XML_GetRootNode(iNodeCnt, iNodeName)
// Check for "Race" root node before continuing.
IF (iNodeName <> TRI_XML_HASH_RACE)
SCRIPT_ASSERT("TRI_Race_Load: Failed to find 'Race' root node")
DELETE_XML_FILE()
RETURN FALSE
ENDIF
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Race' root node")
TRI_XML_GetNextNode(iNodeCnt, iNodeName)
// Check for "Gates" parent node before continuing.
IF (iNodeName <> TRI_XML_HASH_GATES)
SCRIPT_ASSERT("TRI_Race_Load: Failed to find 'Gates' parent node")
DELETE_XML_FILE()
RETURN FALSE
ENDIF
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Gates' parent node")
TRI_XML_GetNextNode(iNodeCnt, iNodeName)
// Loop through each node of "Gates" branch.
bDataLimitReached = FALSE
WHILE (iNodeName <> TRI_XML_HASH_RACERS)
// Check for nodes in "Gates" branch.
SWITCH (iNodeName)
// "Gate" node.
CASE TRI_XML_HASH_GATE
// Check if "Gate" data limit has been reached.
IF (Race.iGateCnt >= TRI_GATE_MAX)
DEBUG_MESSAGE("TRI_Race_Load: Reached 'Gate' data limit")
bDataLimitReached = TRUE
BREAK
ENDIF
// Debug info.
PRINTSTRING("TRI_Race_Load: Inside 'Gate' node: ")
PRINTINT(Race.iGateCnt)
PRINTNL()
BREAK
// "Position" node.
CASE TRI_XML_HASH_POS
// Check if "Gate" data limit has been reached.
IF bDataLimitReached
BREAK
ENDIF
// Loop through each attribute of "Position" node and save data.
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Position' node")
vTempBuff = TRI_Master.vDefRcrPos
REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttrCnt
SWITCH (GET_HASH_KEY(GET_XML_NODE_ATTRIBUTE_NAME(iAttrCnt)))
CASE TRI_XML_HASH_X
vTempBuff.x = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'X' data")
BREAK
CASE TRI_XML_HASH_Y
vTempBuff.y = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Y' data")
BREAK
CASE TRI_XML_HASH_Z
vTempBuff.z = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Z' data")
BREAK
ENDSWITCH
ENDREPEAT
BREAK
// "Checkpoint" node.
CASE TRI_XML_HASH_CHKPNT
// Check if "Gate" data limit has been reached.
IF bDataLimitReached
BREAK
ENDIF
// Loop through each attribute of "Checkpoint" node and save data.
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Checkpoint' node")
fGateRadius = TRI_GATE_CHKPNT_SCL
eChkpntType = TRI_CHKPT_OFFROAD_DEFAULT
REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttrCnt
SWITCH (GET_HASH_KEY(GET_XML_NODE_ATTRIBUTE_NAME(iAttrCnt)))
CASE TRI_XML_HASH_RADIUS
fGateRadius = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Radius' data")
BREAK
CASE TRI_XML_HASH_TYPE
iTempBuff = GET_INT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
eChkpntType = TRI_ChkpntType_GetEnum(iTempBuff)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Type' data")
BREAK
CASE TRI_XML_HASH_STUNT
iTempBuff = GET_INT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
BREAK
ENDSWITCH
ENDREPEAT
// Setup race Gate using saved data from "Position"/"Checkpoint" nodes.
TRI_Gate_Setup(Race.sGate[Race.iGateCnt], vTempBuff, fGateRadius, eChkpntType)
PRINTSTRING("TRI_Race_Load: Setup Gate: ")
PRINTINT(Race.iGateCnt)
PRINTNL()
// Increment race Gate count.
++Race.iGateCnt
BREAK
ENDSWITCH
// Get next node of "Gates" branch.
TRI_XML_GetNextNode(iNodeCnt, iNodeName)
ENDWHILE
// Ensure there is at least 1 gate.
IF (Race.iGateCnt <= 0)
Race.iGateCnt = 1
ENDIF
// Check for "Racers" parent node before continuing.
IF (GET_HASH_KEY(GET_XML_NODE_NAME()) <> TRI_XML_HASH_RACERS)
SCRIPT_ASSERT("TRI_Race_Load: Failed to find 'Racers' parent node")
DELETE_XML_FILE()
RETURN FALSE
ENDIF
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Racers' parent node")
TRI_XML_GetNextNode(iNodeCnt, iNodeName)
// Loop through each node of "Racers" branch.
bDataLimitReached = FALSE
WHILE (iNodeCnt < GET_NUMBER_OF_XML_NODES())
// Check for nodes in "Racers".
SWITCH (iNodeName)
// "Racer" node.
CASE TRI_XML_HASH_RACER
// Check if "Racer" data limit has been reached.
IF (Race.iRacerCnt >= TRI_RACER_MAX)
DEBUG_MESSAGE("TRI_Race_Load: Reached 'Racer' data limit")
bDataLimitReached = TRUE
BREAK
ENDIF
// Debug info.
PRINTSTRING("TRI_Race_Load: Inside 'Racer' node: ")
PRINTINT(Race.iRacerCnt)
PRINTNL()
// Loop through each attribute of "Racer" node and save data.
szRacerName = "Racer"
REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttrCnt
SWITCH (GET_HASH_KEY(GET_XML_NODE_ATTRIBUTE_NAME(iAttrCnt)))
CASE TRI_XML_HASH_NAME
szRacerName = GET_STRING_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Name' data")
BREAK
ENDSWITCH
ENDREPEAT
BREAK
// "Location" node.
CASE TRI_XML_HASH_LOC
// Check if "Racer" data limit has been reached.
IF bDataLimitReached
BREAK
ENDIF
// Loop through each attribute of "Location" node and save data.
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Location' node")
vTempBuff = TRI_Master.vDefRcrPos
fTempBuff = TRI_Master.fDefRcrHead
REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttrCnt
SWITCH (GET_HASH_KEY(GET_XML_NODE_ATTRIBUTE_NAME(iAttrCnt)))
CASE TRI_XML_HASH_X
vTempBuff.x = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'X' data")
BREAK
CASE TRI_XML_HASH_Y
vTempBuff.y = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Y' data")
BREAK
CASE TRI_XML_HASH_Z
vTempBuff.z = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Z' data")
BREAK
CASE TRI_XML_HASH_H
fTempBuff = GET_FLOAT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'H' data")
BREAK
ENDSWITCH
ENDREPEAT
BREAK
// "Driver" node.
CASE TRI_XML_HASH_DRIVER
// Check if "Racer" data limit has been reached.
IF bDataLimitReached
BREAK
ENDIF
// Loop through each attribute of "Driver" node and save data.
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Driver' node")
eDriverType = TRI_Master.eDefDrvType
eDriverModel = TRI_Master.eDefDrvModel
REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttrCnt
SWITCH (GET_HASH_KEY(GET_XML_NODE_ATTRIBUTE_NAME(iAttrCnt)))
CASE TRI_XML_HASH_TYPE
iTempBuff = GET_INT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
eDriverType = TRI_DriverType_GetEnum(iTempBuff)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Type' data")
BREAK
CASE TRI_XML_HASH_MODEL
iTempBuff = GET_INT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
eDriverModel = TRI_DriverModel_GetEnum(iTempBuff)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Model' data")
BREAK
ENDSWITCH
ENDREPEAT
BREAK
// "Vehicle" node.
CASE TRI_XML_HASH_VEHICLE
// Check if "Racer" data limit has been reached.
IF bDataLimitReached
BREAK
ENDIF
// Loop through each attribute of "Vehicle" node and save data.
DEBUG_MESSAGE("TRI_Race_Load: Inside 'Vehicle' node")
eVehicleModel = TRI_Master.eDefVehModel
REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttrCnt
SWITCH (GET_HASH_KEY(GET_XML_NODE_ATTRIBUTE_NAME(iAttrCnt)))
CASE TRI_XML_HASH_MODEL
iTempBuff = GET_INT_FROM_XML_NODE_ATTRIBUTE(iAttrCnt)
eVehicleModel = TRI_VehicleModel_GetEnum(iTempBuff)
DEBUG_MESSAGE("TRI_Race_Load: Saved 'Model' data")
BREAK
ENDSWITCH
ENDREPEAT
// Setup race Racer using saved data from "Location"/"Driver"/"Vehicle" nodes.
// TODO: Forcing entity for player. May want to figure out a better way to do this...
TRI_Racer_Setup_Misc(Race.Racer[Race.iRacerCnt])
TRI_Racer_Setup_Name(Race.Racer[Race.iRacerCnt], szRacerName)
// TODO: Making all entities NULL from start for editor. Figure out way for race...
//IF (Race.Racer[Race.iRacerCnt].eDriverType <= PEDTYPE_PLAYER_UNUSED)
//TRI_Racer_Setup_Entities(Race.Racer[Race.iRacerCnt], PLAYER_PED_ID(), TRI_Master.PlayerVeh)
//ELSE
TRI_Racer_Setup_Entities(Race.Racer[Race.iRacerCnt], NULL, NULL)
//ENDIF
TRI_Racer_Setup_Start(Race.Racer[Race.iRacerCnt], vTempBuff, fTempBuff)
TRI_Racer_Setup_Types(Race.Racer[Race.iRacerCnt], eDriverType, eDriverModel, eVehicleModel)
PRINTSTRING("TRI_Race_Load: Setup Racer: ")
PRINTINT(Race.iRacerCnt)
PRINTNL()
// Increment race Racer count.
++Race.iRacerCnt
BREAK
ENDSWITCH
// Get next node of "Racers" branch.
TRI_XML_GetNextNode(iNodeCnt, iNodeName)
ENDWHILE
// Ensure there is at least 1 racer.
IF (Race.iRacerCnt <= 0)
Race.iRacerCnt = 1
ENDIF
// Unload Race XML file from memory.
DELETE_XML_FILE()
DEBUG_MESSAGE("TRI_Race_Load: Finished reading Race XML file: ", sRaceFileName)
// Race successfully loaded.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Save SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully saved.
FUNC BOOL TRI_Race_Save(TRI_RACE_STRUCT& Race, STRING sRaceFileName)
DEBUG_MESSAGE("TRI_Race_Save")
UNUSED_PARAMETER(Race)
sRaceFileName = sRaceFileName
// Local variables.
INT iCnt
INT iTempBuff
TEXT_LABEL_63 szFileName
// Assemble filename for Race XML file.
szFileName = TRI_Master.szTRIPath
szFileName += TRI_Master.szMainPath
szFileName += TRI_Master.szRacesPath
szFileName += sRaceFileName
szFileName += ".xml"
// Clear Race XML file and open it for saving.
DEBUG_MESSAGE("TRI_Race_Save: Opening filepath: ", TRI_Master.szXMLPath)
DEBUG_MESSAGE("TRI_Race_Save: Opening filename: ", szFileName)
CLEAR_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
OPEN_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Started writing Race XML file: ", sRaceFileName)
// Write Race XML file header.
SAVE_STRING_TO_NAMED_DEBUG_FILE("<!-- This file has been generated using Single Player Races widget -->", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("<!-- Feel free to edit this file by hand or by using the widget -->", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("<?xml version='1.0'?>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote Race XML file header")
// Write "Race" node (open).
SAVE_STRING_TO_NAMED_DEBUG_FILE("<Race>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Race' node (open)")
// Write "Gates" node (open).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Gates>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Gates' node (open)")
// Loop through race gates.
REPEAT Race.iGateCnt iCnt
// Write "Gate" node (open).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Gate>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
PRINTSTRING("TRI_Race_Save: Wrote 'Gate' node (open): ")
PRINTINT(iCnt)
PRINTNL()
// Write "Position" node (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Position ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("X = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].vPos.x, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("Y = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].vPos.y, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("Z = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].vPos.z, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" />", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Position' node (open/close)")
// Write "Checkpoint" node (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Checkpoint Radius = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].fRadius, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("Type = \"", TRI_Master.szXMLPath, szFileName)
iTempBuff = TRI_ChkpntType_GetIndex(Race.sGate[iCnt].eChkpntType)
SAVE_INT_TO_NAMED_DEBUG_FILE(iTempBuff, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" />", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Checkpoint' node (open/close)")
// Write "Gate" node (close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" </Gate>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
PRINTSTRING("TRI_Race_Save: Wrote 'Gate' node (close): ")
PRINTINT(iCnt)
PRINTNL()
ENDREPEAT
// Write "Gates" node (close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" </Gates>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Gates' node (close)")
// Write "Racers" node (open).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Racers>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Racers' node (open)")
// Loop through race racers.
REPEAT Race.iRacerCnt iCnt
// Write "Racer" node (open).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Racer Name = \"", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].szName, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" >", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
PRINTSTRING("TRI_Race_Save: Wrote 'Racer' node (open): ")
PRINTINT(iCnt)
PRINTNL()
// Write "Location" node (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Location ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("X = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].vStartPos.x, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("Y = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].vStartPos.y, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("Z = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].vStartPos.z, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" ", TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("H = \"", TRI_Master.szXMLPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].fStartHead, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" />", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Location' node (open/close)")
// Write "Driver" node (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Driver Type = \"", TRI_Master.szXMLPath, szFileName)
iTempBuff = TRI_DriverType_GetIndex(Race.Racer[iCnt].eDriverType)
SAVE_INT_TO_NAMED_DEBUG_FILE(iTempBuff, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" Model = \"", TRI_Master.szXMLPath, szFileName)
iTempBuff = TRI_DriverModel_GetIndex(Race.Racer[iCnt].eDriverModel)
SAVE_INT_TO_NAMED_DEBUG_FILE(iTempBuff, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" />", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Driver' node (open/close)")
// Write "Vehicle" node (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" <Vehicle Model = \"", TRI_Master.szXMLPath, szFileName)
iTempBuff = TRI_VehicleModel_GetIndex(Race.Racer[iCnt].eVehicleModel)
SAVE_INT_TO_NAMED_DEBUG_FILE(iTempBuff, TRI_Master.szXMLPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\" />", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Vehicle' node (open/close)")
// Write "Racer" node (close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" </Racer>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
PRINTSTRING("TRI_Race_Save: Wrote 'Racer' node (close): ")
PRINTINT(iCnt)
PRINTNL()
ENDREPEAT
// Write "Racers" node (close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" </Racers>", TRI_Master.szXMLPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Racers' node (close)")
// Write "Race" node (close).
SAVE_STRING_TO_NAMED_DEBUG_FILE("</Race>", TRI_Master.szXMLPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Save: Wrote 'Race' node (close)")
// Close Race XML file.
CLOSE_DEBUG_FILE()
DEBUG_MESSAGE("TRI_Race_Save: Finished writing Race XML file: ", sRaceFileName)
// Race successfully saved.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Export SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully exported.
FUNC BOOL TRI_Race_Export(TRI_RACE_STRUCT& Race, STRING sRaceFileName)
DEBUG_MESSAGE("TRI_Race_Export")
UNUSED_PARAMETER(Race)
sRaceFileName = sRaceFileName
// Local variables.
INT iCnt
TEXT_LABEL_31 szTempBuff
TEXT_LABEL_63 szFileName
// Assemble filename for Race SCH file.
// TODO: Add SPR Path when it is needed.
//szFileName = TRI_Master.szTRIPath
szFileName = TRI_Master.szMainPath
szFileName += TRI_Master.szRacesPath
szFileName += sRaceFileName
szFileName += ".sch"
// Clear Race SCH file and open it for saving.
DEBUG_MESSAGE("TRI_Race_Export: Opening filepath: ", TRI_Master.szSCHPath)
DEBUG_MESSAGE("TRI_Race_Export: Opening filename: ", szFileName)
CLEAR_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
OPEN_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Started writing Race SCH file: ", sRaceFileName)
// Write Race SCH file header.
SAVE_STRING_TO_NAMED_DEBUG_FILE("// This file has been generated from its matching xml using Single Player Races widget", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("// Do NOT edit this file by hand because your changes will likely get overwritten", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote Race SCH file header")
// Write "TRI_Setup_RaceName" function (open).
SAVE_STRING_TO_NAMED_DEBUG_FILE("PROC TRI_Setup_", TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(sRaceFileName, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("(TRI_RACE_STRUCT& Race)", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote 'TRI_Setup_RaceName' function (open)")
// Write "TRI_Race_Init" function call.
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Race_Init(Race)", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote 'TRI_Race_Init' function call")
// Write "Race.iGateCnt" assignment.
SAVE_STRING_TO_NAMED_DEBUG_FILE(" Race.iGateCnt = ", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(Race.iGateCnt, TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote 'Race.iGateCnt' assignment")
// Loop through race gates.
REPEAT Race.iGateCnt iCnt
// Write "TRI_Gate_Setup" function (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Gate_Setup(Race.sGate[", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(iCnt, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("], <<", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].vPos.x, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(",", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].vPos.y, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(",", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].vPos.z, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(">>, ", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.sGate[iCnt].fRadius, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(", ", TRI_Master.szSCHPath, szFileName)
szTempBuff = TRI_ChkpntType_GetString(Race.sGate[iCnt].eChkpntType)
SAVE_STRING_TO_NAMED_DEBUG_FILE(szTempBuff, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(")", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Debug info.
PRINTSTRING("TRI_Race_Export: Wrote 'TRI_Gate_Setup' function (open/close): ")
PRINTINT(iCnt)
PRINTNL()
ENDREPEAT
// Write a newline to space out gates and racers.
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Write "Race.iRacerCnt" assignment.
SAVE_STRING_TO_NAMED_DEBUG_FILE(" Race.iRacerCnt = ", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(Race.iRacerCnt, TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote 'Race.iRacerCnt' assignment")
// Loop through race racers.
REPEAT Race.iRacerCnt iCnt
// Write "TRI_Racer_Setup_Misc" function (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Racer_Setup_Misc(Race.Racer[", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(iCnt, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("])", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Write "TRI_Racer_Setup_Name" function (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Racer_Setup_Name(Race.Racer[", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(iCnt, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("], \"", TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].szName, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("\")", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Write "TRI_Racer_Setup_Entities" function (open/close).
// TODO: Forcing entity for player. May want to figure out a better way to do this...
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Racer_Setup_Entities(Race.Racer[", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(iCnt, TRI_Master.szSCHPath, szFileName)
IF (Race.Racer[iCnt].eDriverType <= PEDTYPE_PLAYER_UNUSED)
SAVE_STRING_TO_NAMED_DEBUG_FILE("], PLAYER_PED_ID(), ", TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("TRI_Master.PlayerVeh)", TRI_Master.szSCHPath, szFileName)
ELSE
SAVE_STRING_TO_NAMED_DEBUG_FILE("], NULL, NULL)", TRI_Master.szSCHPath, szFileName)
ENDIF
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Write "TRI_Racer_Setup_Start" function (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Racer_Setup_Start(Race.Racer[", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(iCnt, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("], <<", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].vStartPos.x, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(",", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].vStartPos.y, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(",", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].vStartPos.z, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(">>, ", TRI_Master.szSCHPath, szFileName)
SAVE_FLOAT_TO_NAMED_DEBUG_FILE(Race.Racer[iCnt].fStartHead, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(")", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Write "TRI_Racer_Setup_Types" function (open/close).
SAVE_STRING_TO_NAMED_DEBUG_FILE(" TRI_Racer_Setup_Types(Race.Racer[", TRI_Master.szSCHPath, szFileName)
SAVE_INT_TO_NAMED_DEBUG_FILE(iCnt, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE("], ", TRI_Master.szSCHPath, szFileName)
szTempBuff = TRI_DriverType_GetString(Race.Racer[iCnt].eDriverType)
SAVE_STRING_TO_NAMED_DEBUG_FILE(szTempBuff, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(", ", TRI_Master.szSCHPath, szFileName)
szTempBuff = TRI_DriverModel_GetString(Race.Racer[iCnt].eDriverModel)
SAVE_STRING_TO_NAMED_DEBUG_FILE(szTempBuff, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(", ", TRI_Master.szSCHPath, szFileName)
szTempBuff = TRI_VehicleModel_GetString(Race.Racer[iCnt].eVehicleModel)
SAVE_STRING_TO_NAMED_DEBUG_FILE(szTempBuff, TRI_Master.szSCHPath, szFileName)
SAVE_STRING_TO_NAMED_DEBUG_FILE(")", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
// Debug info.
PRINTSTRING("TRI_Race_Export: Wrote 'TRI_Racer_Setup' functions (open/close): ")
PRINTINT(iCnt)
PRINTNL()
ENDREPEAT
// Write "TRI_Setup_RaceName" function (close).
SAVE_STRING_TO_NAMED_DEBUG_FILE("ENDPROC", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote 'TRI_Setup_RaceName' function (close)")
// Write Race SCH file footer.
SAVE_STRING_TO_NAMED_DEBUG_FILE("// END OF FILE! DO NOT ADD ANYTHING BELOW THIS LINE!", TRI_Master.szSCHPath, szFileName)
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szSCHPath, szFileName)
DEBUG_MESSAGE("TRI_Race_Export: Wrote Race SCH file footer")
// Close Race SCH file.
CLOSE_DEBUG_FILE()
DEBUG_MESSAGE("TRI_Race_Export: Finished writing Race SCH file: ", sRaceFileName)
// Race successfully exported.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Create SPR Race.
/// RETURNS:
/// TRUE if SPR Race was successfully created.
FUNC BOOL TRI_Race_Create(TRI_RACE_STRUCT& Race, STRING sRaceFileName)
//DEBUG_MESSAGE("TRI_Race_Create")
TRI_Race_Init(Race)
IF TRI_Race_Save(Race, sRaceFileName)
RETURN TRI_Race_Export(Race, sRaceFileName)
ENDIF
RETURN FALSE
ENDFUNC
#ENDIF
FUNC BOOL HAS_TRI_SCALEFORM_LOADED(TRI_RACE_STRUCT& thisRace)
IF NOT HAS_SCALEFORM_MOVIE_LOADED(thisRace.uiLeaderboard)
CPRINTLN(DEBUG_TRIATHLON, "HAS_TRI_SCALEFORM_LOADED :: Waiting on thisRace.uiLeaderboard")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
// -----------------------------------
// MAIN PROCS/FUNCTIONS
// -----------------------------------
/// PURPOSE:
/// Setup SPR Race.
/// RETURNS:
/// TRUE if still setting up SPR Race.
FUNC BOOL TRI_Race_Setup(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Setup")
// Setup SPR Race State Machine.
SWITCH (Race.eSetup)
// Setup (init).
CASE TRI_RACE_SETUP_INIT
DEBUG_MESSAGE("TRI_RACE_SETUP - INIT")
// Disable cellphone.
DISABLE_CELLPHONE(TRUE)
REQUEST_STREAMED_TEXTURE_DICT("MPHUD")
Race.bigMessageUI.siMovie = REQUEST_MG_BIG_MESSAGE()
// Request the appropriate race textures.
SWITCH (TRI_Master.eRaceType)
CASE TRI_RACE_TYPE_PLANE
REQUEST_STREAMED_TEXTURE_DICT("SPRRaces")
BREAK
CASE TRI_RACE_TYPE_OFFROAD
REQUEST_STREAMED_TEXTURE_DICT("SPROffroad")
BREAK
CASE TRI_RACE_TYPE_TRIATHLON
REQUEST_STREAMED_TEXTURE_DICT("Triathlon")
BREAK
ENDSWITCH
DEBUG_MESSAGE("TRI_RACE_SETUP - LOAD_INIT")
Race.eSetup = TRI_RACE_SETUP_LOAD_INIT
BREAK
// Setup Load (init).
CASE TRI_RACE_SETUP_LOAD_INIT
TRI_Race_Racer_Request_All(Race)
// Request Countdown UI scaleform movie.
REQUEST_MINIGAME_COUNTDOWN_UI(TRI_CountDownUI)
// TRI_COUNTDOWN_UI = REQUEST_SCALEFORM_MOVIE("COUNTDOWN")
DEBUG_MESSAGE("TRI_RACE_SETUP - LOAD_WAIT")
Race.eSetup = TRI_RACE_SETUP_LOAD_WAIT
BREAK
// Setup Load (wait).
CASE TRI_RACE_SETUP_LOAD_WAIT
IF TRI_Race_Racer_Stream_All(Race)
/*
IF HAS_STREAMED_TEXTURE_DICT_LOADED("MPHUD")
AND HAS_STREAMED_TEXTURE_DICT_LOADED("SPROffroad")
AND HAS_STREAMED_TEXTURE_DICT_LOADED("SPRRaces")
IF HAS_SCALEFORM_MOVIE_LOADED(TRI_COUNTDOWN_UI)
DEBUG_MESSAGE("TRI_RACE_SETUP - CREATE_INIT")
Race.eSetup = TRI_RACE_SETUP_CREATE_INIT
ENDIF
ENDIF
*/
IF HAS_STREAMED_TEXTURE_DICT_LOADED("MPHUD")
// IF HAS_TRI_SCALEFORM_LOADED(Race)
IF HAS_MINIGAME_COUNTDOWN_UI_LOADED(TRI_CountDownUI)
// Check the appropriate race textures have loaded.
SWITCH (TRI_Master.eRaceType)
CASE TRI_RACE_TYPE_PLANE
IF HAS_STREAMED_TEXTURE_DICT_LOADED("SPRRaces")
DEBUG_MESSAGE("TRI_RACE_SETUP - CREATE_INIT")
Race.eSetup = TRI_RACE_SETUP_CREATE_INIT
ENDIF
BREAK
CASE TRI_RACE_TYPE_OFFROAD
IF HAS_STREAMED_TEXTURE_DICT_LOADED("SPROffroad")
DEBUG_MESSAGE("TRI_RACE_SETUP - CREATE_INIT")
Race.eSetup = TRI_RACE_SETUP_CREATE_INIT
ENDIF
BREAK
CASE TRI_RACE_TYPE_TRIATHLON
IF HAS_STREAMED_TEXTURE_DICT_LOADED("Triathlon")
DEBUG_MESSAGE("TRI_RACE_SETUP - CREATE_INIT")
Race.eSetup = TRI_RACE_SETUP_CREATE_INIT
ENDIF
BREAK
ENDSWITCH
ENDIF
// ENDIF
ENDIF
ENDIF
BREAK
// Setup Create (init).
CASE TRI_RACE_SETUP_CREATE_INIT
//clear this so we dont set off fail checks immediately
CLEAR_PLAYER_HAS_DAMAGED_AT_LEAST_ONE_PED(PLAYER_ID())
TRI_Race_Racer_Create_All(Race)
TRI_Race_Racer_Blip_Create_All(Race)
DEBUG_MESSAGE("TRI_RACE_SETUP - CREATE_WAIT")
Race.eSetup = TRI_RACE_SETUP_CREATE_WAIT
BREAK
// Setup Create (wait).
CASE TRI_RACE_SETUP_CREATE_WAIT
RETURN FALSE
BREAK
// Setup (wait).
CASE TRI_RACE_SETUP_WAIT
RETURN FALSE
BREAK
// Setup (cleanup).
CASE TRI_RACE_SETUP_CLEANUP
RETURN FALSE
BREAK
ENDSWITCH
// Setup SPR Race still running.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// If a vehicle was stored for the player during the race, return vehicle to the player.
PROC PLACE_PRE_TRIATHLON_PLAYER_VEHICLE_AT_END_OF_RACE()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PLACE_PRE_TRIATHLON_PLAYER_VEHICLE_AT_END_OF_RACE] Procedure started.")
IF IS_VEHICLE_GEN_AVAILABLE( VEHGEN_MISSION_VEH )
UPDATE_DYNAMIC_VEHICLE_GEN_POSITION(VEHGEN_MISSION_VEH, vDestinationPosOfStoredPlayerVehicle, fDestinationHeadingOfStoredPlayerVehicle)
CPRINTLN(DEBUG_TRIATHLON,"PLACE_PRE_TRIATHLON_PLAYER_VEHICLE_AT_END_OF_RACE - Vehicle placed back, IS_VEHICLE_GEN_AVAILABLE passed")
ENDIF
ENDPROC
/// PURPOSE:
/// Update SPR Race.
/// RETURNS:
/// TRUE if still updating SPR Race.
FUNC BOOL TRI_Race_Update(TRI_RACE_STRUCT& Race)
//DEBUG_MESSAGE("TRI_Race_Update")
// Update SPR Race State Machine.
SWITCH (Race.eUpdate)
// Update (init).
CASE TRI_RACE_UPDATE_INIT
DEBUG_MESSAGE("TRI_RACE_UPDATE - INIT")
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_PLAYED_STINGER)
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_ENDSCREEN_READY)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
stop_vehicle_recordings(Race)
// Setup countdown display.
CANCEL_TIMER(Race.Display.tCnt)
eCountdownStage = TRI_COUNTDOWN_STAGE_INIT
IF NOT HAS_MINIGAME_COUNTDOWN_UI_LOADED(TRI_CountDownUI)
REQUEST_MINIGAME_COUNTDOWN_UI(TRI_CountDownUI)
ENDIF
DEBUG_MESSAGE("TRI_RACE_UPDATE - COUNTDOWN")
Race.eUpdate = TRI_RACE_UPDATE_COUNTDOWN
BREAK
// Update Countdown.
CASE TRI_RACE_UPDATE_COUNTDOWN
IF NOT IS_SCREEN_FADED_OUT()
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
// Display countdown until done, then start race.
IF HAS_MINIGAME_COUNTDOWN_UI_LOADED(TRI_CountDownUI) AND NOT TRI_Countdown_Display(Race.Display)
IF TRI_Master.eRaceType = TRI_RACE_TYPE_TRIATHLON
TRIGGER_MUSIC_EVENT("MGTR_MUSIC_START")
START_AUDIO_SCENE("TRI_SWIM_SCENE")
STOP_AUDIO_SCENE("TRI_START_SCENE")
ENDIF
Race.iCountdownStamp = GET_GAME_TIMER() + 2000
// clear one shot first checkpoints drawn bits
IF IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, TRI_FIRST_GATE_ACTIVATION)
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_FIRST_GATE_ACTIVATION)
ENDIF
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
ENDIF
// Start race racers.
DISPLAY_HUD(TRUE)
TRI_Race_Racer_Start(Race)
DEBUG_MESSAGE("TRI_RACE_UPDATE - WAIT")
ODDJOB_EXIT_CUTSCENE()
Race.eUpdate = TRI_RACE_UPDATE_WAIT
// ELSE
// HANDLE_TRI_COUNTDOWN_ANIMS(Race)
ENDIF
ENDIF
BREAK
// Update Finish.
CASE TRI_RACE_UPDATE_FINISH
// Immediately show the celebrating/tired triatheles.
SET_TRI_RACERS_ONCE_RACE_ENDS(Race)
ODDJOB_ENTER_CUTSCENE()
DISPLAY_HUD(FALSE)
// show player controls after 1 second
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, TRI_SCORECARD_INIT)
CLEAR_HELP()
SETTIMERA(0)
Race.uiLeaderboard = REQUEST_SC_LEADERBOARD_UI()
TRI_Race_Leaderboard_Init_Scorecard(Race)
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "TRI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
// ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_UI_RESTART", FRONTEND_CONTROL, INPUT_FRONTEND_X)
SET_SIMPLE_USE_CONTEXT_FULLSCREEN(TRI_Master.uiInput, TRUE)
SET_SIMPLE_USE_CONTEXT_MINIGAME_ATTACHED(TRI_Master.uiInput)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_SCORECARD_INIT)
ENDIF
// If it's Triathlon, show player for a brief moment before showing the leaderboard.
IF NOT Tri_Showing_Player_Finished_Race(sOutroSceneData.iOutroSceneID)
PLAY_TRI_CAM_SNAP_UPWARD_AFTER_OUTRO()
PLACE_PRE_TRIATHLON_PLAYER_VEHICLE_AT_END_OF_RACE()
SET_TRI_CONTROL_FLAG(TCF_FINISHED_RACE)
MISSION_FLOW_PLAY_END_OF_MISSION_MUSIC(TRUE)
// Show off-screen camera for Triathlon to clean up without fading out.
DEBUG_MESSAGE("TRI_RACE_UPDATE - LEADERBOARD")
SETTIMERA(0)
TRI_KILL_HINT_CAM()
TRI_SET_HINT_CAM_ACTIVE(FALSE)
SPECIAL_ABILITY_DEACTIVATE(PLAYER_ID())
ENABLE_SPECIAL_ABILITY(PLAYER_ID(), FALSE)
SET_RESULT_SCREEN_DISPLAYING_STATE(TRUE)
IF IS_PLAYER_ONLINE()
TRI_LOAD_SOCIAL_CLUB_LEADERBOARD(INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur))
bIsJustOnline = TRUE
ENDIF
Race.eUpdate = TRI_RACE_UPDATE_LEADERBOARD
CPRINTLN(DEBUG_MINIGAME, "TRI_RACE_UPDATE_FINISH - Adding complex use context (clickable)")
TRI_Draw_Scorecard(Race, 0)
INIT_SIMPLE_USE_CONTEXT(TRI_Master.uiInput, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "TRI_CONT", FRONTEND_CONTROL, INPUT_FRONTEND_ENDSCREEN_ACCEPT)
IF NOT IS_PLAYER_ONLINE()
ADD_SIMPLE_USE_CONTEXT_INPUT(TRI_Master.uiInput, "SPR_SCLB", FRONTEND_CONTROL, INPUT_FRONTEND_LEADERBOARD)
bIsLBDContextSet = TRUE
ENDIF
SET_SIMPLE_USE_CONTEXT_FULLSCREEN(TRI_Master.uiInput, TRUE)
ENDIF
BREAK
// Update Leaderboard.
CASE TRI_RACE_UPDATE_LEADERBOARD
// Prevent player from aiming in melee mode.
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Driver)
IF GET_PEDS_CURRENT_WEAPON(Race.Racer[0].Driver) = WEAPONTYPE_UNARMED
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON)
ENDIF
ENDIF
#IF COMPILE_WIDGET_OUTPUT
EXPORT_SCREEN_MEGA_PLACEMENT(Race.uiScorecard)
#ENDIF
IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL)
SET_MOUSE_CURSOR_THIS_FRAME()
ENDIF
TRI_RETURN_VALUES_ENUM eRetVal
eRetVal = TRI_Race_Draw_Scorecard(Race, INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur))
// Wait for player to exit leaderboard.
IF eRetVal = TRV_TRUE
//Get the end screen animating out
ENDSCREEN_START_TRANSITION_OUT(thisEsd)
// If we haven't written to the leaderboard, but the player already Continued, do so now.
IF NOT sclb_rank_predict.bFinishedWrite
IF NOT bCheated
WRITE_TRI_TRI_TIME_TO_LEADERBOARD(INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur), Race.Racer[0].fClockTime, CLAMP_INT((4 - Race.Racer[0].iRank), 0, 3))
ENDIF
ENDIF
CANCEL_TIMER(tReadLeaderboardTimer)
CLEAR_RANK_REDICTION_DETAILS()
TRI_CLEANUP_SOCIAL_CLUB_LEADERBOARD()
SET_RESULT_SCREEN_DISPLAYING_STATE(FALSE)
CLEAR_HELP()
IF IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, TRI_SCORECARD_INIT)
CLEAR_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_SCORECARD_INIT)
ENDIF
DEBUG_MESSAGE("TRI_RACE_UPDATE - CLEANUP")
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
// Based on the race, clear the ending area.
IF (eCurrentTriRace = TRIATHLON_RACE_VESPUCCI)
IF IS_IPL_ACTIVE("VB_08_TriAf01")
REMOVE_IPL("VB_08_TriAf01")
ENDIF
ELIF (eCurrentTriRace = TRIATHLON_RACE_ALAMO_SEA)
IF IS_IPL_ACTIVE("CS4_08_TriAf02")
REMOVE_IPL("CS4_08_TriAf02")
ENDIF
ELIF (eCurrentTriRace = TRIATHLON_RACE_IRONMAN)
IF IS_IPL_ACTIVE("CH1_07_TriAf03")
REMOVE_IPL("CH1_07_TriAf03")
ENDIF
ENDIF
IF DOES_ENTITY_EXIST(objRaceBanners[1])
DELETE_OBJECT(objRaceBanners[1])
ENDIF
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
TRI_PLAY_CAM_SNAP_DOWN_FROM_BOARD(eCurrentTriRace)
//Wait until the pass screen animates-out
Race.eUpdate = TRI_RACE_UPDATE_WAIT_ANIM_OUT
ELIF eRetVal = TRV_RESET
// If we haven't written to the leaderboard, but the player already Retried, do so now.
IF NOT sclb_rank_predict.bFinishedWrite
IF NOT bCheated
WRITE_TRI_TRI_TIME_TO_LEADERBOARD(INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur), Race.Racer[0].fClockTime, CLAMP_INT((4 - Race.Racer[0].iRank), 0, 3))
ENDIF
ENDIF
CANCEL_TIMER(tReadLeaderboardTimer)
CLEAR_RANK_REDICTION_DETAILS()
TRI_CLEANUP_SOCIAL_CLUB_LEADERBOARD()
bRankPredictReady = FALSE
bIsLBDContextSet = FALSE
PLAY_SOUND_FRONTEND(-1, "Phone_Generic_Key_02", "HUD_MINIGAME_SOUNDSET")
// Let the game know we're restarting
SET_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
CLEAR_TRI_CONTROL_FLAG(TCF_FAIL_CHECKING)
Race.Racer[0].eReset = TRI_RACER_RESET_FADE_OUT // Set the player to reset fade out
KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
RESET_TRI_NEWS_EVENTS()
Race.eUpdate = TRI_RACE_UPDATE_WAIT // Bring the player back to an updating game state
Race.Racer[0].iGateCur = 0 // Reset our gate position so the reset stuff runs too
ENDIF
BREAK
//Wait for the end screen to animate out
CASE TRI_RACE_UPDATE_WAIT_ANIM_OUT
IF DISPLAY_TRI_END_SCREEN()
Race.eUpdate = TRI_RACE_UPDATE_FADE_OUT_BEFORE_FINISH
ENDIF
BREAK
// Fade out right before cleaning and killing the script.
CASE TRI_RACE_UPDATE_FADE_OUT_BEFORE_FINISH
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
// Prevent player from aiming in melee mode.
IF (TRI_Master.eRaceType = TRI_RACE_TYPE_TRIATHLON)
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Driver)
IF GET_PEDS_CURRENT_WEAPON(Race.Racer[0].Driver) = WEAPONTYPE_UNARMED
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON)
ENDIF
ENDIF
ENDIF
IF NOT IS_THREAD_ACTIVE(trackerThreadID) // checkin to see if stat tracker is still up for Tris
//IF TRI_FadeOut_Safe(750)
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID())
ENDIF
ENDIF
// Clear any minigames text.
CLEAR_ADDITIONAL_TEXT(MINIGAME_TEXT_SLOT, TRUE)
// Restore the player's previous outfit.
CPRINTLN(DEBUG_TRIATHLON, "CASE TRI_RACE_UPDATE_FADE_OUT_BEFORE_FINISH restoring outfit")
IF NOT Tri_Master.bVariationRestored
CPRINTLN(DEBUG_TRIATHLON, "PROC CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT restoring outfit # 3")
RESTORE_PLAYER_PED_VARIATIONS(PLAYER_PED_ID())
SET_PED_VARIATIONS( PLAYER_PED_ID(), Tri_Master.sPlayerVariation )
Tri_Master.bVariationRestored = TRUE
ENDIF
IF (Race.Racer[0].iRank <= 3)
CPRINTLN(DEBUG_TRIATHLON, "******** Triathlon Win logged in TRI_RACE.sch ********")
CPRINTLN(DEBUG_TRIATHLON, "Awarding completion percentage for ", GET_STRING_FROM_TRI_RACE_INDEX(eCurrentTriRace))
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_VESPUCCI REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL(CP_MG_TRI1) BREAK
CASE TRIATHLON_RACE_ALAMO_SEA REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL(CP_MG_TRI2) BREAK
CASE TRIATHLON_RACE_IRONMAN REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL(CP_MG_TRI3) BREAK
ENDSWITCH
SET_BITMASK_AS_ENUM(g_savedGlobals.sTriathlonData.iBitFlags, TRIATHLON_WonRace)
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "Unlocking next race")
SET_BITMASK(sLauncherData.iLauncherFlags,BIT18)
CPRINTLN(DEBUG_TRIATHLON, "MAKE_AUTOSAVE_REQUEST()")
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
RESTART_TIMER_NOW(taxiTime)
Race.eUpdate = TRI_RACE_UPDATE_FADE_IN_BEFORE_FINISH
//ENDIF
ENDIF
BREAK
// Fade in after cleaning and killing the script.
CASE TRI_RACE_UPDATE_FADE_IN_BEFORE_FINISH
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
// taxiTimer is not used in Tri, so instead of creating a new timer, just use taxiTimer instead.
IF TIMER_DO_WHEN_READY(taxiTime, 1.0)
VECTOR vOutroPos
FLOAT fOutroHeading
// Warp player nearby, to a safe location, once the race is completed.
IF (TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_ALAMO_SEA))
vOutroPos = <<1742.2, 3910.3, 33.85>>
fOutroHeading = 10.25
ELIF (TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_VESPUCCI))
vOutroPos = <<-1339.9078, -1015.8990, 6.9290>>
fOutroHeading = 28.6984
ELIF (TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_IRONMAN))
vOutroPos = <<-2280.5549, 411.8955, 173.6018>>
fOutroHeading = 353.5356
ENDIF
IF NOT IS_ENTITY_DEAD(Race.Racer[0].Driver)
SET_ENTITY_COORDS(Race.Racer[0].Driver, vOutroPos)
SET_ENTITY_HEADING(Race.Racer[0].Driver, fOutroHeading)
ENDIF
IF IS_TRI_CONTROL_FLAG_SET(TCF_FINISHED_RACE)
IF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_ALAMO_SEA)
SET_SCENARIO_GROUP_ENABLED("Triathlon_1", FALSE)
ELIF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_VESPUCCI)
SET_SCENARIO_GROUP_ENABLED("Triathlon_2", FALSE)
ELIF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_IRONMAN)
SET_SCENARIO_GROUP_ENABLED("Triathlon_3", FALSE)
ENDIF
CLEAR_AREA_OF_PEDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), 25.0)
CDEBUG2LN(DEBUG_TRIATHLON, "Preemptive cleanup calls to scenarios and peds")
ENDIF
PLAY_TRI_OUTRO_SYNC_SCENE_WATER_BOTTLE(sOutroSceneData, Race, vOutroPos, fOutroHeading)
RESTART_TIMER_NOW(Race.tUpdate)
// Cleanup race.
TRI_Race_Init(Race)
CLEAR_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
ODDJOB_EXIT_CUTSCENE()
Race.eUpdate = TRI_RACE_UPDATE_CLEANUP
ENDIF
BREAK
// Update (wait).
CASE TRI_RACE_UPDATE_WAIT
// need to draw it for a bit longer after the GO! first appears
IF GET_GAME_TIMER() > Race.iCountdownStamp
SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(TRI_CountDownUI.uiCountdown)
ELSE
IF GET_GAME_TIMER() > Race.iCountdownStamp - 1900
IF NOT bCatchupActive
ADD_TRI_NEWS_EVENT(TRNE_RACE_STARTED)
STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()
bCatchupActive = TRUE
bCatchupDone = TRUE
ENDIF
ENDIF
DRAW_SCALEFORM_MOVIE(TRI_CountDownUI.uiCountdown, 0.5, 0.5, 1.0, 1.0, 255, 255, 255, 100)
ENDIF
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, TRI_FIRST_GATE_ACTIVATION)
// Activate first/second race gates.
TRI_Race_Gate_Activate(Race, 0, TRUE)
TRI_Race_Gate_Activate(Race, 1, FALSE)
SET_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_FIRST_GATE_ACTIVATION)
TRI_SET_HINT_CAM_ACTIVE(TRUE)
// Set the first blip to show the swim blip sprite.
SET_BLIP_COLOUR(Race.sGate[0].Blip, BLIP_COLOUR_YELLOW)
ENDIF
// Update race racers and auto-restart race.
IF NOT TRI_Race_Racer_Update(Race)
// Finish race racers.
TRI_Race_Racer_Finish(Race)
// Setup finish display.
CANCEL_TIMER(Race.Display.tCnt)
DEBUG_MESSAGE("TRI_RACE_UPDATE - FINISH")
Race.eUpdate = TRI_RACE_UPDATE_FINISH
WHILE NOT HAVE_TRI_OUTRO_ASSETS_LOADED(sOutroSceneData)
WAIT(0)
ENDWHILE
RESTART_TIMER_NOW(Race.tUpdate)
PLAY_TRI_OUTRO_SYNC_SCENE_WINLOSS(sOutroSceneData, Race, eCurrentTriRace, Race.Racer[0].iRank <= 3)
ENDIF
UPDATE_TRI_NEWS_DIALOGUE(Race)
BREAK
// Update (cleanup).
CASE TRI_RACE_UPDATE_CLEANUP
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
// Handle the proper release of the water bottle.
IF DOES_ENTITY_EXIST(sOutroSceneData.oBottle)
AND IS_TIMER_STARTED(Race.tUpdate)
FLOAT fTime
fTime = GET_TIMER_IN_SECONDS(Race.tUpdate)
enumCharacterList ePed
ePed = GET_CURRENT_PLAYER_PED_ENUM()
BOOL bRelease
IF (ePed = CHAR_MICHAEL)
bRelease = (fTime > 3.6)
ELIF (ePed = CHAR_FRANKLIN)
bRelease = (fTime > 4.05)
ELIF (ePed = CHAR_TREVOR)
bRelease = (fTime > 3.51)
ENDIF
IF bRelease
IF DOES_ENTITY_EXIST(sOutroSceneData.oBottle)
STOP_SYNCHRONIZED_ENTITY_ANIM(sOutroSceneData.oBottle, INSTANT_BLEND_OUT, TRUE)
ACTIVATE_PHYSICS(sOutroSceneData.oBottle)
SET_OBJECT_AS_NO_LONGER_NEEDED(sOutroSceneData.oBottle)
ENDIF
CANCEL_TIMER(Race.tUpdate)
ENDIF
VECTOR vScenePos
//re-enable any previous disabled navmesh
IF eCurrentTriRace = TRIATHLON_RACE_VESPUCCI
vScenePos = <<-1332.92249, -1043.14160, 6.65>>
ELIF eCurrentTriRace = TRIATHLON_RACE_ALAMO_SEA
vScenePos = <<1759.43518, 3894.69409, 33.789>>
ELSE
vScenePos = <<-2304.44312, 462.66916, 173.4493>>
ENDIF
DISABLE_NAVMESH_IN_AREA(<< vScenePos.x - 3.0, vScenePos.y - 3.0, vScenePos.z - 3.0 >>, << vScenePos.x + 3.0, vScenePos.y + 3.0, vScenePos.z + 3.0 >>, FALSE)
RETURN TRUE
ENDIF
SET_PLAYER_INVINCIBLE(PLAYER_ID(), FALSE)
IF NOT IS_MESSAGE_BEING_DISPLAYED()
AND NOT IS_HELP_MESSAGE_BEING_DISPLAYED()
RETURN FALSE
ELSE
IF NOT IS_TIMER_STARTED(tShutdownTimer)
START_TIMER_NOW_SAFE(tShutdownTimer)
ELIF (GET_TIMER_IN_SECONDS(tShutdownTimer) > 5)
RETURN FALSE
ENDIF
ENDIF
BREAK
ENDSWITCH
// Update SPR Race still running.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Cleanup SPR Race.
PROC TRI_Race_Cleanup(TRI_RACE_STRUCT& Race, BOOL bDefault)
//DEBUG_MESSAGE("TRI_Race_Cleanup")
IF bDefault
DEBUG_MESSAGE("TRI_RACE_CLEANUP: Default bool hit, doing race init")
// Init race data.
TRI_Race_Init(Race)
ELSE
DEBUG_MESSAGE("TRI_RACE_CLEANUP: False bool hit, releasing offroad AI")
// Release AI
RELEASE_AI_RACERS(Race)
ENDIF
// Enable cellphone.
DISABLE_CELLPHONE(FALSE)
CLEANUP_SIMPLE_USE_CONTEXT( TRI_Master.uiInput )
// Reseting this here, in case MG_UPDATE_FAIL_SPLASH_SCREEN failed to cleanup. (Very important this gets reset)
SET_NO_LOADING_SCREEN(FALSE)
CLEAR_HELP()
CLEAR_PRINTS()
ENDPROC
// END OF FILE! DO NOT ADD ANYTHING BELOW THIS LINE!