// ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // 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("", TRI_Master.szXMLPath, szFileName) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(TRI_Master.szXMLPath, szFileName) SAVE_STRING_TO_NAMED_DEBUG_FILE("", TRI_Master.szXMLPath, szFileName) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(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 Race XML file header") // Write "Race" node (open). 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 'Race' node (open)") // Write "Gates" node (open). 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 'Gates' node (open)") // Loop through race gates. REPEAT Race.iGateCnt iCnt // Write "Gate" node (open). 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 'Gate' node (open): ") PRINTINT(iCnt) PRINTNL() // Write "Position" node (open/close). 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(" ", 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(" ", 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(" ", 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(" ", 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(" ", 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(" ", 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(" ", 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(" ", 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(" ", 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(" ", 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("", 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!