3601 lines
125 KiB
Scheme
Executable File
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!
|