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

4850 lines
188 KiB
Python
Executable File

// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// SCRIPT NAME : TriathlonSP.sc
// AUTHOR : Chris Bourassa (CB), Carlos Mijares (CM)
// DESCRIPTION : Main Triathlon script.
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//Compile out Title Update changes to header functions.
//Must be before includes.
//CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R.
BOOL bCheated = FALSE
#IF IS_DEBUG_BUILD
BOOL DESTROY_NEWS_CHOPPER = FALSE
#ENDIF
CONST_INT TRI_RACE_IS_TRIATHLON 1
CONST_INT TRI_GATE_MAX 122 // Max race gates for Tri.
CONST_INT TRI_MAX_BLOCKING_AREAS 6
CONST_FLOAT TRI_VENICE_SCENARIO_MULT 10.0
CONST_FLOAT ANIM_WAIT_THRESHOLD 2.0
CONST_INT LOWEST_BIG_CHEER_GATE 5
CONST_FLOAT STAMINA_RESTORE_PERCENTAGE 0.33
CONST_FLOAT MAX_STAMINA_BOOST 2.0
CONST_FLOAT NORMAL_RACE_ENERGY 30000.0
CONST_FLOAT IRONMAN_RACE_ENERGY 200000.0
CONST_INT TRI_NEWS_SCAN_LINES 55
CONST_FLOAT KITS_BAG_HEIGHT 0.213
// Cheering Tweaks
CONST_FLOAT TRI_TIME_TO_CHEERING 0.5
CONST_FLOAT TRI_CHEERING_PROB 0.7
CONST_FLOAT TRI_CHEERING_RANGE 30.0
// Cutscene anim playback constants
CONST_FLOAT TRI_ANIM_PLAYBACK_LOW_PROB 0.4
CONST_FLOAT TRI_ANIM_PLAYBACK_LOW_LOW 0.8
CONST_FLOAT TRI_ANIM_PLAYBACK_LOW_HI 0.95
CONST_FLOAT TRI_ANIM_PLAYBACK_HI_LOW 1.1
CONST_FLOAT TRI_ANIM_PLAYBACK_HI_HI 1.3
//// Wheezing thresholds
//CONST_FLOAT TRI_WHEEZE_EASY 0.66
//CONST_FLOAT TRI_WHEEZE_MED 0.33
//CONST_FLOAT TRI_WHEEZE_HARD 0.10
//CONST_FLOAT TRI_WHEEZE_ODDS_EASY 0.03
//CONST_FLOAT TRI_WHEEZE_ODDS_MED 0.08
//CONST_FLOAT TRI_WHEEZE_ODDS_HARD 0.12
//CONST_FLOAT TRI_WHEEZE_COUNTDOWN 10.00
// Chance to say Danny Glover lines.
CONST_FLOAT MICHAEL_LINES_GETTING_OLD_CHANCE 0.30
// Menu offsets
CONST_FLOAT MENU_OFFSET_1 -1.0
CONST_FLOAT MENU_OFFSET_2 -1.0
CONST_FLOAT MENU_OFFSET_3 0.248
CONST_INT NEWS_CAM_INTERRUPT_DURATION 2700
TWEAK_FLOAT TRI_AI_FINISH_HEADING_ADJUST 5.0
CONST_FLOAT TRI_LOD_SETTING 2.0
TEXT_LABEL_23 texCheckPatch = "MPMissMarkers256"
#IF IS_DEBUG_BUILD
BOOL IS_CHEATING_ENABLED = FALSE
VECTOR TEST_VECTOR_1
VECTOR TEST_VECTOR_2
TWEAK_FLOAT TEST_HEADING 0.0
#ENDIF
// =====================================
// FILE INCLUDES
// =====================================
USING "globals.sch"
// -----------------------------------
// SPR FILE INCLUDES
// -----------------------------------
USING "tri_head.sch"
USING "tri_helpers_triathlon.sch"
USING "tri_ai.sch"
USING "tri_dialogue.sch"
USING "tri_roads.sch"
USING "tri_helpers.sch"
USING "tri_camera.sch"
USING "tri_gate.sch"
USING "tri_racer.sch"
USING "tri_race_scorecard_lib.sch"
USING "minigames_helpers.sch"
USING "cheat_controller_public.sch"
// SPR Main Data.
TRI_MAIN_STRUCT TRI_Main
USING "tri_race.sch"
USING "tri_cutscenes.sch"
USING "tri_widget.sch"
USING "tri_xml_lib.sch"
// -----------------------------------
// RACE FILE INCLUDES
// -----------------------------------
USING "Races\Triathlon_traditional_01.sch"
USING "Races\Triathlon_traditional_02.sch"
USING "Races\Triathlon_traditional_03.sch"
// -----------------------------------
// GENERAL FILE INCLUDES
// -----------------------------------
USING "z_volumes.sch"
// =====================================
// E N D FILE INCLUDES
// =====================================
// ===================================
// TRIATHLON VARIABLES
// ===================================
// SPR Race Data.
TRI_RACE_STRUCT TRI_Race
// Race position, which naturally varies between race.
VECTOR vScriptStartPos
// Tracks intended player heading at start of race.
FLOAT fPlayerHeading
VECTOR vRaceLauncherPos
// Start fade-in timer, so racers don't pop before cutscene intro.
structTimer timerBeforeIntroCutscene
// After player restarts race, amount to wait before fading back into the game.
INT iFadeInMilsecToRaceStart
// news heli and its pilot
VEHICLE_INDEX vehChopper
PED_INDEX pedPilot
// -----------------------------------------
// DEBUG VARIABLES
// -----------------------------------------
#IF IS_DEBUG_BUILD
// Race editor widget.
TRI_WIDGET_MAIN TRI_Widget
// Debug timers.
structTimer timerDebug_A
// Number of selections in Z-debug menu.
CONST_INT MAX_STAGE_MENU_LENGTH 6
// Track the current Z-debug menu selection.
INT iReturnCurrentMenuStageSelection
// Struct containing the Z-debug menu (Tap 'Z' on debug keyboard at start of race to access)
MissionStageMenuTextStruct skipMenuStruct[MAX_STAGE_MENU_LENGTH]
ENUM DEBUG_TRI_RACE_STATE
DEBUG_TRI_RACE_STATE_FIRST_GATE,
DEBUG_TRI_RACE_STATE_LAST_SWIM_GATE,
DEBUG_TRI_RACE_STATE_LAST_BIKE_GATE,
DEBUG_TRI_RACE_STATE_LAST_RUN_GATE,
DEBUG_TRI_RACE_STATE_END,
DEBUG_TRI_RACE_STATE_NONE
ENDENUM
BOOL S_SKIP_ACTIVATED
#ENDIF
// Track the state of the bikes, primarily the player's.
ENUM TRI_BIKES_STATE
TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_FINISH_SWIM_LEG,
TRI_BIKES_STATE_CREATE_BIKES_RADAR_BLIP,
TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_GET_ON_BIKE,
TRI_BIKES_STATE_PLAYER_GOT_ON_BIKE_FOR_FIRST_TIME,
TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE,
TRI_BIKES_STATE_PLAYER_GOT_OFF_BIKE_IN_BIKE_LEG,
TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_RETURN_TO_BIKE,
TRI_BIKES_STATE_PLAYER_IS_BACK_ON_BIKE,
TRI_BIKES_STATE_PLAYER_FINISHED_BIKE_LEG,
TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_BE_FORCED_TO_LEAVE_BIKE,
TRI_BIKES_STATE_DONE
ENDENUM
TRI_BIKES_STATE eCurrentTriBikesState
// ===================================
// E N D TRIATHLON VARIABLES
// ===================================
// ===============================================
// PLAYER PROCEDURES AND FUNCTIONS
// ===============================================
/// PURPOSE:
/// Ensure the player is in a ready state before he's used in Triathlon.
PROC READY_PLAYER_CHARACTER_FOR_TRIATHLON()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->READY_PLAYER_CHARACTER_FOR_TRIATHLON] Procedure started.")
// Ensure the player is standing idle before fade-in occurs, in case the player is in stealth mode when Triathlon loads.
//FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_IDLE, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->READY_PLAYER_CHARACTER_FOR_TRIATHLON] Setting ped to an idle position.")
// Prevent player from using his melee moves during the race, as the melee button is shared with the TV cam button.
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_DisableMelee, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->READY_PLAYER_CHARACTER_FOR_TRIATHLON] Melee button INACTIVE.")
// Prevent player from activating the cinematic camera so it doesn't conflict with the TV news cam.
SET_CINEMATIC_BUTTON_ACTIVE(FALSE)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->READY_PLAYER_CHARACTER_FOR_TRIATHLON] Cinematic button INACTIVE.")
// Set player-related trackers.
bIsPlayerBikeSpeedSlowedForTransitionSet = FALSE
ENDPROC
/// PURPOSE: Start to save everything about the player's vehicle here
///
/// PARAMS:
/// viVehicle - The player's vehicle, probably can have different ones like the bicycle or your vehicle before the race
/// bRecreateVeh - Not sure it's purpose, but leaving it exposed.
PROC TRI_SAVE_VEHICLE_SETTINGS(VEHICLE_INDEX viVehicle, BOOL bRecreateVeh = FALSE)
TRI_Race.sPlayerVehicleData.iVehicleColor = GET_VEHICLE_COLOUR_COMBINATION( viVehicle )
TRI_Race.sPlayerVehicleData.modelName = GET_ENTITY_MODEL( viVehicle )
TRI_Race.sPlayerVehicleData.bRecreateSavedVeh = bRecreateVeh
GET_VEHICLE_SETUP( viVehicle, TRI_Race.sPlayerVehicleData.sVehicleSetup )
TRI_Race.sPlayerVehicleData.bProperlyInit = TRUE
CDEBUG1LN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->READY_PLAYER_CHARACTER_FOR_TRIATHLON] Vehicle settings properly INIT.")
ENDPROC
/// PURPOSE:
/// If the player arrived to the race in a vehicle, or left
/// a vehicle near the starting point of the race, store it
/// until the player has completed the race.
PROC STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Procedure started.")
fDestinationHeadingOfStoredPlayerVehicle = 0
vehPlayerDroveBeforeRace = GET_PLAYERS_LAST_VEHICLE()
vRaceLauncherPos = GET_TRIATHLON_RACE_POSITION_BY_RACE_INDEX(eCurrentTriRace)
IF NOT DOES_ENTITY_EXIST(vehPlayerDroveBeforeRace)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Player does not have a vehicle that exists to store during race.")
vehPlayerDroveBeforeRace = NULL
EXIT
ENDIF
IF IS_ENTITY_DEAD(vehPlayerDroveBeforeRace)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Player does not have a valid vehicle to store during race.")
vehPlayerDroveBeforeRace = NULL
EXIT
ENDIF
MODEL_NAMES modelName = GET_ENTITY_MODEL(GET_ENTITY_FROM_PED_OR_VEHICLE(vehPlayerDroveBeforeRace))
CPRINTLN(DEBUG_TRIATHLON, "the vehicle model name is: ", GET_MODEL_NAME_FOR_DEBUG(modelName))
//This should be wrapped up somehow
IF (modelName = TAXI
AND NOT IS_VEHICLE_SEAT_FREE(vehPlayerDroveBeforeRace, VS_DRIVER))
OR IS_THIS_MODEL_A_BOAT(modelName)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Player was driven to race by taxi or boat!")
vehPlayerDroveBeforeRace = NULL
EXIT
ENDIF
//Is it still valid at this point? Or have you lost it already
IF GET_DISTANCE_BETWEEN_COORDS(vRaceLauncherPos, GET_ENTITY_COORDS(vehPlayerDroveBeforeRace)) >= 100.0
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Player's vehicle is too far to store for the race ")
vehPlayerDroveBeforeRace = NULL
EXIT
ENDIF
// Set the vehicle as a mission entity so it doesn't get deleted while it's offscreen and far away from player.
// Store the position to return the player vehicle to.
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_ALAMO_SEA
vDestinationPosOfStoredPlayerVehicle = <<1747.3027, 3904.7615, 33.9140>>
fDestinationHeadingOfStoredPlayerVehicle = 201.6
BREAK
CASE TRIATHLON_RACE_VESPUCCI
vDestinationPosOfStoredPlayerVehicle = <<-1345.9988, -1010.2684, 7.0159>>
fDestinationHeadingOfStoredPlayerVehicle = 30.0
BREAK
CASE TRIATHLON_RACE_IRONMAN
vDestinationPosOfStoredPlayerVehicle = << -2286.66, 409.97, 174.12 >>
fDestinationHeadingOfStoredPlayerVehicle = 133.90
BREAK
ENDSWITCH
//B*1567473 - Leveling up the vehicle savings for Triathlon - 7/19/13
SET_MISSION_VEHICLE_GEN_VEHICLE( vehPlayerDroveBeforeRace, <<0,0,0>>, 0 )
SET_LAST_DRIVEN_VEHICLE( vehPlayerDroveBeforeRace )
TRI_SAVE_VEHICLE_SETTINGS(vehPlayerDroveBeforeRace)
TRI_POSITION_VEHICLE_AT_RACE_ORIGIN()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Warping vehicle player arrived in to an out-of-view location during race.")
CPRINTLN(DEBUG_TRIATHLON, "vDestinationPosOfStoredPlayerVehicle = ", vDestinationPosOfStoredPlayerVehicle)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE] Set destination position and headig for returning vehicle at the end of the race.")
ENDPROC
// ===============================================
// E N D PLAYER PROCEDURES AND FUNCTIONS
// ===============================================
// ===============================================
// REQUESTS PROCEDURES AND FUNCTIONS
// ===============================================
PROC TRI_REQUEST_INTRO_WAYPOINT_RECS(TRI_RACE_STRUCT& Race)
TEXT_LABEL_63 waypointRec
INT iIndex
REPEAT Race.iRacerCnt iIndex
IF iIndex <> 0
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_VESPUCCI
waypointRec = "triathlon_ves_racer"
BREAK
CASE TRIATHLON_RACE_ALAMO_SEA
waypointRec = "triathlon_ala_racer"
BREAK
CASE TRIATHLON_RACE_IRONMAN
waypointRec = "triathlon_coy_racer"
BREAK
ENDSWITCH
waypointRec += iIndex
REQUEST_WAYPOINT_RECORDING(waypointRec)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Request Triathlon string tables.
PROC REQUEST_TRI_WAYPOINT_RECORDINGS(TRI_RACE_STRUCT& Race)
SWITCH (eCurrentTriRace)
CASE TRIATHLON_RACE_ALAMO_SEA
REQUEST_WAYPOINT_RECORDING("Tri1_Bk_0")
REQUEST_WAYPOINT_RECORDING("Tri1_Run")
BREAK
CASE TRIATHLON_RACE_VESPUCCI
REQUEST_WAYPOINT_RECORDING("Tri2_Bk_0")
REQUEST_WAYPOINT_RECORDING("Tri2_Run")
BREAK
CASE TRIATHLON_RACE_IRONMAN
REQUEST_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_0)
REQUEST_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_1)
REQUEST_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_2)
REQUEST_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_3)
REQUEST_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_4)
REQUEST_WAYPOINT_RECORDING("Tri3_Run")
BREAK
ENDSWITCH
TRI_REQUEST_INTRO_WAYPOINT_RECS(Race)
ENDPROC
/// PURPOSE:
/// Request Triathlon string tables.
PROC REQUEST_TRI_SCALEFORM()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_SCALEFORM] Requesting Triathlon scaleform movies.")
scformTVCam = REQUEST_SCALEFORM_MOVIE("BREAKING_NEWS")
ENDPROC
/// PURPOSE:
/// Request Triathlon textures.
PROC REQUEST_TRI_TEXTURES()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_TEXTURES] Requesting Triathlon textures.")
// Contains all medals, images and checkpoint decal textures.
REQUEST_STREAMED_TEXTURE_DICT("TRIATHLON")
// Contains some textures shared across several missions and minigames, and other things.
REQUEST_STREAMED_TEXTURE_DICT("Shared")
//Request the dictionary for the coronas
REQUEST_STREAMED_TEXTURE_DICT(texCheckPatch)
ENDPROC
/// PURPOSE:
/// Request Triathlon string tables.
PROC REQUEST_TRI_STRING_TABLES()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_STRING_TABLES] Requesting Triathlon string tables.")
REQUEST_ADDITIONAL_TEXT("SP_SPR", MINIGAME_TEXT_SLOT)
ENDPROC
/// PURPOSE:
/// Request Tri-specific animations.
PROC REQUEST_TRI_ANIMATIONS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_ANIMATIONS] Requesting Triathlon animations.")
// Request all animations.
INT iAnimDictCounter
REPEAT COUNT_OF(szTriAnimDicts) iAnimDictCounter
REQUEST_ANIM_DICT(szTriAnimDicts[iAnimDictCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_ANIMATIONS] The animation dictionary ", szTriAnimDicts[iAnimDictCounter], " was just requested.")
ENDREPEAT
REQUEST_ANIM_DICT("VEH@BIKE@COMMON@FRONT@BASE")
REQUEST_ANIM_SET("random@escape_paparazzi@standing@")
REQUEST_ANIM_DICT("VEH@BICYCLE@ROADFRONT@BASE")
REQUEST_ANIM_DICT("missfbi4")
REQUEST_ANIM_DICT("mini@triathlonintro")
ENDPROC
/// PURPOSE:
/// Request Tri-specific models.
PROC REQUEST_TRI_MODELS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_MODELS] Requesting Triathlon models.")
// Load bike models.
REQUEST_MODEL(TRIBIKE)
REQUEST_MODEL(TRIBIKE2)
REQUEST_MODEL(TRIBIKE3)
// Load street barriers to delineate race roads.
REQUEST_MODEL(PROP_BARRIER_WORK06A)
// Request models needed for the helicopter
//REQUEST_MODEL(A_M_M_PAPARAZZI_01)
REQUEST_MODEL(FROGGER)
// Request Buoy model
REQUEST_MODEL(PROP_DOCK_BOUY_3)
REQUEST_MODEL(A_M_Y_RoadCyc_01)
//REQUEST_MODEL(A_M_M_Paparazzi_01) // prestream photogs for the scenario
//REQUEST_MODEL(A_F_Y_EastSA_03) // prestream females for the scenario
//REQUEST_MODEL(A_F_Y_EastSA_01) // prestream females for the scenario
//REQUEST_MODEL(A_F_Y_Vinewood_01) // prestream females for the scenario
//REQUEST_MODEL(A_F_Y_Fitness_01) // prestream females for the scenario
//REQUEST_MODEL(A_M_Y_Runner_01) // prestream males for the scenario
//REQUEST_MODEL(A_M_Y_Beach_02) // prestream males for the scenario
//REQUEST_MODEL(A_M_Y_BeachVesp_01) // prestream males for the scenario
//REQUEST_MODEL(A_M_Y_EastSA_01) // prestream males for the scenario
REQUEST_MODEL(PROP_PENCIL_01)
ENDPROC
/// PURPOSE:
/// Request Tri-specific assets.
PROC REQUEST_TRI_ASSETS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI_MODELS] Requesting Triathlon assets.")
REQUEST_TRI_MODELS()
REQUEST_TRI_ANIMATIONS()
REQUEST_TRI_STRING_TABLES()
REQUEST_TRI_TEXTURES()
REQUEST_TRI_SCALEFORM()
ENDPROC
/// PURPOSE:
/// Request Triathlon assets and waypoint recordings.
PROC REQUEST_TRI(TRI_RACE_STRUCT& Race)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REQUEST_TRI] Requesting Triathlon assets and waypoint recordings.")
REQUEST_TRI_ASSETS()
REQUEST_TRI_WAYPOINT_RECORDINGS(Race)
ENDPROC
FUNC BOOL HAVE_TRI_INTRO_WAYPOINT_RECORDINGS_LOADED(TRI_RACE_STRUCT& Race)
TEXT_LABEL_63 waypointRec
BOOL bRetVal = TRUE
INT iIndex
REPEAT Race.iRacerCnt iIndex
IF iIndex <> 0
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_VESPUCCI
waypointRec = "triathlon_ves_racer"
BREAK
CASE TRIATHLON_RACE_ALAMO_SEA
waypointRec = "triathlon_ala_racer"
BREAK
CASE TRIATHLON_RACE_IRONMAN
waypointRec = "triathlon_coy_racer"
BREAK
ENDSWITCH
waypointRec += iIndex
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(waypointRec)
bRetVal = FALSE
ENDIF
ENDIF
ENDREPEAT
RETURN bRetVal
ENDFUNC
/// PURPOSE:
/// Check if the requested Triathlon waypoint recordings have loaded.
FUNC BOOL HAVE_TRI_WAYPOINT_RECORDINGS_LOADED(TRI_RACE_STRUCT& Race)
IF NOT HAVE_TRI_INTRO_WAYPOINT_RECORDINGS_LOADED(Race)
RETURN FALSE
ENDIF
SWITCH (eCurrentTriRace)
CASE TRIATHLON_RACE_ALAMO_SEA
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED("Tri1_Bk_0")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] Tri1_Bk_0 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED("Tri1_Run")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] Tri1_Run has NOT yet loaded.")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] All Triathlon 1 waypoint recordings have LOADED!")
RETURN TRUE
BREAK
CASE TRIATHLON_RACE_VESPUCCI
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED("Tri2_Bk_0")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] Tri2_Bk_0 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED("Tri2_Run")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] Tri2_Run has NOT yet loaded.")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] All Triathlon 2 waypoint recordings have LOADED!")
RETURN TRUE
BREAK
CASE TRIATHLON_RACE_IRONMAN
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED("Tri3_Run")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] Tri3_Run has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(szTriBikeRecordingName_IronMan_0)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] szTriBikeRecordingName_IronMan_0 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(szTriBikeRecordingName_IronMan_1)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] szTriBikeRecordingName_IronMan_1 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(szTriBikeRecordingName_IronMan_2)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] szTriBikeRecordingName_IronMan_2 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(szTriBikeRecordingName_IronMan_3)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] szTriBikeRecordingName_IronMan_3 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(szTriBikeRecordingName_IronMan_4)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] szTriBikeRecordingName_IronMan_4 has NOT yet loaded.")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_WAYPOINT_RECORDINGS_LOADED] All Triathlon 3 waypoint recordings have LOADED!")
RETURN TRUE
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Check if the requested Triathlon scaleform movies have loaded.
FUNC BOOL HAVE_TRI_SCALEFORM_MOVIES_LOADED()
IF NOT HAS_SCALEFORM_MOVIE_LOADED(scformTVCam)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_SCALEFORM_MOVIES_LOADED] Scaleform movie scformTVCam has NOT yet loaded!")
RETURN FALSE
ENDIF
IF NOT LOAD_MENU_ASSETS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_SCALEFORM_MOVIES_LOADED] Waiting for LOAD_MENU_ASSETS")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_SCALEFORM_MOVIES_LOADED] All Triathlon scaleform movies have LOADED!")
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Check if the requested Triathlon textures have loaded.
FUNC BOOL HAVE_TRI_TEXTURES_LOADED()
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED("TRIATHLON")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_STRING_TABLES_LOADED] Texture dictionary TRIATHLON has NOT yet loaded!")
RETURN FALSE
ENDIF
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED(texCheckPatch)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_STRING_TABLES_LOADED] Texture dictionary texCheckPatch has NOT yet loaded!")
RETURN FALSE
ENDIF
// Contains some textures shared across several missions and minigames, and other things.
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED("Shared")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_STRING_TABLES_LOADED] Texture dictionary Shared has NOT yet loaded!")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_STRING_TABLES_LOADED] All Triathlon textures have LOADED!")
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Check if the requested Triathlon string tables have loaded.
FUNC BOOL HAVE_TRI_STRING_TABLES_LOADED()
IF NOT HAS_ADDITIONAL_TEXT_LOADED(MINIGAME_TEXT_SLOT)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_STRING_TABLES_LOADED] String table ", MINIGAME_TEXT_SLOT, " has NOT yet loaded!")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_STRING_TABLES_LOADED] All Triathlon string tables have LOADED!")
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Check if the requested Triathlon animations have loaded.
FUNC BOOL HAVE_TRI_ANIMATIONS_LOADED()
INT iLoopCounter
REPEAT COUNT_OF(szTriAnimDicts) iLoopCounter
IF NOT HAS_ANIM_DICT_LOADED(szTriAnimDicts[iLoopCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_ANIMATIONS_LOADED] Animation ", szTriAnimDicts[iLoopCounter], " has NOT yet loaded.")
RETURN FALSE
ENDIF
ENDREPEAT
IF NOT HAS_ANIM_DICT_LOADED("VEH@BIKE@COMMON@FRONT@BASE")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_ANIMATIONS_LOADED] VEH@BIKE@COMMON@FRONT@BASE has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAS_ANIM_DICT_LOADED("missfbi4")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_ANIMATIONS_LOADED] missfbi4 has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAS_ANIM_SET_LOADED("random@escape_paparazzi@standing@")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_ANIMATIONS_LOADED] random@escape_paparazzi@standing@ has NOT yet loaded.")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_ANIMATIONS_LOADED] All Triathlon animations have LOADED!")
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Check if the requested Triathlon models have loaded.
FUNC BOOL HAVE_TRI_MODELS_LOADED()
IF NOT HAS_MODEL_LOADED(PROP_BARRIER_WORK06A)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", PROP_BARRIER_WORK06A, " has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAS_MODEL_LOADED(TRIBIKE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", TRIBIKE, " has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAS_MODEL_LOADED(TRIBIKE2)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", TRIBIKE2, " has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAS_MODEL_LOADED(TRIBIKE3)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", TRIBIKE3, " has NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAS_MODEL_LOADED(FROGGER)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", FROGGER, " has NOT yet loaded.")
RETURN FALSE
ENDIF
// IF NOT HAS_MODEL_LOADED(A_M_M_PAPARAZZI_01)
// CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", A_M_M_PAPARAZZI_01, " has NOT yet loaded.")
// RETURN FALSE
// ENDIF
IF NOT HAS_MODEL_LOADED(PROP_DOCK_BOUY_3)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] Model ", PROP_DOCK_BOUY_3, " has NOT yet loaded.")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_MODELS_LOADED] All Triathlon models have LOADED!")
RETURN TRUE
ENDFUNC
FUNC BOOL HAVE_TRI_AUDIO_ASSETS_LOADED()
IF NOT REQUEST_SCRIPT_AUDIO_BANK("CROWD_CHEER")
CPRINTLN(DEBUG_TRIATHLON, "Waiting for CROWD_CHEER audio")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Check if all Triathlon assets have loaded.
FUNC BOOL HAVE_TRI_ASSETS_LOADED()
IF NOT HAVE_TRI_MODELS_LOADED()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_ASSETS_LOADED] Triathlon models are NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAVE_TRI_ANIMATIONS_LOADED()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_ASSETS_LOADED] Triathlon animations are NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAVE_TRI_STRING_TABLES_LOADED()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_ASSETS_LOADED] Triathlon string tables are NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAVE_TRI_TEXTURES_LOADED()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_ASSETS_LOADED] Triathlon textures are NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAVE_TRI_SCALEFORM_MOVIES_LOADED()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP->HAVE_TRI_ASSETS_LOADED] Triathlon scaleform movies are NOT yet loaded.")
RETURN FALSE
ENDIF
IF NOT HAVE_TRI_AUDIO_ASSETS_LOADED()
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HAVE_TRI_ASSETS_LOADED] All Triathlon assets have LOADED!")
RETURN TRUE
ENDFUNC
// ===============================================
// E N D REQUESTS PROCEDURES AND FUNCTIONS
// ===============================================
// ===============================================
// TRI CLEANUP PROCEDURES AND FUNCTIONS
// ===============================================
/// PURPOSE:
/// Cancel dialog timers.
PROC CANCEL_TRI_DIALOG_TIMERS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CANCEL_TRI_DIALOG_TIMERS] Procedure started.")
CANCEL_TIMER(timerAnyDialogCanPlay)
CANCEL_TIMER(timerPlayerRemainingInPlace)
CANCEL_TIMER(timerPlayerRemainingInFirstPlace)
CANCEL_TIMER(timerPlayerRemainingInSecondPlace)
CANCEL_TIMER(timerPlayerDialogCanPlay)
CANCEL_TIMER(timerPlayerStayInPlaceDialogCanPlay)
CANCEL_TIMER(timerPlayerStayFirstDialogCanPlay)
CANCEL_TIMER(timerPlayerStaySecondDialogCanPlay)
CANCEL_TIMER(timerPlayerStayLastDialogCanPlay)
ENDPROC
/// PURPOSE:
/// Reset racers' AI.
PROC RESET_RADAR_BLIPS()
IF DOES_BLIP_EXIST(blipBikes)
REMOVE_BLIP(blipBikes)
ENDIF
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
ENDIF
ENDPROC
/// PURPOSE:
/// Reset racers' AI.
PROC RESET_TRI_AI()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->RESET_TRI_AI] Procedure started.")
bIsEndOfRaceRacerAnimSet = FALSE
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver)
CLEAR_PED_TASKS(TRI_Race.Racer[iRacerCounter].Driver)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// reset the helicopter over the player
PROC RESET_TRI_CHASE_HELI(VECTOR vReset)
//Create a helicopter, put a pilot in it, task it to chase us.
CPRINTLN(DEBUG_TRIATHLON, "RESET_TRI_CHASE_HELI called")
IF NOT IS_ENTITY_DEAD(vehChopper)
SET_ENTITY_COORDS(vehChopper, vReset)
ENDIF
TASK_TRI_HELI(pedPilot, vehChopper)
ENDPROC
/// PURPOSE:
/// Remove Race barriers. These need to be removed even on restart, since
/// some races enable and disable sets of barriers based on player location.
PROC REMOVE_TRI_RACE_BARRIERS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->REMOVE_TRI_RACE_BARRIERS] Procedure started.")
// Remove the race barriers.
INT iBarricadeCounter
REPEAT COUNT_OF(objTriRaceBarricades) iBarricadeCounter
IF DOES_ENTITY_EXIST(objTriRaceBarricades[iBarricadeCounter])
DELETE_OBJECT(objTriRaceBarricades[iBarricadeCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Deleting barricade at index ", iBarricadeCounter)
ENDIF
ENDREPEAT
REPEAT iNumTriRaceBarricadesPerGroup iBarricadeCounter
IF DOES_ENTITY_EXIST(objTriRaceBarricades_Group1[iBarricadeCounter])
DELETE_OBJECT(objTriRaceBarricades_Group1[iBarricadeCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Delete Group 1 barricades at index ", iBarricadeCounter)
ENDIF
IF DOES_ENTITY_EXIST(objTriRaceBarricades_Group2[iBarricadeCounter])
DELETE_OBJECT(objTriRaceBarricades_Group2[iBarricadeCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Delete Group 2 barricades at index ", iBarricadeCounter)
ENDIF
IF DOES_ENTITY_EXIST(objTriRaceBarricades_Group3[iBarricadeCounter])
DELETE_OBJECT(objTriRaceBarricades_Group3[iBarricadeCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Delete Group 3 barricades at index ", iBarricadeCounter)
ENDIF
IF DOES_ENTITY_EXIST(objTriRaceBarricades_Group4[iBarricadeCounter])
DELETE_OBJECT(objTriRaceBarricades_Group4[iBarricadeCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Delete Group 4 barricades at index ", iBarricadeCounter)
ENDIF
ENDREPEAT
//IF DOES_ENTITY_EXIST( Tri_Master.oClipboard )
// SET_ENTITY_AS_MISSION_ENTITY( Tri_Master.oClipboard, DEFAULT, TRUE )
// DELETE_OBJECT( Tri_Master.oClipboard )
//ENDIF
ENDPROC
/// PURPOSE:
/// Triathlon 2, Vespucci Beach, has errant buoys removed by script, this places them back in the world.
PROC RESET_TRI_ERRANT_BUOYS()
IF DOES_ENTITY_EXIST(TRI_Race.objErrantBuoy1)
SET_ENTITY_VISIBLE(TRI_Race.objErrantBuoy1, TRUE)
SET_ENTITY_COLLISION(TRI_Race.objErrantBuoy1, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "Restoring the first errant buoy")
ENDIF
IF DOES_ENTITY_EXIST(TRI_Race.objErrantBuoy2)
SET_ENTITY_VISIBLE(TRI_Race.objErrantBuoy2, TRUE)
SET_ENTITY_COLLISION(TRI_Race.objErrantBuoy2, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "Restoring the second errant buoy")
ENDIF
ENDPROC
/// PURPOSE:
/// Reset Triathlon to its initial state.
PROC RESET_TRI(BOOL bRaceRestarting = FALSE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->RESET_TRI] Procedure started.")
CPRINTLN(DEBUG_TRIATHLON, "RESET_TRI: Allowing peds in area")
// SWITCH TRI_Master.iRaceCur
// Remove 0-based road node speed zones.
// REMOVE_TRI_RACE_ROAD_NODE_SPEED_ZONES()
CLEAR_AREA_AROUND_TRI_POS(TRI_Race.sGate[0].vPos)
// Remove race barriers.
REMOVE_TRI_RACE_BARRIERS()
// Reset racers' AI.
RESET_TRI_AI()
// Reset radar blips.
RESET_RADAR_BLIPS()
// Destroy intro cutscene camera.
DESTROY_TRI_INTRO_CUTSCENE_CAMERAS()
// Cancel dialog timers. They'll restart as intended.
CANCEL_TRI_DIALOG_TIMERS()
// Turn off any debug that may have been turned on during the game.
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(FALSE)
// Resetting last known info to be consistent with missions, B*909265
ResetLastKnownPedInfo(g_savedGlobals.sPlayerData.sInfo, SP_MISSION_NONE)
IF NOT bRaceRestarting
RESET_TRI_ERRANT_BUOYS()
ENDIF
IF bRaceRestarting
CPRINTLN(DEBUG_TRIATHLON, "RESET_TRI :: RENDER_SCRIPT_CAMS(FALSE, FALSE)")
RENDER_SCRIPT_CAMS(FALSE, FALSE)
ENDIF
CLEAR_TRI_CONTROL_FLAG(TCF_NEWS_CAM_ACTIVE)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_1)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_2)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_3)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_4)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_5)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_6)
CLEAR_TRI_CONTROL_FLAG(TCF_RACER_WAYPOINTED_7)
//Set multihead blinders off
SET_MULTIHEAD_SAFE(FALSE,TRUE)
ENDPROC
/// PURPOSE:
/// Revert default settings originally altered for the Triathlon race.
PROC CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Procedure started.")
// Clear any Triathlon routes used for the races.
CLEAR_GPS_CUSTOM_ROUTE()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Custom GPS cleared.")
// Ensure radar is being displayed.
IF IS_RADAR_HIDDEN()
DISPLAY_RADAR(TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Display hidden radar.")
ENDIF
// Re-enable melee functionality.
SET_PED_CONFIG_FLAG(GET_PLAYER_PED(GET_PLAYER_INDEX()), PCF_DisableMelee, FALSE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Melee functionality re-enabled.")
// Re-enable cinematic button.
SET_CINEMATIC_BUTTON_ACTIVE(TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Cinematic camera button re-enabled.")
// Re-enable player control.
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Player control re-enabled.")
// Allow the player to behave in the water as intended.
SET_PED_MAX_TIME_IN_WATER(GET_PLAYER_PED(PLAYER_ID()), 300.0)
SET_PED_DIES_IN_WATER(GET_PLAYER_PED(PLAYER_ID()), TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Player affected by water as intended.")
// Remove helmet in case the player's original attire included a helmet.
REMOVE_PLAYER_HELMET(GET_PLAYER_INDEX(), TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] Player helmet removed if he was carrying one before race.")
// Allow player to access any bike, if any of them are still available, and set bikes to their default speed.
INT iRacerCounter
REPEAT (TRI_Race.iRacerCnt) iRacerCounter
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Vehicle)
SET_VEHICLE_IS_CONSIDERED_BY_PLAYER(TRI_Race.Racer[iRacerCounter].Vehicle, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[Triathlon.sc->CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS] :: Allowing bike ", iRacerCounter, " to be mounted by player")
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerCounter].Driver)
SET_DRIVE_TASK_CRUISE_SPEED(TRI_Race.Racer[iRacerCounter].Driver, Tri_Racer_AI_Speed.fDefaultTribikeTopSpeedOnFlatSurface)
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC CLEANUP_TRI_INTRO_WAYPOINT_RECORDINGS(TRI_RACE_STRUCT& Race)
TEXT_LABEL_63 waypointRec
INT iIndex
REPEAT Race.iRacerCnt iIndex
IF iIndex <> 0
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_VESPUCCI
waypointRec = "triathlon_ves_racer"
BREAK
CASE TRIATHLON_RACE_ALAMO_SEA
waypointRec = "triathlon_ala_racer"
BREAK
CASE TRIATHLON_RACE_IRONMAN
waypointRec = "triathlon_coy_racer"
BREAK
ENDSWITCH
waypointRec += iIndex
REMOVE_WAYPOINT_RECORDING( waypointRec )
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Remove any requested waypoint recordings.
PROC CLEANUP_TRI_WAYPOINT_RECORDINGS(TRI_RACE_STRUCT& Race)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_WAYPOINT_RECORDINGS] Procedure started.")
// Remove waypoint recordings.
SWITCH (eCurrentTriRace)
CASE TRIATHLON_RACE_ALAMO_SEA
REMOVE_WAYPOINT_RECORDING("Tri1_Bk_0")
REMOVE_WAYPOINT_RECORDING("Tri1_Run")
BREAK
CASE TRIATHLON_RACE_VESPUCCI
REMOVE_WAYPOINT_RECORDING("Tri2_Bk_0")
REMOVE_WAYPOINT_RECORDING("Tri2_Run")
BREAK
CASE TRIATHLON_RACE_IRONMAN
REMOVE_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_0)
REMOVE_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_1)
REMOVE_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_2)
REMOVE_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_3)
REMOVE_WAYPOINT_RECORDING(szTriBikeRecordingName_IronMan_4)
REMOVE_WAYPOINT_RECORDING("Tri3_Run")
BREAK
ENDSWITCH
CLEANUP_TRI_INTRO_WAYPOINT_RECORDINGS(Race)
ENDPROC
/// PURPOSE:
/// Remove any requested scaleform movies.
PROC CLEANUP_TRI_SCALEFORM_MOVIES()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_SCALEFORM_MOVIES] Procedure started.")
CLEANUP_MENU_ASSETS()
// Remove the TV camera HUD.
SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(scformTVCam)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_ANIMATIONS] Cleaned up scaleform movie scformTVCam.")
ENDPROC
/// PURPOSE:
/// Remove any requested texture dictionaries.
PROC CLEANUP_TRI_TEXTURES()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_TEXTURES] Procedure started.")
// Remove texture dictionary containing medals, checkpoint decals and scoreboard images.
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("TRIATHLON")
// Contains some textures shared across several missions and minigames, and other things.
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("Shared")
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED(texCheckPatch)
ENDPROC
/// PURPOSE:
/// Remove any loaded string tables.
PROC CLEANUP_TRI_STRING_TABLES()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_STRING_TABLES] Procedure started.")
CLEAR_ADDITIONAL_TEXT(MINIGAME_TEXT_SLOT, TRUE)
ENDPROC
/// PURPOSE:
/// Remove any loaded animation dictionaries.
PROC CLEANUP_TRI_ANIMATIONS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_ANIMATIONS] Procedure started.")
INT iAnimDictCounter
REPEAT COUNT_OF(szTriAnimDicts) iAnimDictCounter
REMOVE_ANIM_DICT(szTriAnimDicts[iAnimDictCounter])
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_ANIMATIONS] Cleaned up animation dictionary ", szTriAnimDicts[iAnimDictCounter])
ENDREPEAT
REMOVE_ANIM_DICT("VEH@BIKE@COMMON@FRONT@BASE")
REMOVE_ANIM_DICT("missfbi4")
REMOVE_ANIM_DICT("mini@triathlonintro")
ENDPROC
/// PURPOSE:
/// Remove any loaded models.
PROC CLEANUP_TRI_MODELS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Procedure started.")
SET_MODEL_AS_NO_LONGER_NEEDED(PROP_BARRIER_WORK06A)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Cleaned up ", PROP_BARRIER_WORK06A)
SET_MODEL_AS_NO_LONGER_NEEDED(FROGGER)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Cleaned up ", FROGGER)
// SET_MODEL_AS_NO_LONGER_NEEDED(A_M_M_PAPARAZZI_01)
// CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_MODELS] Cleaned up ", A_M_M_PAPARAZZI_01)
SET_MODEL_AS_NO_LONGER_NEEDED(PROP_PENCIL_01)
ENDPROC
/// PURPOSE:
/// Let the heli go, if it loves you it'll come back on its own.
PROC CLEANUP_TRI_CHASE_HELI()
IF NOT IS_PED_INJURED(pedPilot)
CLEAR_PED_TASKS(pedPilot)
ENDIF
SET_VEHICLE_AS_NO_LONGER_NEEDED(vehChopper)
SET_PED_AS_NO_LONGER_NEEDED(pedPilot)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_CHASE_HELI] Cleaned up vehChopper")
ENDPROC
/// PURPOSE:
/// Remove any Tri-specific assets.
PROC CLEANUP_TRI_ASSETS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_ASSETS] Cleaning up assets.")
// Remove any loaded models.
CLEANUP_TRI_MODELS()
// Remove any loaded animation dictionaries.
CLEANUP_TRI_ANIMATIONS()
// Remove any loaded string tables.
CLEANUP_TRI_STRING_TABLES()
// Remove any requested texture dictionaries.
CLEANUP_TRI_TEXTURES()
// Remove any loaded scaleform movies.
CLEANUP_TRI_SCALEFORM_MOVIES()
ENDPROC
/// PURPOSE:
/// Clean up Triathlon before terminating the script.
///
/// NOTE: This is NOT called when the player chooses
/// to restart the race.
PROC CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT(TRI_RACE_STRUCT& Race, BOOL bInterpToGameCam = TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT] Procedure started.")
// Set race roads back to their original state.
SET_TRI_RACE_ROADS_BACK_TO_ORIGINAL_STATE()
// Remove any Triathlon assets.
CLEANUP_TRI_ASSETS()
// Remove any requested waypoint recordings.
CLEANUP_TRI_WAYPOINT_RECORDINGS(Race)
// Revert default settings originally altered for the Triathlon race.
CLEANUP_RACE_CHANGES_MADE_TO_DEFAULT_WORLD_SETTINGS()
// Destroy any created cameras.
CLEANUP_TRI_CAMERAS(bInterpToGameCam)
// Cleanup Tri Chase Heli
CLEANUP_TRI_CHASE_HELI()
// Cleanup race banners
CLEANUP_TRI_RACE_BANNERS()
IF IS_TRI_CONTROL_FLAG_SET(TCF_FINISHED_RACE)
CLEAR_AREA_OF_PEDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), 25.0)
IF NOT Tri_Master.bVariationRestored
CPRINTLN(DEBUG_TRIATHLON, "PROC CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT restoring outfit # 1")
RESTORE_PLAYER_PED_VARIATIONS(PLAYER_PED_ID())
SET_PED_VARIATIONS(PLAYER_PED_ID(),Tri_Master.sPlayerVariation)
Tri_Master.bVariationRestored = TRUE
ENDIF
ENDIF
Set_Leave_Area_Flag_For_All_Blipped_Missions()
// Activate scenario groups
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
ENDPROC
/// PURPOSE:
/// Cleanup SPR system for Triathlon.
PROC CLEANUP_TRI_SYSTEM_TRI_RACE()
CPRINTLN(DEBUG_TRIATHLON, "CLEANUP_TRI_SYSTEM_TRI_RACE() started")
ENABLE_SPECIAL_ABILITY(PLAYER_ID(), TRUE)
TRI_SET_PED_CONFIG_FLAG( PLAYER_PED_ID(), PCF_DisableDeepSurfaceAnims, FALSE )
CANCEL_TIMER(TRI_Race.tClock)
TRI_Cleanup_Leaderboard(TRI_Race)
BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_YOGA) //stockmarket #1514495
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
TRI_Race.fBestClockTime = fBestClockTime
TRI_Race.fBestSplitTime = TRI_Race.fBestClockTime / 2.0
CLEAR_PED_NON_CREATION_AREA()
ENDIF
// Reset all racers before cleaning them up.
TRI_Race_Gate_Init_All(TRI_Race)
TRI_Race.iGateCnt = 0
// Cleanup the race banners
CLEANUP_TRI_RACE_BANNERS()
// Cleanup the swim buoys
CLEANUP_TRI_SWIM_LEG_BUOYS(TRI_Race)
// CLean up the end screen UI
RELEASE_TRI_END_SCREEN()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver) OR IS_PED_INJURED(TRI_Race.Racer[0].Driver) // AND TRI_Race.Racer[iRacerCounter].iGateCur < TRI_Race.
IF NOT IS_PED_INJURED(TRI_Race.Racer[iRacerCounter].Driver) AND iRacerCounter <> 0
CPRINTLN(DEBUG_TRIATHLON, "CLEANUP_TRI_SYSTEM_TRI_RACE :: TASK_GO_STRAIGHT_TO_COORD(TRI_Race.Racer[", iRacerCounter, "].Driver, (TRI_Race.Racer[", iRacerCounter, "].vStartPos)")
TASK_GO_STRAIGHT_TO_COORD(TRI_Race.Racer[iRacerCounter].Driver, (TRI_Race.Racer[iRacerCounter].vStartPos), PEDMOVE_WALK)
ENDIF
ELIF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver) AND NOT IS_PED_INJURED(TRI_Race.Racer[0].Driver)
IF NOT (TRI_Race.Racer[iRacerCounter].Driver = TRI_Race.Racer[0].Driver)
CPRINTLN(DEBUG_TRIATHLON, "CLEANUP_TRI_SYSTEM_TRI_RACE :: SET_PED_AS_NO_LONGER_NEEDED(TRI_Race.Racer[", iRacerCounter, "].Driver)")
SET_PED_AS_NO_LONGER_NEEDED(TRI_Race.Racer[iRacerCounter].Driver)
ENDIF
ENDIF
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Vehicle)
SET_VEHICLE_AS_NO_LONGER_NEEDED(TRI_Race.Racer[iRacerCounter].Vehicle)
ENDIF
ENDREPEAT
IF IS_TRI_CONTROL_FLAG_SET(TCF_FINISHED_RACE)
CPRINTLN(DEBUG_TRIATHLON, "IF IS_TRI_CONTROL_FLAG_SET(TCF_FINISHED_RACE) restoring outfit")
IF NOT Tri_Master.bVariationRestored
CPRINTLN(DEBUG_TRIATHLON, "PROC CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT restoring outfit # 2")
RESTORE_PLAYER_PED_VARIATIONS(PLAYER_PED_ID())
SET_PED_VARIATIONS(PLAYER_PED_ID(), Tri_Master.sPlayerVariation)
Tri_Master.bVariationRestored = TRUE
ENDIF
ENDIF
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(FALSE)
// Un-suppress the runner model
SET_PED_MODEL_IS_SUPPRESSED(A_M_Y_RoadCyc_01, FALSE)
SET_PED_MODEL_IS_SUPPRESSED(A_C_SharkTiger, FALSE)
// Enable cellphone.
DISABLE_CELLPHONE(FALSE)
MISSION_FLOW_CLEAR_DISPLAY_MISSION_TITLE()
ENABLE_SELECTOR()
// Clear the exclusive scenario group string
szExlusiveScenarioGroup = NULL
// IF DOES_CAM_EXIST(camIntroIECam)
// CPRINTLN(DEBUG_TRIATHLON, "CLEANUP_TRI_SYSTEM_TRI_RACE :: STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()")
// STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()
// SIMULATE_PLAYER_INPUT_GAIT(PLAYER_ID(), PEDMOVE_WALK, 750)
// ENDIF
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
// Clear any help and print texts being displayed.
CLEAR_HELP()
CLEAR_PRINTS()
IF IS_SCREEN_FADED_OUT()
DO_SCREEN_FADE_IN(200)
ENDIF
ENDPROC
PROC UNLOCK_TRI_OUTFIT()
CDEBUG1LN(DEBUG_TRIATHLON, "UNLOCK_TRI_OUTFIT called")
enumCharacterList eChar = GET_CURRENT_PLAYER_PED_ENUM()
SWITCH eChar
CASE CHAR_MICHAEL
SET_PED_COMP_ITEM_ACQUIRED_SP(PLAYER_ZERO, COMP_TYPE_OUTFIT, OUTFIT_P0_TRIATHLON, TRUE)
SET_PED_COMP_ITEM_AVAILABLE_SP(PLAYER_ZERO, COMP_TYPE_OUTFIT, OUTFIT_P0_TRIATHLON, TRUE)
CDEBUG2LN(DEBUG_TRIATHLON, "UNLOCK_TRI_OUTFIT CHAR_MICHAEL")
BREAK
CASE CHAR_TREVOR
SET_PED_COMP_ITEM_ACQUIRED_SP(PLAYER_TWO, COMP_TYPE_OUTFIT, OUTFIT_P2_TRIATHLON, TRUE)
SET_PED_COMP_ITEM_AVAILABLE_SP(PLAYER_TWO, COMP_TYPE_OUTFIT, OUTFIT_P2_TRIATHLON, TRUE)
CDEBUG2LN(DEBUG_TRIATHLON, "UNLOCK_TRI_OUTFIT CHAR_TREVOR")
BREAK
CASE CHAR_FRANKLIN
SET_PED_COMP_ITEM_ACQUIRED_SP(PLAYER_ONE, COMP_TYPE_OUTFIT, OUTFIT_P1_TRIATHLON, TRUE)
SET_PED_COMP_ITEM_AVAILABLE_SP(PLAYER_ONE, COMP_TYPE_OUTFIT, OUTFIT_P1_TRIATHLON, TRUE)
CDEBUG2LN(DEBUG_TRIATHLON, "UNLOCK_TRI_OUTFIT CHAR_FRANKLIN")
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Cleanup SPR system and kill the script.
PROC CLEANUP_TRI_SYSTEM_AND_TERMINATE_TRIATHLON()
IF NOT IS_ENTITY_DEAD( PLAYER_PED_ID() )
IF NOT IS_PED_ON_ANY_BIKE( PLAYER_PED_ID() )
//FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_IDLE, TRUE)
ENDIF
ENDIF
// Cleanup SPR Main for Tri.
CLEANUP_TRI_SYSTEM_TRI_RACE()
UNLOCK_TRI_OUTFIT()
// If in Debug Mode, cleanup SPR Main Widget.
#IF IS_DEBUG_BUILD
TRI_Widget_Main_Cleanup(TRI_Widget)
// Cleanup running RAG->Script->Z-Volume. Ensure it's being initialized.
// NOTE: This should be commented out when checked in, as it triggers an assert
// when conflicting with the SPR race editor widget.
//CLEANUP_ZVOLUME_WIDGETS()
#ENDIF
//Restore the cam. -- This was shoving the cam up the player's butt at the end of the cutscene. - RP
//SET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT, CAM_VIEW_MODE_THIRD_PERSON_MEDIUM)
TRIGGER_MUSIC_EVENT("MGTR_STOP")
STOP_AUDIO_SCENE("TRI_START_SCENE")
STOP_AUDIO_SCENE("TRI_SWIM_SCENE")
STOP_AUDIO_SCENE("TRI_BIKE_SCENE")
STOP_AUDIO_SCENE("TRI_RUN_SCENE")
STOP_AUDIO_SCENE("TRI_END_SCENE")
CPRINTLN(DEBUG_TRIATHLON, "**************************************************** Triathlon Last Post ****************************************************")
// Terminate script.
TERMINATE_THIS_THREAD()
ENDPROC
/// PURPOSE:
/// Cleanup Triathlon and SPR system, and kill the script.
///
/// NOTE: This is called for sudden fail cases, like the player
/// getting killed, arrested, or when debug-failing.
PROC CLEANUP_ALL_AND_TERMINATE_TRIATHLON(TRI_RACE_STRUCT& Race, BOOL bInterpToGameCam=TRUE)
// Reset Triathlon to its initial state.
RESET_TRI()
// Run Triathlon cleanup.
CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT(Race, bInterpToGameCam)
// Run SPR system cleanup.
CLEANUP_TRI_SYSTEM_AND_TERMINATE_TRIATHLON()
ENDPROC
// ===============================================
// E N D TRI CLEANUP PROCEDURES AND FUNCTIONS
// ===============================================
// ===============================================
// TRI INIT PROCEDURES AND FUNCTIONS
// ===============================================
/// PURPOSE:
/// Initialize the racers last gate destination, so it's way past the final gate position.
/// This decreases the chance of racers getting too close to each other as they reach the
/// end of the race.
PROC INIT_TRI_RACERS_LAST_GATE_DESTINATION()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_CHECK_GATE_FOR_WARPING_RACERS_IN_SUPERDUMMY_MODE_IN_SWIM_LEG] Procedure started.")
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_ALAMO_SEA
vLastGateRacerDestination = << 1750.35, 3910.37, 33.95 >>
BREAK
CASE TRIATHLON_RACE_VESPUCCI
vLastGateRacerDestination = << -1326.66, -1054.43, 6.34 >>
BREAK
CASE TRIATHLON_RACE_IRONMAN
vLastGateRacerDestination = << -2306.02, 446.45, 173.48 >>
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Initialize the player's gate where racers in superdummy mode in
/// the swim leg can be warped to their bikes to resume race.
PROC INIT_TRI_CHECK_GATE_FOR_WARPING_RACERS_IN_SUPERDUMMY_MODE_IN_SWIM_LEG()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_CHECK_GATE_FOR_WARPING_RACERS_IN_SUPERDUMMY_MODE_IN_SWIM_LEG] Procedure started.")
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_ALAMO_SEA
iPlayerCurrentGateToWarpSuperDummySwimRacer = 9
BREAK
CASE TRIATHLON_RACE_VESPUCCI
iPlayerCurrentGateToWarpSuperDummySwimRacer = 11
BREAK
CASE TRIATHLON_RACE_IRONMAN
iPlayerCurrentGateToWarpSuperDummySwimRacer = 13
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Initialize where the player will slow down as he approaches
/// the bike->run transition gate.
PROC INIT_TRI_PLAYER_SLOWDOWN_APPROACH_TO_END_OF_BIKE_LEG()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_PLAYER_SLOWDOWN_APPROACH_TO_END_OF_BIKE_LEG] Procedure started.")
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_ALAMO_SEA
vSlowDownPlayerBikeAtThisPos = << 1936.00, 3931.37, 31.49 >>
BREAK
CASE TRIATHLON_RACE_VESPUCCI
vSlowDownPlayerBikeAtThisPos = << -1229.05, -880.58, 11.65 >>
BREAK
CASE TRIATHLON_RACE_IRONMAN
vSlowDownPlayerBikeAtThisPos = << -1241.35, 231.29, 63.51 >>
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Initialize the gates where help text will be displayed.
///
/// These gates will be checked against the player's current
/// gate, so the print help will display when the player clears
/// the gate before the one set below.
///
/// NOTE: As requested, we're only displaying help text
/// in Triathlon 1.
PROC INIT_TRI_SET_PRINT_HELP_GATES()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_SET_PRINT_HELP_GATES] Procedure started.")
iShowSwimHelpAtThisGate = 1 // Will print after player clears the first gate.
iShowBikeHelpAtThisGate = 5 // Will print a few seconds after player has cleared the invisible checkpoint
// surrounding all bikes, which is cleared only after player gets on a bike.
iStopShowBikeHelpAtThisGate = 16 // Will print a couple of gates before the bike->run transition. Print help should be out of the screen by then.
iShowRunHelpAtThisGate = 19 // Will print a few seconds after player gets off the bike in the bikr->run transition gate.
iShowTipHelpAtThisGate = 2 // Will print after player clears second gate.
iShowCamHelpAtThisGate = 3 // Will print after player clears last gate before reaching land.
ENDPROC
/// PURPOSE:
/// Initialize Triathlon waypoint recordings.
PROC INIT_TRI_WAYPOINT_RECORDINGS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_WAYPOINT_RECORDINGS] Initializing Triathlon waypoint recordings.")
IF eCurrentTriRace = TRIATHLON_RACE_IRONMAN
szTriBikeRecordingName_IronMan_0 = "Tri3_Bk_0"
szTriBikeRecordingName_IronMan_1 = "Tri3_Bk_1"
szTriBikeRecordingName_IronMan_2 = "Tri3_Bk_2"
szTriBikeRecordingName_IronMan_3 = "Tri3_Bk_3"
szTriBikeRecordingName_IronMan_4 = "Tri3_Bk_4"
ENDIF
ENDPROC
/// PURPOSE:
/// Initialize the TV camera news strings.
PROC INIT_TRI_TV_CAM_NEWS_STRINGS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_TV_CAM_NEWS_STRINGS] Initializing Triathlon TV cam news strings.")
szTVNews_Title = "TRI_NEWS_00"
szTVNews_Headline1 = "TRI_NEWS_01"
szTVNews_Headline2 = "TRI_NEWS_02"
szTVNews_Headline3 = "TRI_NEWS_03"
szTVNews_Headline4 = "TRI_NEWS_04"
szTVNews_Headline5 = "TRI_NEWS_05"
szTVNews_Headline6 = "TRI_NEWS_06"
szTVNews_Headline7 = "TRI_NEWS_07"
// Some of the strings will be specific to Ironman.
IF eCurrentTriRace = TRIATHLON_RACE_IRONMAN
szTVNews_Headline1 = "TRI_NEWS_30"
szTVNews_Headline2 = "TRI_NEWS_31"
szTVNews_Headline3 = "TRI_NEWS_32"
szTVNews_Headline4 = "TRI_NEWS_33"
szTVNews_Headline7 = "TRI_NEWS_34"
ENDIF
ENDPROC
/// PURPOSE:
/// Initialize Triathlon animation strings.
PROC INIT_TRI_ANIMATION_STRINGS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_ANIMATION_STRINGS] Initializing Triathlon animation strings.")
// Array holding anim dict names. This used to spread between dictionaries, now it's all mini@tri. Should consolidate these.
szTriAnimDicts[0] = "mini@triathlon" // Used for winning racer.
szTriAnimDicts[1] = "mini@triathlon" // Used for racers that placed.
szTriAnimDicts[2] = "mini@triathlon" // Used for racers at start of race.
szTriAnimDicts[3] = "mini@triathlon" // Used for the space between the intro and the end of the countdown
// Array holding all possible winning animation clips. These are used for the winner of the race.
szRaceWinningAnims[0] = "male_one_handed_a"
szRaceWinningAnims[1] = "male_two_handed_a"
szRaceWinningAnims[2] = "male_unarmed_a"
szRaceWinningAnims[3] = "male_unarmed_b"
// Array holding all possible finished animation clips. These are used for non-winning competitors as they finish the race.
szRaceFinishedAnims[0] = "jog_idle_d"
szRaceFinishedAnims[1] = "jog_idle_e"
szRaceFinishedAnims[2] = "jog_idle_f"
ENDPROC
// ===============================================
// E N D TRI INIT PROCEDURES AND FUNCTIONS
// ===============================================
// ===============================================
// TRI SETUP PROCEDURES AND FUNCTIONS
// ===============================================
/// PURPOSE:
/// Sets up the helicopter that validates the news coverage
/// PARAMS:
/// vFirstGate - Only used if bFirstInit is true
/// bFirstInit - Indicates that this is the first time the heli is created.
PROC SETUP_TRI_CHASE_HELI(TRIATHLON_RACE_INDEX eRace, BOOL bFirstInit)
//Create a helicopter, put a pilot in it, task it to chase us.
VECTOR vCreate
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
IF bFirstInit
IF eRace = TRIATHLON_RACE_ALAMO_SEA
vCreate = <<2382.7773, 4323.4897, 56.0818>>
ELIF eRace = TRIATHLON_RACE_VESPUCCI
vCreate = <<-1250.5433, -1844.4894, 0.8696>>
ELIF eRace = TRIATHLON_RACE_IRONMAN
vCreate = <<1593.9043, 3854.2043, 30.3967>>
ENDIF
ELSE
vCreate = vPlayerPos
vCreate.z += 100.0
ENDIF
//VEHICLE_INDEX vehNull = NULL
vehChopper = CREATE_VEHICLE(FROGGER, vCreate)
pedPilot = CREATE_PED_INSIDE_VEHICLE(vehChopper, PEDTYPE_MISSION, A_M_Y_RoadCyc_01)
//TASK_HELI_MISSION(pedPilot, vehChopper, vehNull, PLAYER_PED_ID(), vCreate, MISSION_FOLLOW, 10.0, 35.0, -1, 35, 35)
TASK_TRI_HELI(pedPilot, vehChopper)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc::SETUP_TRI_CHASE_HELI] Created Tri Chase Heli at ", vCreate)
ENDPROC
/// PURPOSE:
/// Setup the variables tracking if state of cameras used in Triathlon.
PROC SETUP_TRI_CAMERA_TRACKERS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SETUP_TRI_CAMERA_TRACKERS] Procedure started.")
bIsTVCamHintSetToBeCleared = FALSE
bTVCam_Has_TV_Cam_Stopped = TRUE
bFinishedLookingAtPlayer = FALSE
ENDPROC
/// PURPOSE:
/// Setup the variables for setting up and keeping track of racer bikes.
PROC SETUP_TRI_RACER_BIKES()
// Track the number of racers that have already mounted a bike.
iNumOfRacersThatHaveMountedBikes = 0
// Set the state of the Tri racer bikes.
eCurrentTriBikesState = TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_FINISH_SWIM_LEG
ENDPROC
/// PURPOSE:
/// Setup the variables tracking if text messages have printed.
PROC SETUP_TRI_TEXT_TRACKERS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SETUP_TRI_TEXT_TRACKERS] Procedure started.")
// Tutorial hints.
bHasSwimHintPlayed = FALSE
bHasBikeHintPlayed = FALSE
bHasRunHintPlayed = FALSE
bHasTipHintPlayed_0 = FALSE
bHasTipHintPlayed_1 = FALSE
bHasCamHintPlayed = FALSE
ENDPROC
///// PURPOSE:
///// Setup the blip sprites used for each leg transition.
PROC SETUP_TRI_SPRITE_BLIPS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_SPRITE_BLIPS] Procedure started.")
bIsSwimBlipSpriteSet = FALSE
bIsBikeBlipSpriteSet = FALSE
bIsRunBlipSpriteSet = FALSE
ENDPROC
/// PURPOSE:
/// Setup some of the parameters to be used for the player stamina (Intensity and Energy meters).
PROC SETUP_TRI_PLAYER_STAMINA()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_PLAYER_STAMINA] Procedure started.")
iPlayerPreviousSpeedZoneGate = -1
iPlayerPreviousBarricadeGate = -1
// Initialize the stamina state.
ePlayerStaminaResetState = PLAYER_STAMINA_WAIT_FOR_SWIM_BIKE_GATE
// Initialize the player's speed and energy meters.
SETUP_TRI_PLAYER_ENERGY_AND_INTENSITY()
ENDPROC
/// PURPOSE:
/// Setup the parameters that track player changing rank in the race. This is mainly used
/// for determining when to play dialog for player passing or being passed in race.
PROC SETUP_TRI_PLAYER_RANK_TRACKING()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_PLAYER_RANK_TRACKING] Procedure started.")
iPlayerPreviousRank = -1
iPlayerCurrentRank = 1
iPlayerInPlaceRank = 1
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRI_PLAYER_RANK_TRACKING] Set iPlayerPreviousRank to ", iPlayerPreviousRank, ", and iPlayerCurrentRank to ", iPlayerCurrentRank)
ENDPROC
/// PURPOSE:
/// Setup the race competitors, gates, etc.
PROC SETUP_TRI_ENTITIES_BY_TRI_SYSTEM()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SETUP_TRIATHLON] Procedure started.")
TRI_Race_Init(TRI_Race)
SWITCH INT_TO_ENUM(TRIATHLON_RACE_INDEX, TRI_Master.iRaceCur)
CASE TRIATHLON_RACE_ALAMO_SEA
TRI_Setup_Triathlon_traditional_01(TRI_Race)
BREAK
CASE TRIATHLON_RACE_VESPUCCI
TRI_Setup_Triathlon_traditional_02(TRI_Race)
BREAK
CASE TRIATHLON_RACE_IRONMAN
TRI_Setup_Triathlon_traditional_03(TRI_Race)
BREAK
ENDSWITCH
INT iGateCounter
REPEAT TRI_Race.iGateCnt iGateCounter
TRI_Gate_Set_Condition_Flag(TRI_Race.sGate[iGateCounter], TRI_RACE_GATE_FLAG_DO_NOT_SNAP_TO_GROUND)
ENDREPEAT
ENDPROC
//Debug only: If positions need to be adjusted, I have a data driven method using widgets
//PROC UPDATE_NAV_AROUND_TRIATHLON_PROPS()
// INT idx2
// REPEAT COUNT_OF(TRI_Master.iNavBlockAreas) idx2
// IF DOES_NAVMESH_BLOCKING_OBJECT_EXIST(TRI_Master.iNavBlockAreas[idx2])
// UPDATE_NAVMESH_BLOCKING_OBJECT(TRI_Master.iNavBlockAreas[idx2], TRI_Master.vNavBlockPositions[idx2], TRI_Master.vNavBlockScales[idx2], TRI_Master.fNavBlockHeadings[idx2])
// ENDIF
// ENDREPEAT
//ENDPROC
PROC REMOVE_NAV_BLOCKING_OBJECTS()
INT iNavAreaIter
REPEAT COUNT_OF(TRI_Master.iNavBlockAreas) iNavAreaIter
IF DOES_NAVMESH_BLOCKING_OBJECT_EXIST(TRI_Master.iNavBlockAreas[iNavAreaIter])
REMOVE_NAVMESH_BLOCKING_OBJECT(TRI_Master.iNavBlockAreas[iNavAreaIter])
ENDIF
ENDREPEAT
CPRINTLN(DEBUG_TRIATHLON, "REMOVE_NAV_BLOCKING_OBJECTS: Removed all navmesh blocking objects")
ENDPROC
PROC BLOCK_NAV_AROUND_TRIATHLON_PROPS()
//SETUP_NAVMESH_BLOCKING_VALUES(TRI_Master, eCurrentTriRace)
INT idx2
VECTOR vPos, vScale
FLOAT fHeading
REPEAT COUNT_OF(TRI_Master.iNavBlockAreas) idx2
SETUP_NAVMESH_BLOCKING_VALUES_HARDCODED(eCurrentTriRace, idx2, vPos, vScale, fHeading)
IF NOT IS_VECTOR_ZERO(vPos)
TRI_Master.iNavBlockAreas[idx2] = ADD_NAVMESH_BLOCKING_OBJECT(vPos, vScale, fHeading)
ENDIF
ENDREPEAT
CPRINTLN(DEBUG_TRIATHLON, "BLOCK_NAV_AROUND_TRIATHLON_PROPS: Added all navmesh blocking objects")
ENDPROC
/// PURPOSE:
/// Setup Triathlon. This will also be called on player restart, so this is
/// a good place to reset values and states that change over the course of the race.
PROC SETUP_TRIATHLON()
// Ensure the player is in a ready state before he's used in Triathlon.
READY_PLAYER_CHARACTER_FOR_TRIATHLON()
// Setup the race competitors, gates, etc.
SETUP_TRI_ENTITIES_BY_TRI_SYSTEM()
// Setup the parameters that track player changing rank in the race. This is mainly used
// for determining when to play dialog for player passing or being passed in race.
SETUP_TRI_PLAYER_RANK_TRACKING()
// Setup some of the parameters to be used for the player stamina (Intensity and Energy meters).
SETUP_TRI_PLAYER_STAMINA()
// Setup the blip sprites used for each leg transition.
SETUP_TRI_SPRITE_BLIPS()
// Setup the variables tracking if text messages have printed.
SETUP_TRI_TEXT_TRACKERS()
// Setup the variables for setting up and keeping track of racer bikes.
SETUP_TRI_RACER_BIKES()
// Setup the variables tracking if state of cameras used in Triathlon.
SETUP_TRI_CAMERA_TRACKERS()
// Setup Triathlon dialog.
SETUP_TRI_DIALOG()
SWITCH( eCurrentTriRace )
CASE TRIATHLON_RACE_VESPUCCI
IF NOT IS_IPL_ACTIVE("AP1_04_TriAf01")
REQUEST_IPL("AP1_04_TriAf01")
ENDIF
IF NOT IS_IPL_ACTIVE("VB_08_TriAf01")
REQUEST_IPL("VB_08_TriAf01")
ENDIF
BREAK
CASE TRIATHLON_RACE_ALAMO_SEA
IF NOT IS_IPL_ACTIVE("CS2_06_TriAf02")
REQUEST_IPL("CS2_06_TriAf02")
ENDIF
IF NOT IS_IPL_ACTIVE("CS4_08_TriAf02")
REQUEST_IPL("CS4_08_TriAf02")
ENDIF
BREAK
CASE TRIATHLON_RACE_IRONMAN
IF NOT IS_IPL_ACTIVE("CS4_04_TriAf03")
REQUEST_IPL("CS4_04_TriAf03")
ENDIF
IF NOT IS_IPL_ACTIVE("CH1_07_TriAf03")
REQUEST_IPL("CH1_07_TriAf03")
ENDIF
BREAK
ENDSWITCH
BLOCK_NAV_AROUND_TRIATHLON_PROPS()
// Track whether or not speed zones have been set for non-Ironman races.
bAreNonIronSpeedZonesSet = FALSE
ENDPROC
/// PURPOSE:
/// Initialize Triathlon. Use this command only for setting variables
/// and states that won't change during the race. This is called only
/// once while the race is setting up during fade-out, so it won't be
/// called if player restarts race.
///
/// For setting up variables and states that will change over the course
/// of the race, which will generally need to be reset on race restart,
/// use SETUP_TRIATHLON.
PROC INIT_TRIATHLON()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->INIT_TRIATHLON] Procedure started.")
// Initialize the Race Complete scorecard.
TRI_Init_Scorecard(TRI_Race)
// Initialize the animation strings before requesting them.
INIT_TRI_ANIMATION_STRINGS()
// Initialize the TV camera news strings.
INIT_TRI_TV_CAM_NEWS_STRINGS()
// Initialize Triathlon waypoint recordings.
INIT_TRI_WAYPOINT_RECORDINGS()
// Initialize the gates where help text will be played.
INIT_TRI_SET_PRINT_HELP_GATES()
// Initialize where the player will slow down as he approaches the bike->run transition gate.
INIT_TRI_PLAYER_SLOWDOWN_APPROACH_TO_END_OF_BIKE_LEG()
// Initialize the player's gate where racers in superdummy mode in the swim leg can be warped to their bikes to resume race.
INIT_TRI_CHECK_GATE_FOR_WARPING_RACERS_IN_SUPERDUMMY_MODE_IN_SWIM_LEG()
// Initialize the racers last gate destination, so it's way past the final gate position. This decreases
// the chance of racers getting too close to each other as they reach the end of the race.
INIT_TRI_RACERS_LAST_GATE_DESTINATION()
// Initialize Triathlon dialog system.
INIT_TRI_DIALOG()
// Setup Triathlon.
SETUP_TRIATHLON()
ENDPROC
// ===============================================
// E N D TRI SETUP PROCEDURES AND FUNCTIONS
// ===============================================
// ===============================================
// TRI CREATE PROCEDURES AND FUNCTIONS
// ===============================================
/// PURPOSE:
/// Create and place the Triathlon bikes, and assign them to each racer.
PROC CREATE_TRI_BIKES(TRI_RACE_STRUCT& Race, INT iNumberOfBikeClusters = 4)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->CREATE_TRI_BIKES] Started procedure.")
IF (Race.iRacerCnt < iNumberOfBikeClusters)
iNumberOfBikeClusters = Race.iRacerCnt
ENDIF
INT iBikesPerCluster = Race.iRacerCnt / iNumberOfBikeClusters
BOOL bIsNewBikeClusterNeeded = FALSE
// Loop counters.
INT iGateLoopCounter, iRacerLoopCounter, iBikesInClusterCounter
// ------------------
// Offset variables.
// ------------------
FLOAT fOffsetFromPrevBikeInCluster_X = -2.0 // The X component of the offset between bikes in a cluster.
FLOAT fOffsetFromFirstBikeInPrevCluster_Y = 7.0 // The Y component of the offset between clusters.
// Space out the bikes appropriately for each race.
IF eCurrentTriRace = TRIATHLON_RACE_ALAMO_SEA
fOffsetFromPrevBikeInCluster_X = -4.0
fOffsetFromFirstBikeInPrevCluster_Y = 8.0
ELIF eCurrentTriRace = TRIATHLON_RACE_VESPUCCI
fOffsetFromPrevBikeInCluster_X = -2.5
fOffsetFromFirstBikeInPrevCluster_Y = 7.0
ELIF eCurrentTriRace = TRIATHLON_RACE_IRONMAN
fOffsetFromPrevBikeInCluster_X = -4.0
fOffsetFromFirstBikeInPrevCluster_Y = 8.0
ENDIF
// The X component of the offset between the first bike in the cluster, and the center of the checkpoint.
FLOAT fOffsetFromCenter_X = (fOffsetFromPrevBikeInCluster_X * (iBikesPerCluster - 1)) / 2
VECTOR vCurrentBikeSpawnPos // The position of a bike.
VECTOR vFirstBikePos // The first bike's position in a cluster.
VECTOR vOffsetFromPrevBikeInCluster // Offsets bike off of the previous bike in the cluster.
VECTOR vOffsetFromFirstBikeInPrevCluster // Offsets first bike in new cluster off of the first bike in the previous cluster.
// Iterate through the race gates until we find the first bike gate.
REPEAT Race.iGateCnt iGateLoopCounter
// Check if we reached the first bike gate.
IF Race.sGate[iGateLoopCounter].eChkpntType = TRI_CHKPT_TRI_BIKE
// Get the orientation of the bikes using the first bike-gate's and next gate's position, so
// the bikes point towards the next gate.
VECTOR vFwd = Race.sGate[iGateLoopCounter + 1].vPos - Race.sGate[iGateLoopCounter].vPos
FLOAT fBikeHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
// The first bike of the first cluster should start at the checkpoint.
vFirstBikePos = Race.sGate[iGateLoopCounter].vPos
// Set the offsets between bikes based on the race.
IF eCurrentTriRace = TRIATHLON_RACE_ALAMO_SEA
vOffsetFromPrevBikeInCluster = << fOffsetFromPrevBikeInCluster_X, -3.0, 0.0 >>
ELIF eCurrentTriRace = TRIATHLON_RACE_VESPUCCI
vOffsetFromPrevBikeInCluster = << fOffsetFromPrevBikeInCluster_X, -3.0, 0.0 >>
ELIF eCurrentTriRace = TRIATHLON_RACE_IRONMAN
vOffsetFromPrevBikeInCluster = << fOffsetFromPrevBikeInCluster_X, -3.0, 0.0 >>
ENDIF
vOffsetFromFirstBikeInPrevCluster = << 0.0, fOffsetFromFirstBikeInPrevCluster_Y, 0.0 >>
// Use this counter to determine how to place the current bike.
iBikesInClusterCounter = 0
// Iterate through every racer, so we can access their vehicles.
REPEAT Race.iRacerCnt iRacerLoopCounter
// Check if the bike hasn't already been created.
IF NOT DOES_ENTITY_EXIST(Race.Racer[iRacerLoopCounter].Vehicle)
// Check if we need to make a new cluster.
IF bIsNewBikeClusterNeeded
// Determine which index containts the first bike in the previous cluster.
INT nIndexOfFirstBikeInPrevCluster = iRacerLoopCounter - iBikesPerCluster
// Update to a new offset position from the first bike in the previous cluster.
vFirstBikePos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(Race.Racer[nIndexOfFirstBikeInPrevCluster].Vehicle, vOffsetFromFirstBikeInPrevCluster)
// We just created a new cluster, so we don't need another one just yet.
bIsNewBikeClusterNeeded = FALSE
// There aren't any bikes in the new cluster.
iBikesInClusterCounter = 0
ENDIF
// Check if we already created a bike in the cluster.
IF iBikesInClusterCounter > 0
// Get offset from the previous bike to set the new bike's position.
vCurrentBikeSpawnPos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(Race.Racer[iRacerLoopCounter - 1].Vehicle, vOffsetFromPrevBikeInCluster)
// Otherwise, this is our first bike in the cluster, so let's set it to the first position.
ELSE
// Check if this isn't the first bike out of all clusters.
IF iRacerLoopCounter > iBikesInClusterCounter
// No previous bike in the cluster, so set the position of the bike as the first one in the new cluster.
vCurrentBikeSpawnPos = vFirstBikePos
// Otherwise, we need to offset the first bike from the center.
ELSE
// Offset the position of the bike so all the cluster are centered to the checkpoint's position.
vCurrentBikeSpawnPos = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(vFirstBikePos, fBikeHeading, << fOffsetFromCenter_X, 0.0, 0.0 >>)
ENDIF
ENDIF
// Set the Z (up) component of the position vector of the bike to the bike checkpoint's.
vCurrentBikeSpawnPos.z = Race.sGate[iGateLoopCounter].vPos.z
// Choose which bike to use.
MODEL_NAMES RandomTriBikeModelName
INT iRandIndex = GET_RANDOM_INT_IN_RANGE(1, 101)
IF (iRandIndex > 1) AND (iRandIndex < 33)
RandomTriBikeModelName = TRIBIKE
ELIF (iRandIndex > 33) AND (iRandIndex < 66)
RandomTriBikeModelName = TRIBIKE2
ELSE
RandomTriBikeModelName = TRIBIKE3
ENDIF
// Create the bike using the position and orientation we set earlier, and set it to the racer.
Race.Racer[iRacerLoopCounter].Vehicle = CREATE_VEHICLE(RandomTriBikeModelName, vCurrentBikeSpawnPos, fBikeHeading)
SET_VEHICLE_ON_GROUND_PROPERLY(Race.Racer[iRacerLoopCounter].Vehicle)
// SET_VEHICLE_IS_RACING(
// DRIVINGMODE_AVOIDCARS_RECKLESS
// SET_DRIVER_RACING_MODIFIER
// SET_DRIVE_TASK_DRIVING_STYLE(ped, DRIVINGSTYLE_RACING)
// We've created a new bike in the cluster.
iBikesInClusterCounter++
// Check if we've completed a cluster, and create a new one in the next loop iteration.
IF ( (iRacerLoopCounter + 1) % iBikesPerCluster ) = 0
bIsNewBikeClusterNeeded = TRUE
ENDIF
ENDIF // E N D DOES_ENTITY_EXIST(Race.Racer[iRacerLoopCounter].Vehicle)
ENDREPEAT // E N D Race.iRacerCnt iRacerLoopCounter
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->CREATE_TRI_BIKES] Make any position corrections for bike placement.")
// Make any position corrections once all bikes have been created.
REPEAT Race.iRacerCnt iRacerLoopCounter
IF NOT IS_ENTITY_DEAD(Race.Racer[iRacerLoopCounter].Vehicle)
VECTOR vOffsetFromBike_PositiveX
IF eCurrentTriRace = TRIATHLON_RACE_ALAMO_SEA
// Shift bikes to the right, on the road.
vOffsetFromBike_PositiveX = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(Race.Racer[iRacerLoopCounter].Vehicle, << 1.0, 0.0, 0.0 >>)
SET_ENTITY_COORDS(Race.Racer[iRacerLoopCounter].Vehicle, vOffsetFromBike_PositiveX)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->CREATE_TRI_BIKES] Correct bike placement at index ", iRacerLoopCounter)
ELIF eCurrentTriRace = TRIATHLON_RACE_VESPUCCI
ELIF eCurrentTriRace = TRIATHLON_RACE_IRONMAN
// Shift bikes to the right, on the road.
vOffsetFromBike_PositiveX = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(Race.Racer[iRacerLoopCounter].Vehicle, << 3.6, 0.0, 0.0 >>)
SET_ENTITY_COORDS(Race.Racer[iRacerLoopCounter].Vehicle, vOffsetFromBike_PositiveX)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_Helpers.sch->CREATE_TRI_BIKES] Correct bike placement at index ", iRacerLoopCounter)
ENDIF
ENDIF
ENDREPEAT
EXIT // No reason to keep checking gates, as we found the one we needed. Leave this process.
ENDIF
ENDREPEAT
ENDPROC
// Moved this func up to be used in SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS
/// PURPOSE:
/// Update the checkpoints' blip sprites used in the minimap. Currently,
/// there are blip sprites shown at the start of each gate representing the
/// start of a leg.
///
/// Swim Sprite: First gate of race.
/// Bike Sprite: First gate ahead of bikes location.
/// Run Sprite: First gate after player exits bike.
PROC UPDATE_TRI_CHECKPOINT_BLIP_SPRITES()
IF (TRI_Race.Racer[0].iGateCur = 0)
AND (NOT bIsSwimBlipSpriteSet)
bIsSwimBlipSpriteSet = TRUE
ELIF (TRI_Race.Racer[0].iGateCur = Tri_Get_Swim_To_Bike_Transition_Gate() + 2)
AND (NOT bIsBikeBlipSpriteSet)
AND (DOES_BLIP_EXIST(TRI_Race.sGate[TRI_Race.Racer[0].iGateCur].Blip))
AND (IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver))
// SET_BLIP_SPRITE(TRI_Race.sGate[TRI_Race.Racer[0].iGateCur].Blip, RADAR_TRACE_TRIATHLON_CYCLING)
SET_BLIP_COLOUR(TRI_Race.sGate[TRI_Race.Racer[0].iGateCur].Blip, BLIP_COLOUR_YELLOW)
bIsBikeBlipSpriteSet = TRUE
ELIF (TRI_Race.Racer[0].iGateCur = Tri_Get_Bike_To_Run_Transition_Gate() + 1)
AND (NOT bIsRunBlipSpriteSet)
// SET_BLIP_SPRITE(TRI_Race.sGate[TRI_Race.Racer[0].iGateCur].Blip, RADAR_TRACE_TRIATHLON)
SET_BLIP_COLOUR(TRI_Race.sGate[TRI_Race.Racer[0].iGateCur].Blip, BLIP_COLOUR_YELLOW)
bIsRunBlipSpriteSet = TRUE
ENDIF
ENDPROC
/// PURPOSE:
/// Show current and next checkpoints and their blips.
PROC SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(INT iPlayerCurrentGate)
IF NOT IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_CHECKPOINTS)
SET_TRI_CONTROL_FLAG(TCF_SHOW_CHECKPOINTS)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Procedure started.")
// Show player's current checkpoint.
IF iPlayerCurrentGate < TRI_Race.iGateCnt
VECTOR vPlayerPrevGate
IF iPlayerCurrentGate > 0
vPlayerPrevGate = TRI_Race.sGate[iPlayerCurrentGate-1].vPos
ELSE
vPlayerPrevGate = <<0,0,0>>
ENDIF
IF (iPlayerCurrentGate+1) < TRI_Race.iGateCnt
TRI_Chkpnt_Create(vPlayerPrevGate, TRI_Race.sGate[iPlayerCurrentGate], TRI_Race.sGate[iPlayerCurrentGate+1].vPos)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Creating player's current checkpoint #", iPlayerCurrentGate)
ELSE
TRI_Chkpnt_Create(vPlayerPrevGate, TRI_Race.sGate[iPlayerCurrentGate], TRI_Race.sGate[iPlayerCurrentGate].vPos)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Creating player's current checkpoint #", iPlayerCurrentGate, ". LookAt can't point to non-existant checkpoint.")
ENDIF
TRI_Race_Gate_Activate(TRI_Race, iPlayerCurrentGate, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Activating player's current checkpoint #", iPlayerCurrentGate)
// Check if this gate is the first gate after the bikes, so the sprite can be reset if gate is shown again.
IF iPlayerCurrentGate = (Tri_Get_Swim_To_Bike_Transition_Gate()+2)
bIsBikeBlipSpriteSet = FALSE
UPDATE_TRI_CHECKPOINT_BLIP_SPRITES()
ENDIF
// Same check above for run gate
IF iPlayerCurrentGate = (Tri_Get_Bike_To_Run_Transition_Gate()+1)
bIsRunBlipSpriteSet = FALSE
UPDATE_TRI_CHECKPOINT_BLIP_SPRITES()
ENDIF
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] ERROR: Trying to show player's current checkpoint out of bounds at: ", iPlayerCurrentGate)
ENDIF
// Show player's next checkpoint.
IF (iPlayerCurrentGate+1) < TRI_Race.iGateCnt
IF (iPlayerCurrentGate+2) < TRI_Race.iGateCnt
TRI_Chkpnt_Create(TRI_Race.sGate[iPlayerCurrentGate].vPos, TRI_Race.sGate[iPlayerCurrentGate+1], TRI_Race.sGate[iPlayerCurrentGate+2].vPos)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Creating player's current checkpoint #", iPlayerCurrentGate+1)
ELSE
TRI_Chkpnt_Create(TRI_Race.sGate[iPlayerCurrentGate].vPos, TRI_Race.sGate[iPlayerCurrentGate+1], TRI_Race.sGate[iPlayerCurrentGate+1].vPos)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Creating player's current checkpoint #", iPlayerCurrentGate+1, ". LookAt can't point to non-existant checkpoint.")
ENDIF
TRI_Race_Gate_Activate(TRI_Race, iPlayerCurrentGate+1, FALSE)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Activating player's current checkpoint #", iPlayerCurrentGate+1)
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] ERROR: Trying to show player's current checkpoint out of bounds at: ", iPlayerCurrentGate+1)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Hide current and next checkpointS and their blips.
PROC HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(INT iPlayerCurrentGate)
IF IS_TRI_CONTROL_FLAG_SET(TCF_SHOW_CHECKPOINTS)
CLEAR_TRI_CONTROL_FLAG(TCF_SHOW_CHECKPOINTS)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS] Procedure started.")
// Hide player's current checkpoint.
IF iPlayerCurrentGate < TRI_Race.iGateCnt
TRI_Chkpnt_Destroy(TRI_Race.sGate[iPlayerCurrentGate].Chkpnt)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] Hiding player's current checkpoint #", iPlayerCurrentGate)
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] ERROR: Trying to hide player's current checkpoint out of bounds at: ", iPlayerCurrentGate)
ENDIF
// Hide player's next checkpoint.
IF (iPlayerCurrentGate+1) < TRI_Race.iGateCnt
TRI_Chkpnt_Destroy(TRI_Race.sGate[iPlayerCurrentGate+1].Chkpnt)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] Hiding player's next checkpoint #", iPlayerCurrentGate+1)
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] ERROR: Trying to hide player's next checkpoint out of bounds at: ", iPlayerCurrentGate+1)
ENDIF
// Hide player's current checkpoint's blip.
IF DOES_BLIP_EXIST(TRI_Race.sGate[iPlayerCurrentGate].Blip)
IF iPlayerCurrentGate < TRI_Race.iGateCnt
SET_BLIP_DISPLAY(TRI_Race.sGate[iPlayerCurrentGate].Blip, DISPLAY_NOTHING)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] Hiding player's current checkpoint blip #", iPlayerCurrentGate)
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] ERROR: Trying to hide player's current checkpoint blip out of bounds at: ", iPlayerCurrentGate)
ENDIF
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] ERROR: Trying to hide player's current checkpoint blip that does not exist.")
ENDIF
// Hide player's next checkpoint's blip.
IF DOES_BLIP_EXIST(TRI_Race.sGate[iPlayerCurrentGate+1].Blip)
IF (iPlayerCurrentGate+1) < TRI_Race.iGateCnt
SET_BLIP_DISPLAY(TRI_Race.sGate[iPlayerCurrentGate+1].Blip, DISPLAY_NOTHING)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] Hiding player's next checkpoint blip #", iPlayerCurrentGate+1)
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] ERROR: Trying to hide player's next checkpoint blip out of bounds at: ", iPlayerCurrentGate+1)
ENDIF
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINT] ERROR: Trying to hide player's next checkpoint blip that does not exist.")
ENDIF
ENDIF
ENDPROC
// ===============================================
// E N D TRI CREATE PROCEDURES AND FUNCTIONS
// ===============================================
// ===============================================
// TRI UPDATE PROCEDURES AND FUNCTIONS
// ===============================================
/// PURPOSE:
/// Update each racer's bike status.
PROC UPDATE_TRI_RACER_BIKES()
// Updates whether or not a bike has been mounted by a racer.
UPDATE_TRIBIKE_MOUNTING_STATUS(TRI_Race)
// Update the player's bike speed.
UPDATE_TRI_PLAYER_BIKE_SPEED(TRI_Race, Tri_Racer_AI_Speed.fDefaultTribikeTopSpeedOnFlatSurface)
SWITCH (eCurrentTriBikesState)
// Wait until player finishes the swim leg before dealing with the bikes.
CASE TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_FINISH_SWIM_LEG
IF Tri_Get_Racer_Current_Race_Leg(TRI_Race, TRI_Race.Racer[0]) = TRI_TRI_RACE_LEG_BIKE
eCurrentTriBikesState = TRI_BIKES_STATE_CREATE_BIKES_RADAR_BLIP
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_FINISH_SWIM_LEG to TRI_BIKES_STATE_CREATE_BIKES_RADAR_BLIP")
ENDIF
BREAK
// Create the bike blips and tell player to get on a bike.
CASE TRI_BIKES_STATE_CREATE_BIKES_RADAR_BLIP
// Create the radar blip for the bikes.
CREATE_TRI_BIKES_EDGE_RADAR_BLIP(TRI_Race)
// Print god text: "Get on a bicycle."
PRINT_NOW("SPR_OBJ_BIKE2", DEFAULT_GOD_TEXT_TIME, 0)
// Hide current and next checkpoints and their blips.
HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(TRI_Race.Racer[0].iGateCur)
eCurrentTriBikesState = TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_GET_ON_BIKE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_CREATE_BIKES_RADAR_BLIP to TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_GET_ON_BIKE")
BREAK
// Wait until player gets on a bike.
CASE TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_GET_ON_BIKE
IF IS_TRI_RACER_GETTING_ON_OR_IS_HE_ALREADY_ON_A_TRIBIKE(TRI_Race, 0, TRUE)
eCurrentTriBikesState = TRI_BIKES_STATE_PLAYER_GOT_ON_BIKE_FOR_FIRST_TIME
START_AUDIO_SCENE("TRI_BIKE_SCENE")
STOP_AUDIO_SCENE("TRI_SWIM_SCENE")
// INT iPropIndex
// enumCharacterList ePed
// ePed = GET_CURRENT_PLAYER_PED_ENUM()
// IF ePed = CHAR_MICHAEL
// iPropIndex = 7
// ELIF ePed = CHAR_FRANKLIN
// iPropIndex = 2
// ELIF ePed = CHAR_TREVOR
// iPropIndex = 9
// ENDIF
// SET_PED_PROP_INDEX(PLAYER_PED_ID(), ANCHOR_HEAD, iPropIndex)
// GIVE_PED_HELMET(PLAYER_PED_ID()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_GET_ON_BIKE to TRI_BIKES_STATE_PLAYER_GOT_ON_BIKE_FOR_FIRST_TIME")
ENDIF
BREAK
// Player gets on bike for the first time.
CASE TRI_BIKES_STATE_PLAYER_GOT_ON_BIKE_FOR_FIRST_TIME
IF DOES_BLIP_EXIST(blipBikes)
REMOVE_BLIP(blipBikes)
ENDIF
IF DOES_BLIP_EXIST(blipBikesEdge)
REMOVE_BLIP(blipBikesEdge)
ENDIF
// Update the player's current and next checkpoints to be the one after the invisible checkpoint over the bikes.
IF (TRI_Race.Racer[0].iGateCur = Tri_Get_Swim_To_Bike_Transition_Gate() + 1)
TRI_Race.Racer[0].iGateCur = Tri_Get_Swim_To_Bike_Transition_Gate() + 2
ENDIF
// Show current and next checkpoints and their blips.
SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(TRI_Race.Racer[0].iGateCur)
// Checks if an AI has taken the player's intended bike, or vice versa.
// Swaps the assigned vehicles if either of these cases is true.
UPDATE_TRI_RACER_VEHICLE_ASSIGNMENT(TRI_Race, GET_VEHICLE_PED_IS_USING(GET_PLAYER_PED(GET_PLAYER_INDEX())))
SET_VEHICLE_HAS_STRONG_AXLES(GET_VEHICLE_PED_IS_USING(GET_PLAYER_PED(GET_PLAYER_INDEX())), TRUE)
// Ensure the player can only get on his chosen bike.
SET_TRI_PLAYER_CAN_ONLY_RIDE_BIKE_HE_IS_ON(TRI_Race)
// Now that the player has chosen his bike, we can safely set the other racers' bike skill levels.
SET_TRI_RACERS_SKILL_LEVEL_IN_BIKE_LEG(TRI_Race)
// Play the music for getting on a tribike
TRIGGER_MUSIC_EVENT("MGTR_ON_BIKE")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] MGTR_ON_BIKE music triggered")
eCurrentTriBikesState = TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_PLAYER_GOT_ON_BIKE_FOR_FIRST_TIME to TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE")
BREAK
// Wait for player to exit bike again.
CASE TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE
IF (Tri_Get_Racer_Current_Race_Leg(TRI_Race, TRI_Race.Racer[0]) = TRI_TRI_RACE_LEG_RUN)
eCurrentTriBikesState = TRI_BIKES_STATE_PLAYER_FINISHED_BIKE_LEG
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE to TRI_BIKES_STATE_PLAYER_FINISHED_BIKE_LEG")
// Play the music for getting off a tribike
TRIGGER_MUSIC_EVENT("MGTR_ON_FOOT")
START_AUDIO_SCENE("TRI_RUN_SCENE")
STOP_AUDIO_SCENE("TRI_BIKE_SCENE")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] MGTR_ON_FOOT music triggered")
ENDIF
IF NOT IS_TRI_RACER_GETTING_ON_OR_IS_HE_ALREADY_ON_A_TRIBIKE(TRI_Race, 0)
eCurrentTriBikesState = TRI_BIKES_STATE_PLAYER_GOT_OFF_BIKE_IN_BIKE_LEG
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_PLAYER_WAIT_FOR_PLAYER_TO_EXIT_BIKE to TRI_BIKES_STATE_PLAYER_GOT_OFF_BIKE_IN_BIKE_LEG")
ENDIF
BREAK
// Player got off bike while still in the bike leg.
CASE TRI_BIKES_STATE_PLAYER_GOT_OFF_BIKE_IN_BIKE_LEG
// Hide current and next checkpoints and their blips.
HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(TRI_Race.Racer[0].iGateCur)
// Show player bike blip.
CREATE_PLAYER_TRI_BIKE_BLIP(TRI_Race)
// Print god text once in race: "Get on your bicycle."
PRINT_NOW_ONCE("SPR_OBJ_BIKE1", DEFAULT_GOD_TEXT_TIME, 0, TRI_HELP_BIT, TRI_DAMG_HELP)
eCurrentTriBikesState = TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_RETURN_TO_BIKE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_PLAYER_GOT_OFF_BIKE_IN_BIKE_LEG to TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_RETURN_TO_BIKE")
BREAK
// Wait for player to return to his bike.
CASE TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_RETURN_TO_BIKE
IF IS_TRI_RACER_GETTING_ON_OR_IS_HE_ALREADY_ON_A_TRIBIKE(TRI_Race, 0, FALSE)
eCurrentTriBikesState = TRI_BIKES_STATE_PLAYER_IS_BACK_ON_BIKE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_RETURN_TO_BIKE to TRI_BIKES_STATE_PLAYER_IS_BACK_ON_BIKE")
ENDIF
BREAK
// Remove player's bike blip, and show checkpoints and their blips.
CASE TRI_BIKES_STATE_PLAYER_IS_BACK_ON_BIKE
IF IS_THIS_PRINT_BEING_DISPLAYED("SPR_OBJ_BIKE1")
CLEAR_THIS_PRINT("SPR_OBJ_BIKE1")
ENDIF
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
ENDIF
// Show current and next checkpoints and their blips.
SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(TRI_Race.Racer[0].iGateCur)
eCurrentTriBikesState = TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_PLAYER_IS_BACK_ON_BIKE to TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_EXIT_BIKE")
BREAK
// Player has reached the end of the bike leg, so get him off the bike.
CASE TRI_BIKES_STATE_PLAYER_FINISHED_BIKE_LEG
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Vehicle)
BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(TRI_Race.Racer[0].Vehicle, 2.5)
eCurrentTriBikesState = TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_BE_FORCED_TO_LEAVE_BIKE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_PLAYER_FINISHED_BIKE_LEG to TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_BE_FORCED_TO_LEAVE_BIKE")
ENDIF
BREAK
// Force player to leave the bike to continue the race on foot.
CASE TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_BE_FORCED_TO_LEAVE_BIKE
IF IS_TRI_AI_RACER_OR_PLAYER_VALID(TRI_Race, 0, TRUE)
IF GET_ENTITY_SPEED(TRI_Race.Racer[0].Vehicle) < 4.0
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
// Print god text once in race: "Run to the checkpoint to continue the race."
PRINT_NOW_ONCE("TRI_OBJ_RUN", DEFAULT_GOD_TEXT_TIME, 0, TRI_HELP_BIT, TRI_DAMG_HELP)
eCurrentTriBikesState = TRI_BIKES_STATE_DONE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_RACER_BIKES_NEW] From TRI_BIKES_STATE_WAIT_FOR_PLAYER_TO_BE_FORCED_TO_LEAVE_BIKE to TRI_BIKES_STATE_DONE")
ENDIF
ENDIF
BREAK
CASE TRI_BIKES_STATE_DONE
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
CPRINTLN(DEBUG_TRIATHLON, "CASE TRI_BIKES_STATE_DONE :: REMOVE_BLIP(blipPlayerVehicle)")
ENDIF
BREAK
ENDSWITCH
ENDPROC
PROC UPDATE_TRI_HIDE_BLIPS_WHEN_IN_VEHICLES()
IF Tri_Get_Racer_Current_Race_Leg(TRI_Race, TRI_Race.Racer[0]) <> TRI_TRI_RACE_LEG_BIKE
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF IS_TRI_RACER_GETTING_ON_OR_IS_HE_ALREADY_ON_A_TRIBIKE(TRI_Race, 0)
HIDE_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(TRI_Race.Racer[0].iGateCur)
ELIF IS_TRI_RACER_GETTING_ON_OR_IS_HE_ALREADY_ON_A_TRIBIKE(TRI_Race, 0)
IF fOnTribikeTimer > ON_TRIBIKE_THRESHOLD
SET_TRI_CONTROL_FLAG(TCF_CAN_FORFEIT_ON_TRIBIKE)
ELSE
fOnTribikeTimer += GET_FRAME_TIME()
ENDIF
ENDIF
ELSE
SHOW_TRI_CURRENT_AND_NEXT_PLAYER_CHECKPOINTS(TRI_Race.Racer[0].iGateCur)
ENDIF
ENDIF
ENDPROC
PROC UPDATE_TRI_CHASE_HELI()
BOOL bNeedNewHeli = FALSE
BOOL bDeleteOldHeli = FALSE
IF IS_PED_INJURED(pedPilot)
CPRINTLN(DEBUG_TRIATHLON, "We need a new Heli :: IS_PED_INJURED(pedPilot)")
bNeedNewHeli = TRUE
ENDIF
IF NOT DOES_ENTITY_EXIST(vehChopper)
CPRINTLN(DEBUG_TRIATHLON, "We need a new Heli :: NOT DOES_ENTITY_EXIST(vehChopper)")
bNeedNewHeli = TRUE
ENDIF
IF NOT IS_VEHICLE_DRIVEABLE(vehChopper)
CPRINTLN(DEBUG_TRIATHLON, "We need a new Heli :: NOT IS_VEHICLE_DRIVEABLE(vehChopper)")
bNeedNewHeli = TRUE
bDeleteOldHeli = TRUE
ENDIF
IF IS_ENTITY_ON_FIRE(vehChopper)
CPRINTLN(DEBUG_TRIATHLON, "We need a new Heli :: IS_ENTITY_ON_FIRE(vehChopper)")
bNeedNewHeli = TRUE
bDeleteOldHeli = TRUE
ENDIF
IF IS_ENTITY_DEAD(vehChopper)
CPRINTLN(DEBUG_TRIATHLON, "We need a new Heli :: IS_ENTITY_DEAD(vehChopper)")
bNeedNewHeli = TRUE
bDeleteOldHeli = TRUE
ENDIF
IF GET_VEHICLE_ENGINE_HEALTH(vehChopper) <= 500
CPRINTLN(DEBUG_TRIATHLON, "We need a new Heli :: GET_VEHICLE_ENGINE_HEALTH(vehChopper) <= 500")
bNeedNewHeli = TRUE
ENDIF
IF bNeedNewHeli #IF IS_DEBUG_BUILD OR DESTROY_NEWS_CHOPPER
DESTROY_NEWS_CHOPPER = FALSE
#ENDIF
// Get rid of old cam and heli
SET_VEHICLE_AS_NO_LONGER_NEEDED(vehChopper)
SET_PED_AS_NO_LONGER_NEEDED(pedPilot)
IF bDeleteOldHeli
DELETE_VEHICLE(vehChopper)
DELETE_PED(pedPilot)
CPRINTLN(DEBUG_TRIATHLON, "Deleted Heli")
ENDIF
IF DOES_CAM_EXIST(camTV_Top_Medium)
DESTROY_CAM(camTV_Top_Medium)
ENDIF
IF NOT IS_TRI_CONTROL_FLAG_SET(TCF_NEWS_CAST_INTERRUPTED)
SET_TRI_CONTROL_FLAG(TCF_NEWS_CAST_INTERRUPTED)
TRI_Race.iNewsInterruptStamp = GET_GAME_TIMER() + NEWS_CAM_INTERRUPT_DURATION
SHOW_TRI_NEWS_CAM_STATIC(TRUE)
ENDIF
// Get us a new cam and heli
SETUP_TRI_CHASE_HELI(eCurrentTriRace, FALSE)
CREATE_TRI_TV_NEWS_CAM(vehChopper)
ENDIF
ENDPROC
/// PURPOSE:
/// Disables undesired controls during the race
/// -INPUT_VEH_CIN_CAM
/// -INPUT_SELECT_WEAPON
/// -INPUT_WEAPON_WHEEL_UD
/// -INPUT_WEAPON_WHEEL_LR
/// -INPUT_WEAPON_WHEEL_NEXT
/// -INPUT_WEAPON_WHEEL_PREV
/// -INPUT_SELECT_NEXT_WEAPON
/// -INPUT_SELECT_PREV_WEAPON
PROC UPDATE_TRI_DISABLED_CONTROLS()
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_CIN_CAM)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_WEAPON_WHEEL_UD)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_WEAPON_WHEEL_LR)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_WEAPON_WHEEL_NEXT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_WEAPON_WHEEL_PREV)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_NEXT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_PREV_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_NEXT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_PREV_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_AIM)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK2)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_WHEEL)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_AREA_NAME)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_DISTRICT_NAME)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_STREET_NAME)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_VEHICLE_NAME)
// IF IS_TRI_CONTROL_FLAG_SET(TCF_NEWS_CAM_ACTIVE)
// CDEBUG2LN(DEBUG_TRIATHLON, "DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_DIVE)")
// DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_DIVE)
// ENDIF
SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_EnablePressAndReleaseDives, TRUE)
ENDPROC
PROC UPDATE_TRI_RUNNER_OFFSETS(TRI_RACE_STRUCT &thisRace)
INT p=1
WHILE p < 8
IF Tri_Get_Racer_Current_Race_Leg(thisRace, thisRace.Racer[p]) = TRI_TRI_RACE_LEG_RUN
IF GET_SCRIPT_TASK_STATUS(thisRace.Racer[p].Driver, SCRIPT_TASK_FOLLOW_WAYPOINT_ROUTE) = PERFORMING_TASK
FLOAT fAlpha = p/8.0
VECTOR vOffset = LERP_VECTOR((<<3,3,0>>), (<<-3,-3,0>>), fAlpha)
SET_PED_WAYPOINT_ROUTE_OFFSET(thisRace.Racer[p].Driver, vOffset)
// CPRINTLN(DEBUG_TRIATHLON, "UPDATE_TRI_RUNNER_OFFSETS :: p=", p, ", vOffset=", vOffset)
ENDIF
ENDIF
p++
ENDWHILE
ENDPROC
PROC UPDATE_QUIT_TRIATHLON()
//Save player vehicle if he doesn't quit
IF NOT IS_BITMASK_AS_ENUM_SET(iSPRGeneralBits, TRI_PLAYER_VEHICLE_SAVED)
STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE()
SET_BITMASK_AS_ENUM(iSPRGeneralBits, TRI_PLAYER_VEHICLE_SAVED)
ENDIF
IF NOT IS_TRI_CONTROL_FLAG_SET(TCF_TOLD_HOW_TO_QUIT)
PRINT_HELP("TRI_Q_PROMPT")
SET_TRI_CONTROL_FLAG(TCF_TOLD_HOW_TO_QUIT)
ENDIF
IF IS_TRI_CONTROL_FLAG_SET(TCF_QUITTING_RACE) AND IS_SCREEN_FADED_OUT() AND NOT IS_SCREEN_FADING_OUT()
DELETE_ALL_TRI_RACERS(Tri_Race)
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
WHILE NOT HAVE_ALL_STREAMING_REQUESTS_COMPLETED(PLAYER_PED_ID())
CDEBUG2LN(DEBUG_TRIATHLON, "Waiting on Player outfit to load back in")
WAIT(0)
ENDWHILE
CLEANUP_ALL_AND_TERMINATE_TRIATHLON(Tri_Race, FALSE)
ELSE
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_CONTEXT) OR IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_CONTEXT)
SET_TRI_CONTROL_FLAG(TCF_QUIT_SCREEN_ON)
SET_WARNING_MESSAGE_WITH_HEADER("TRI_QUIT_TITLE", "TRI_QUIT_Q", FE_WARNING_NO | FE_WARNING_YES)
SET_GAME_PAUSED(TRUE)
PLAY_SOUND_FRONTEND(-1, "QUIT", "HUD_FRONTEND_DEFAULT_SOUNDSET")
TRI_SET_BLOCK_QUIT_INPUT_TIMER( Tri_Race )
ENDIF
IF IS_TRI_CONTROL_FLAG_SET(TCF_QUIT_SCREEN_ON)
SET_WARNING_MESSAGE_WITH_HEADER("TRI_QUIT_TITLE", "TRI_QUIT_Q", FE_WARNING_NO | FE_WARNING_YES)
TRI_UPDATE_BLOCK_QUIT_INPUT_TIMER( Tri_Race )
IF GET_GAME_TIMER() > TRI_GET_BLOCK_QUIT_INPUT_TIMER( Tri_Race )
AND (IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) OR IS_DISABLED_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT))
SET_GAME_PAUSED(FALSE)
DO_SCREEN_FADE_OUT(0)
CLEAR_TRI_CONTROL_FLAG(TCF_QUIT_SCREEN_ON)
SET_TRI_CONTROL_FLAG(TCF_QUITTING_RACE)
// PLAY_SOUND_FRONTEND(-1, "YES", "HUD_FRONTEND_DEFAULT_SOUNDSET")
ELIF IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) OR IS_DISABLED_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
SET_GAME_PAUSED(FALSE)
CLEAR_TRI_CONTROL_FLAG(TCF_QUIT_SCREEN_ON)
// PLAY_SOUND_FRONTEND(-1, "NO", "HUD_FRONTEND_DEFAULT_SOUNDSET")
ENDIF
ENDIF
ENDIF
ENDPROC
INT iFrameCount
/// PURPOSE:
/// Update Triathlon from start to end of the race every frame.
PROC UPDATE_TRIATHLON_DURING_RACE(INT &iMusicFlags)
//
//Low prioity updates
//
IF iFrameCount = 0
// Update the Tri news heli, spawn a new one if it crashes
UPDATE_TRI_CHASE_HELI()
// Update the checkpoint based musical cues
UPDATE_TRI_MUSIC_CHECKPOINT_CUES(TRI_Race, iMusicFlags)
ELIF iFrameCount = 1
// Update when the player's energy is replenished.
UPDATE_TRI_PLAYER_ENERGY_REPLENISHMENT(TRI_Race)
// Update the player's speed and energy meters.
UPDATE_PLAYER_TRI_INTENSITY_AND_ENERGY()
ELIF iFrameCount = 2
// Ensure all the racers are in the right vehicles, warnings are given for getting off the bike, etc.
UPDATE_TRI_RACER_BIKES()
// Update which barricades are active based on player location in race, and only when the player's current gate changes.
UPDATE_TRI_RACE_ROAD_BARRICADES(TRI_Race)
//Set the AI's helmets to load when they are reaching the end of the swimming section
UPDATE_TRI_AI_BIKE_HELMETS(TRI_Race)
ELIF iFrameCount = 3
// Update when dialog should be played.
UPDATE_TRI_DIALOG(TRI_Race)
// Keep checking when to display help text.
UPDATE_PRINT_HELP_TEXT(TRI_Race)
UPDATE_TRI_RUNNER_OFFSETS(TRI_Race)
ELIF iFrameCount = 4
// Update the playerPed to look at other biking racers
UPDATE_TRI_PLAYER_GLARING_AT_OTHER_RACERS(TRI_Race)
// Cleanup the swim cap and goggles when we can't see the player's face.
UPDATE_TRI_PLAYER_CAP_AND_GOGGLES(TRI_Race)
// Update the cheering from scenario peds
UPDATE_TRI_CHEERING_PEDS(TRI_Race)
// Load in outro sync scenes when appropriate
UPDATE_TRI_OUTRO_ASSETS(TRI_Race, sOutroSceneData)
ENDIF
UPDATE_TRI_CHECKPOINT_BLIP_SPRITES()
IF iFrameCount >= 4
iFrameCount = 0
ELSE
iFrameCount++
ENDIF
//
//High prioirty updates.
//
UPDATE_TRI_SCENARIO_GROUP()
// Update racers' AI.
UPDATE_TRI_AI(TRI_Race)
// Update the TV news camera based on player input.
UPDATE_TRI_TV_NEWS_CAM_PLAYER_INPUT(TRI_Race)
// Update the quit Flow
UPDATE_QUIT_TRIATHLON()
// Stop cheaters from seeing checkpoints while in a car.
UPDATE_TRI_HIDE_BLIPS_WHEN_IN_VEHICLES()
//
//Not expensive
//
// Start timer to allow event dialog to play only after player has entered the water.
IF (TRI_Race.Racer[0].iGateCur = 1)
IF NOT IS_TIMER_STARTED(timerPlayerDialogCanPlay)
START_TIMER_AT(timerPlayerDialogCanPlay, TriDialog.fSecondsBeforeDialogSystemStarts)
ENDIF
ELIF TRI_Race.Racer[0].iGateCur < 1 AND eCurrentTriRace = TRIATHLON_RACE_IRONMAN
REQUEST_COLLISION_AT_COORD(<<1560.9357, 3848.8979, 28.2339>>)
CPRINTLN(DEBUG_TRIATHLON, "REQUEST_COLLISION_AT_COORD(<<1560.9357, 3848.8979, 28.2339>>)")
ENDIF
ENDPROC
// ===============================================
// E N D TRI UPDATE PROCEDURES AND FUNCTIONS
// ===============================================
#IF IS_DEBUG_BUILD
// ===============================================
// TRI DEBUG FUNCTIONS AND PROCEDURES
// ===============================================
/// PURPOSE
/// Warps all racers to next leg, or next set of gates.
PROC SET_TRI_MENU_STAGE()
//skipMenuStruct[0].sTxtLabel = "FIRST GATE" // Stage 0 Name
skipMenuStruct[0].sTxtLabel = "LAST SWIM GATE" // Stage 1 Name
skipMenuStruct[1].sTxtLabel = "LAST BIKE GATE" // Stage 2 Name
skipMenuStruct[2].sTxtLabel = "LAST RUN GATE" // Stage 3 Name
//skipMenuStruct[4].sTxtLabel = "FIRST GATE W/ AI" // Stage 4 Name
skipMenuStruct[3].sTxtLabel = "LAST SWIM GATE W/ AI" // Stage 4 Name
skipMenuStruct[4].sTxtLabel = "LAST BIKE GATE W/ AI" // Stage 5 Name
skipMenuStruct[5].sTxtLabel = "LAST RUN GATE W/ AI" // Stage 6 Name
ENDPROC
/// PURPOSE
/// Resets the state of the race when debug warping is used.
PROC RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE eDebugTriRaceState)
SWITCH eDebugTriRaceState
CASE DEBUG_TRI_RACE_STATE_FIRST_GATE
bIsSwimBlipSpriteSet = FALSE
bIsBikeBlipSpriteSet = FALSE
bIsRunBlipSpriteSet = FALSE
bHasSwimHintPlayed = FALSE
bHasBikeHintPlayed = FALSE
bHasRunHintPlayed = FALSE
bHasTipHintPlayed_0 = FALSE
bHasTipHintPlayed_1 = FALSE
bHasCamHintPlayed = FALSE
CLEAR_TRI_CONTROL_FLAG(TCF_TRI_MOUNTED)
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
ENDIF
IF DOES_BLIP_EXIST(blipBikes)
REMOVE_BLIP(blipBikes)
ENDIF
BREAK
CASE DEBUG_TRI_RACE_STATE_LAST_SWIM_GATE
bIsSwimBlipSpriteSet = TRUE
bIsBikeBlipSpriteSet = FALSE
bIsRunBlipSpriteSet = FALSE
bHasSwimHintPlayed = TRUE
bHasBikeHintPlayed = FALSE
bHasRunHintPlayed = FALSE
bHasTipHintPlayed_0 = TRUE
bHasTipHintPlayed_1 = TRUE
bHasCamHintPlayed = TRUE
CLEAR_TRI_CONTROL_FLAG(TCF_TRI_MOUNTED)
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
ENDIF
BREAK
CASE DEBUG_TRI_RACE_STATE_LAST_BIKE_GATE
bIsSwimBlipSpriteSet = TRUE
bIsBikeBlipSpriteSet = TRUE
bIsRunBlipSpriteSet = FALSE
bHasSwimHintPlayed = TRUE
bHasBikeHintPlayed = TRUE
bHasRunHintPlayed = FALSE
bHasTipHintPlayed_0 = TRUE
bHasTipHintPlayed_1 = TRUE
bHasCamHintPlayed = TRUE
SET_TRI_CONTROL_FLAG(TCF_TRI_MOUNTED)
BREAK
CASE DEBUG_TRI_RACE_STATE_LAST_RUN_GATE
bIsSwimBlipSpriteSet = TRUE
bIsBikeBlipSpriteSet = TRUE
bIsRunBlipSpriteSet = TRUE
bHasSwimHintPlayed = TRUE
bHasBikeHintPlayed = TRUE
bHasRunHintPlayed = TRUE
bHasTipHintPlayed_0 = TRUE
bHasTipHintPlayed_1 = TRUE
bHasCamHintPlayed = TRUE
CLEAR_TRI_CONTROL_FLAG(TCF_TRI_MOUNTED)
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
ENDIF
BREAK
CASE DEBUG_TRI_RACE_STATE_END
bIsSwimBlipSpriteSet = TRUE
bIsBikeBlipSpriteSet = TRUE
bIsRunBlipSpriteSet = TRUE
bHasSwimHintPlayed = TRUE
bHasBikeHintPlayed = TRUE
bHasRunHintPlayed = TRUE
bHasTipHintPlayed_0 = TRUE
bHasTipHintPlayed_1 = TRUE
bHasCamHintPlayed = TRUE
CLEAR_TRI_CONTROL_FLAG(TCF_TRI_MOUNTED)
IF DOES_BLIP_EXIST(blipPlayerVehicle)
REMOVE_BLIP(blipPlayerVehicle)
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// If using debug warp, deactivate all gates not meant to be active.
PROC DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(INT iCurrentGate, INT iNextGate)
INT iGateCounter
REPEAT TRI_Race.iGateCnt iGateCounter
IF (iGateCounter <> iCurrentGate) OR (iGateCounter <> iNextGate)
TRI_Chkpnt_Destroy(TRI_Race.sGate[iGateCounter].Chkpnt)
IF DOES_BLIP_EXIST(TRI_Race.sGate[iGateCounter].Blip)
SET_BLIP_DISPLAY(TRI_Race.sGate[iGateCounter].Blip, DISPLAY_NOTHING)
ENDIF
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// It warps a racer to a gate without warping on top of another racer.
/// Meant to be called when warping every racer at the same time to one location.
PROC WARP_RACER_OFFSET_FROM_GATE(INT iRacerIndex, INT iGateToOffsetWarpFrom, FLOAT fRacerHeading, BOOL bWarpWithVehicle)
CPRINTLN(DEBUG_TRIATHLON, "WARP_RACER_OFFSET_FROM_GATE iRacerIndex=", iRacerIndex)
VECTOR vWarpRacerHere
// Offset the racer's destination position before warping.
SWITCH iRacerIndex
CASE 0
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << -4.0, 0.0, 0.0 >>)
BREAK
CASE 1
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << -3.0, -1.0, 0.0 >>)
BREAK
CASE 2
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << -2.0, 0.0, 0.0 >>)
BREAK
CASE 3
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << -1.0, -1.0, 0.0 >>)
BREAK
CASE 4
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << 0.0, 0.0, 0.0 >>)
BREAK
CASE 5
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << 1.0, -1.0, 0.0 >>)
BREAK
CASE 6
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << 2.0, 0.0, 0.0 >>)
BREAK
CASE 7
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << 3.0, 1.0, 0.0 >>)
BREAK
DEFAULT
vWarpRacerHere = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iGateToOffsetWarpFrom].vPos, fRacerHeading, << 4.0, 0.0, 0.0 >>)
BREAK
ENDSWITCH
TEXT_LABEL_23 texWarp = "Warp"
texWarp += iRacerIndex
texWarp += "toGate"
texWarp += iGateToOffsetWarpFrom
DEBUG_RECORD_SPHERE(texWarp, vWarpRacerHere, 1.0, (<<255,0,0>>))
// Warp the racer to destination.
IF NOT bWarpWithVehicle
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Driver)
IF TRI_Master.iRaceCur <> ENUM_TO_INT(TRIATHLON_RACE_IRONMAN)
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver, vWarpRacerHere, TRUE)
ELSE
vWarpRacerHere = << vWarpRacerHere.x, vWarpRacerHere.y, vWarpRacerHere.z + 1.0 >>
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver, vWarpRacerHere, TRUE)
ENDIF
ENDIF
ELSE
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Driver)
vWarpRacerHere = << vWarpRacerHere.x, vWarpRacerHere.y, vWarpRacerHere.z + 0.5 >>
SET_PED_COORDS_KEEP_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, vWarpRacerHere)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Vehicle)
SET_VEHICLE_ON_GROUND_PROPERLY(TRI_Race.Racer[iRacerIndex].Vehicle)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Warp player to current gate.
PROC WARP_PLAYER_TO_CURRENT_GATE()
INT iPlayerCurrentGate = TRI_Race.Racer[0].iGateCur
VECTOR vFwd = TRI_Race.sGate[iPlayerCurrentGate+1].vPos - TRI_Race.sGate[iPlayerCurrentGate].vPos
FLOAT fBikeHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF (Tri_Get_Racer_Current_Race_Leg(TRI_Race, TRI_Race.Racer[0]) <> TRI_TRI_RACE_LEG_BIKE)
AND (TRI_Race.Racer[0].iGateCur <> (Tri_Get_Swim_To_Bike_Transition_Gate()+1))
SET_ENTITY_COORDS(TRI_Race.Racer[0].Driver, TRI_Race.sGate[iPlayerCurrentGate].vPos, TRUE)
SET_ENTITY_HEADING(TRI_Race.Racer[0].Driver, fBikeHeading)
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ELSE
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Vehicle)
IF NOT ( IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver) )
SET_PED_INTO_VEHICLE(TRI_Race.Racer[0].Driver, TRI_Race.Racer[0].Vehicle)
ENDIF
VECTOR vWarpRacerHere = << TRI_Race.sGate[iPlayerCurrentGate].vPos.x, TRI_Race.sGate[iPlayerCurrentGate].vPos.y, TRI_Race.sGate[iPlayerCurrentGate].vPos.z + 0.5 >>
SET_PED_COORDS_KEEP_VEHICLE(TRI_Race.Racer[0].Driver, vWarpRacerHere)
SET_ENTITY_HEADING(TRI_Race.Racer[0].Vehicle, fBikeHeading)
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ENDIF
ENDIF
ENDIF
TRI_Race_Gate_Activate(TRI_Race, iPlayerCurrentGate, TRUE)
TRI_Race.Racer[0].iGateCur = iPlayerCurrentGate
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iPlayerCurrentGate, iPlayerCurrentGate+1)
ENDPROC
/// PURPOSE:
/// Warp player to the first gate.
PROC WARP_PLAYER_TO_FIRST_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_FIRST_GATE)
// Activating new current gate.
CPRINTLN(DEBUG_TRIATHLON, "Before creating checkpoint.")
//TRI_Race_Gate_Activate(TRI_Race, 1, TRUE)
CPRINTLN(DEBUG_TRIATHLON, "After creating checkpoint.")
TRI_Race.Racer[0].iGateCur = 1
// Deactivate all gates not meant to be active.
//DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(1, 2)
INT iTransitionSwimBikeGate = Tri_Get_Swim_To_Bike_Transition_Gate()
VECTOR vFwd = TRI_Race.sGate[2].vPos - TRI_Race.sGate[1].vPos
FLOAT fBikeHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
ENDIF
//SET_ENTITY_COORDS(TRI_Race.Racer[0].Driver, TRI_Race.Racer[0].vStartPos, TRUE)
SET_ENTITY_COORDS(TRI_Race.Racer[0].Driver, TRI_Race.sGate[0].vPos, TRUE)
ENDIF
// Restore player's bike if necessary.
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Vehicle)
SET_ENTITY_HEALTH(TRI_Race.Racer[0].Vehicle, 1000)
SET_VEHICLE_ENGINE_HEALTH(TRI_Race.Racer[0].Vehicle, 1000.0)
SET_ENTITY_COORDS(TRI_Race.Racer[0].Vehicle, TRI_Race.sGate[iTransitionSwimBikeGate+1].vPos)
SET_VEHICLE_ON_GROUND_PROPERLY(TRI_Race.Racer[0].Vehicle)
ELSE
TRI_Race.Racer[0].Vehicle = CREATE_VEHICLE(TRIBIKE, TRI_Race.sGate[iTransitionSwimBikeGate+1].vPos, fBikeHeading)
ENDIF
ENDPROC
/// PURPOSE:
/// Warp player to the last swim gate.
PROC WARP_PLAYER_TO_LAST_SWIM_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_LAST_SWIM_GATE)
INT iTransitionSwimBikeGate = Tri_Get_Swim_To_Bike_Transition_Gate()
VECTOR vFwd = TRI_Race.sGate[iTransitionSwimBikeGate+2].vPos - TRI_Race.sGate[iTransitionSwimBikeGate+1].vPos
FLOAT fBikeHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
TRI_Race_Gate_Activate(TRI_Race, iTransitionSwimBikeGate+1, TRUE)
TRI_Race.Racer[0].iGateCur = iTransitionSwimBikeGate+1
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iTransitionSwimBikeGate+1, iTransitionSwimBikeGate+2)
// Restore player's bike if necessary.
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Vehicle)
SET_ENTITY_HEALTH(TRI_Race.Racer[0].Vehicle, 1000)
SET_VEHICLE_ENGINE_HEALTH(TRI_Race.Racer[0].Vehicle, 1000.0)
SET_ENTITY_COORDS(TRI_Race.Racer[0].Vehicle, TRI_Race.sGate[iTransitionSwimBikeGate+1].vPos)
ELSE
TRI_Race.Racer[0].Vehicle = CREATE_VEHICLE(TRIBIKE, TRI_Race.sGate[iTransitionSwimBikeGate+1].vPos, fBikeHeading)
ENDIF
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
ENDIF
SET_ENTITY_COORDS(TRI_Race.Racer[0].Driver, TRI_Race.sGate[iTransitionSwimBikeGate].vPos, TRUE)
ENDIF
ENDPROC
/// PURPOSE
/// Warp player to the last bike gate.
PROC WARP_PLAYER_TO_LAST_BIKE_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_LAST_BIKE_GATE)
INT iTransitionBikeRunGate = Tri_Get_Bike_To_Run_Transition_Gate()
VECTOR vFwd = TRI_Race.sGate[iTransitionBikeRunGate].vPos - TRI_Race.sGate[iTransitionBikeRunGate-1].vPos
FLOAT fBikeHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
TRI_Race_Gate_Activate(TRI_Race, iTransitionBikeRunGate, TRUE)
TRI_Race.Racer[0].iGateCur = iTransitionBikeRunGate
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iTransitionBikeRunGate, iTransitionBikeRunGate+1)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF NOT ( IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) )
IF IS_ENTITY_DEAD(TRI_Race.Racer[0].Vehicle)
TRI_Race.Racer[0].Vehicle = CREATE_VEHICLE(TRIBIKE, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(TRI_Race.Racer[0].Driver, << 2.0, 0.0, 0.0 >>), fBikeHeading)
ENDIF
SET_ENTITY_HEALTH(TRI_Race.Racer[0].Vehicle, 1000)
SET_VEHICLE_ENGINE_HEALTH(TRI_Race.Racer[0].Vehicle, 1000.0)
SET_PED_INTO_VEHICLE(TRI_Race.Racer[0].Driver, TRI_Race.Racer[0].Vehicle)
ENDIF
VECTOR vWarpRacerHere = << TRI_Race.sGate[iTransitionBikeRunGate-1].vPos.x, TRI_Race.sGate[iTransitionBikeRunGate-1].vPos.y, TRI_Race.sGate[iTransitionBikeRunGate-1].vPos.z + 0.5 >>
SET_PED_COORDS_KEEP_VEHICLE(TRI_Race.Racer[0].Driver, vWarpRacerHere)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Vehicle)
SET_VEHICLE_ON_GROUND_PROPERLY(TRI_Race.Racer[0].Vehicle)
ENDIF
ENDIF
ENDPROC
/// PURPOSE
/// Warp player to the last run gate.
PROC WARP_PLAYER_TO_LAST_RUN_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_LAST_RUN_GATE)
INT iLastRunGate = TRI_Race.iGateCnt - 2
TRI_Race_Gate_Activate(TRI_Race, iLastRunGate, TRUE)
TRI_Race.Racer[0].iGateCur = iLastRunGate
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iLastRunGate, iLastRunGate+1)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
ENDIF
SET_ENTITY_COORDS(TRI_Race.Racer[0].Driver, TRI_Race.sGate[iLastRunGate].vPos, TRUE)
ENDIF
ENDPROC
/// PURPOSE
/// Warp player to the last run gate.
PROC WARP_PLAYER_END()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_END)
TRI_Race_Gate_Activate(TRI_Race, TRI_Race.iGateCnt-1, TRUE)
TRI_Race.Racer[0].iGateCur = TRI_Race.iGateCnt-1
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
ENDIF
SET_ENTITY_COORDS(TRI_Race.Racer[0].Driver, TRI_Race.sGate[TRI_Race.iGateCnt-1].vPos, TRUE)
ENDIF
ENDPROC
/// PURPOSE
/// Warp all racers to the first gate.
PROC WARP_ALL_TRI_RACERS_TO_FIRST_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_FIRST_GATE)
ENDPROC
/// PURPOSE:
/// Warp all racers to the last swim gate.
PROC WARP_ALL_TRI_RACERS_TO_LAST_SWIM_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_LAST_SWIM_GATE)
INT iRacerIndex
INT iTransitionSwimBikeGate = Tri_Get_Swim_To_Bike_Transition_Gate()
VECTOR vFwd = TRI_Race.sGate[iTransitionSwimBikeGate+1].vPos - TRI_Race.sGate[iTransitionSwimBikeGate].vPos
FLOAT fRacerHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
// Activating new current gate.
TRI_Race_Gate_Activate(TRI_Race, iTransitionSwimBikeGate+1, TRUE)
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iTransitionSwimBikeGate+1, iTransitionSwimBikeGate+2)
REPEAT TRI_Race.iRacerCnt iRacerIndex
IF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_IRONMAN)
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_0
ENDIF
TRI_Race.Racer[iRacerIndex].iGateCur = iTransitionSwimBikeGate+1
// Force racer to leave bike.
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[0].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver)
ENDIF
ENDIF
// We no longer need the current racer bike.
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Vehicle)
SET_VEHICLE_AS_NO_LONGER_NEEDED(TRI_Race.Racer[iRacerIndex].Vehicle)
DELETE_VEHICLE(TRI_Race.Racer[iRacerIndex].Vehicle)
ENDIF
// Warp racer to an offset from a gate.
WARP_RACER_OFFSET_FROM_GATE(iRacerIndex, iTransitionSwimBikeGate, fRacerHeading, FALSE)
ENDREPEAT
// Re-create bikes.
CREATE_TRI_BIKES(TRI_Race)
// Ensure the AI is tasked correctly.
REPEAT TRI_Race.iRacerCnt iRacerIndex
// Racers have not been in bikes.
CLEAR_TRI_AI_CONTROL_FLAG(TRI_Race.Racer[iRacerIndex],TACF_BHASBEENONABIKE)
IF IS_TRI_AI_RACER_VALID(TRI_Race, iRacerIndex, TRUE)
TASK_TRI_RACER_TO_GET_ON_BIKE(TRI_Race, iRacerIndex)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE
/// Warp all racers to the last bike gate.
PROC WARP_ALL_TRI_RACERS_TO_LAST_BIKE_GATE()
CPRINTLN(DEBUG_TRIATHLON, "WARP_ALL_TRI_RACERS_TO_LAST_BIKE_GATE called")
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_LAST_BIKE_GATE)
INT iRacerIndex
INT iTransitionBikeRunGate = Tri_Get_Bike_To_Run_Transition_Gate()
VECTOR vFwd = TRI_Race.sGate[iTransitionBikeRunGate].vPos - TRI_Race.sGate[iTransitionBikeRunGate-1].vPos
FLOAT fRacerHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
// Activating new current gate.
TRI_Race_Gate_Activate(TRI_Race, iTransitionBikeRunGate, TRUE)
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iTransitionBikeRunGate, iTransitionBikeRunGate+1)
REPEAT TRI_Race.iRacerCnt iRacerIndex
IF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_IRONMAN)
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_4
ENDIF
TRI_Race.Racer[iRacerIndex].iGateCur = iTransitionBikeRunGate
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Driver)
IF NOT ( IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) OR IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) )
IF IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Vehicle)
TRI_Race.Racer[iRacerIndex].Vehicle = CREATE_VEHICLE(TRIBIKE, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(TRI_Race.Racer[iRacerIndex].Driver, << 0.0, 4.0, 0.0 >>), fRacerHeading)
ENDIF
SET_ENTITY_HEALTH(TRI_Race.Racer[iRacerIndex].Vehicle, 1000)
SET_VEHICLE_ENGINE_HEALTH(TRI_Race.Racer[iRacerIndex].Vehicle, 1000.0)
SET_PED_INTO_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle)
ENDIF
ENDIF
// Warp racer to an offset from a gate.
WARP_RACER_OFFSET_FROM_GATE(iRacerIndex, iTransitionBikeRunGate-1, fRacerHeading, TRUE)
// Ensure the AI is tasked correctly.
IF IS_TRI_AI_RACER_VALID(TRI_Race, iRacerIndex, TRUE)
// Racers have been on bikes.
SET_TRI_AI_CONTROL_FLAG(TRI_Race.Racer[iRacerIndex],TACF_BHASBEENONABIKE)
TASK_TRI_RACER_TO_FOLLOW_VEHICLE_WAYPOINT_RECORDING(TRI_Race, iRacerIndex)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE
/// Warp all racers to the last run gate.
PROC WARP_ALL_TRI_RACERS_TO_LAST_RUN_GATE()
RESET_DEBUG_RACE_STATE(DEBUG_TRI_RACE_STATE_LAST_RUN_GATE)
INT iRacerIndex
INT iLastRunGate = TRI_Race.iGateCnt - 2
VECTOR vFwd = TRI_Race.sGate[iLastRunGate+1].vPos - TRI_Race.sGate[iLastRunGate].vPos
FLOAT fRacerHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y)
// Activating new current gate.
TRI_Race_Gate_Activate(TRI_Race, iLastRunGate+1, TRUE)
// Deactivate all gates not meant to be active.
DEACTIVATE_OLD_GATES_BEFORE_DEBUG_WARP(iLastRunGate+1, iLastRunGate+1)
REPEAT TRI_Race.iRacerCnt iRacerIndex
TRI_Race.Racer[iRacerIndex].iGateCur = iLastRunGate + 1
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Driver)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) OR IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver)
ENDIF
ENDIF
// Warp racer to an offset from a gate.
WARP_RACER_OFFSET_FROM_GATE(iRacerIndex, iLastRunGate, fRacerHeading, FALSE)
// Ensure the AI is tasked correctly.
IF IS_TRI_AI_RACER_VALID(TRI_Race, iRacerIndex, TRUE)
// Racers have been on bikes.
SET_TRI_AI_CONTROL_FLAG(TRI_Race.Racer[iRacerIndex],TACF_BHASBEENONABIKE)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[iLastRunGate + 1].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE
/// Warps all racers to next leg.
PROC UPDATE_TRI_STAGE_MENU()
IF LAUNCH_MISSION_STAGE_MENU(skipMenuStruct, iReturnCurrentMenuStageSelection, 0)
#IF IS_DEBUG_BUILD
bCheated = TRUE
#ENDIF
SWITCH (iReturnCurrentMenuStageSelection)
/*// Doesn't work for some reason. Not necessary right now. Commenting out.
CASE 0
WARP_PLAYER_TO_FIRST_GATE()
BREAK
*/
CASE 0
WARP_PLAYER_TO_LAST_SWIM_GATE()
BREAK
CASE 1
WARP_PLAYER_TO_LAST_BIKE_GATE()
BREAK
CASE 2
WARP_PLAYER_TO_LAST_RUN_GATE()
BREAK
/*// Doesn't work for some reason. Not necessary right now. Commenting out.
CASE 4
WARP_ALL_TRI_RACERS_TO_FIRST_GATE()
BREAK
*/
CASE 3
CPRINTLN(DEBUG_TRIATHLON, "WARP_ALL_TRI_RACERS_TO_LAST_SWIM_GATE called from UPDATE_TRI_STAGE_MENU")
WARP_ALL_TRI_RACERS_TO_LAST_SWIM_GATE()
BREAK
CASE 4
WARP_ALL_TRI_RACERS_TO_LAST_BIKE_GATE()
BREAK
CASE 5
WARP_ALL_TRI_RACERS_TO_LAST_RUN_GATE()
BREAK
ENDSWITCH
ENDIF
ENDPROC
/// PURPOSE
/// Warp all racers to a different gate ahead.
/// TODO: Cleanup and make behavior clearer.
PROC WARP_ALL_TRI_RACERS_TO_NEXT_SET_OF_GATES()
INT iWarpRacerToThisGate
INT iNewRacerCurrentGate
// Press button to warp player and racers to next leg.
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_BACKSLASH)
#IF IS_DEBUG_BUILD
bCheated = TRUE
#ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->Warp_All_Racers_To_Next_Leg] KEY_BACKSLASH pressed. Warp all racers.")
INT iRacerIndex
REPEAT TRI_Race.iRacerCnt iRacerIndex
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Driver)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerIndex].Vehicle)
VECTOR vGateGotoWithOffset
FLOAT fGateHeading
SWITCH ( Tri_Get_Racer_Current_Race_Leg(TRI_Race, TRI_Race.Racer[iRacerIndex]) )
CASE TRI_TRI_RACE_LEG_SWIM
// Warp the racer to the bike checkpoint.
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_ALAMO_SEA
TRI_Race_Gate_Activate(TRI_Race, 4, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = 4
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.sGate[3].vPos, TRUE)
IF NOT (iRacerIndex = 0)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[4].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
CASE TRIATHLON_RACE_VESPUCCI
TRI_Race_Gate_Activate(TRI_Race, 4, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = 4
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.sGate[3].vPos, TRUE)
IF NOT (iRacerIndex = 0)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[4].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
CASE TRIATHLON_RACE_IRONMAN
IF TRI_Race.Racer[iRacerIndex].iGateCur < 3 // Middle of swim leg.
iWarpRacerToThisGate = 2
iNewRacerCurrentGate = 3
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 8 // End of swim leg.
iWarpRacerToThisGate = 7
iNewRacerCurrentGate = 8
ENDIF
TRI_Race_Gate_Activate(TRI_Race, iNewRacerCurrentGate, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = iNewRacerCurrentGate
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver,
<< TRI_Race.sGate[iWarpRacerToThisGate].vPos.x,
TRI_Race.sGate[iWarpRacerToThisGate].vPos.y,
TRI_Race.sGate[iWarpRacerToThisGate].vPos.z + 5.0 >>,
TRUE)
IF NOT (iRacerIndex = 0)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[iNewRacerCurrentGate].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
ENDSWITCH
BREAK
CASE TRI_TRI_RACE_LEG_BIKE
// Warp the racer to the run checkpoint.
SWITCH eCurrentTriRace
CASE TRIATHLON_RACE_ALAMO_SEA
TRI_Race_Gate_Activate(TRI_Race, 15, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = 15
IF NOT ( IS_PED_IN_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle) OR
IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) )
SET_PED_INTO_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle)
ENDIF
fGateHeading = GET_HEADING_BETWEEN_VECTORS(TRI_Race.sGate[15].vPos, TRI_Race.sGate[14].vPos)
SWITCH iRacerIndex
CASE 1
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << -3.0, -5.5, 0.0 >>)
BREAK
CASE 2
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << -2.0, -5.5, 0.0 >>)
BREAK
CASE 3
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << -1.0, -5.0, 0.0 >>)
BREAK
CASE 4
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 0.0, -5.0, 0.0 >>)
BREAK
CASE 5
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 1.0, -5.0, 0.0 >>)
BREAK
CASE 6
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 2.0, -5.5, 0.0 >>)
BREAK
CASE 7
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 3.0, -5.5, 0.0 >>)
BREAK
CASE 8
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << -3.5, -5.0, 0.0 >>)
BREAK
CASE 9
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 3.5, -5.0, 0.0 >>)
BREAK
CASE 10
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << -2.5, -5.0, 0.0 >>)
BREAK
CASE 11
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 2.5, -5.0, 0.0 >>)
BREAK
DEFAULT
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[14].vPos, fGateHeading, << 0.0, -5.0, 0.0 >>)
BREAK
ENDSWITCH
SET_PED_COORDS_KEEP_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, vGateGotoWithOffset)
IF NOT (iRacerIndex = 0)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[15].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
CASE TRIATHLON_RACE_VESPUCCI
TRI_Race_Gate_Activate(TRI_Race, 18, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = 18
IF NOT ( IS_PED_IN_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle) OR
IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) )
SET_PED_INTO_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle)
ENDIF
fGateHeading = GET_HEADING_BETWEEN_VECTORS(TRI_Race.sGate[18].vPos, TRI_Race.sGate[17].vPos)
SWITCH iRacerIndex
CASE 1
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << -3.0, -5.5, 0.0 >>)
BREAK
CASE 2
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << -2.0, -5.5, 0.0 >>)
BREAK
CASE 3
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << -1.0, -5.0, 0.0 >>)
BREAK
CASE 4
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 0.0, -5.0, 0.0 >>)
BREAK
CASE 5
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 1.0, -5.0, 0.0 >>)
BREAK
CASE 6
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 2.0, -5.5, 0.0 >>)
BREAK
CASE 7
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 3.0, -5.5, 0.0 >>)
BREAK
CASE 8
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << -3.5, -5.0, 0.0 >>)
BREAK
CASE 9
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 3.5, -5.0, 0.0 >>)
BREAK
CASE 10
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << -2.5, -5.0, 0.0 >>)
BREAK
CASE 11
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 2.5, -5.0, 0.0 >>)
BREAK
DEFAULT
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[17].vPos, fGateHeading, << 0.0, -5.0, 0.0 >>)
BREAK
ENDSWITCH
SET_PED_COORDS_KEEP_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, vGateGotoWithOffset)
IF NOT (iRacerIndex = 0)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[18].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
CASE TRIATHLON_RACE_IRONMAN
// Set which gates to activate and warp the racers.
IF TRI_Race.Racer[iRacerIndex].iGateCur < 27 // End of Old Tri 3.
iWarpRacerToThisGate = 26
iNewRacerCurrentGate = 27
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_1
ENDIF
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 36 // Left turn from main road after downhill.
iWarpRacerToThisGate = 35
iNewRacerCurrentGate = 36
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_1
ENDIF
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 43 // Right before the transition from vehicle recoring 1 to 2.
iWarpRacerToThisGate = 42
iNewRacerCurrentGate = 43
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_1
ENDIF
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 51 // Before trolly station before big left turn crossing tracks.
iWarpRacerToThisGate = 50
iNewRacerCurrentGate = 51
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_2
ENDIF
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 62 // Right before Muscle beach houses, before vehicle recording 2 to 3.
iWarpRacerToThisGate = 61
iNewRacerCurrentGate = 62
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_2
ENDIF
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 68 // Start of beachwalk.
iWarpRacerToThisGate = 67
iNewRacerCurrentGate = 68
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_3
ENDIF
ELIF TRI_Race.Racer[iRacerIndex].iGateCur < 84 // Top of the hill. Left turn towards road by hotel and run transition gate.
iWarpRacerToThisGate = 83
iNewRacerCurrentGate = 84
IF iRacerIndex > 0
TRI_Race.Racer[iRacerIndex].szCurrentBikeRecordingName = szTriBikeRecordingName_IronMan_3
ENDIF
ENDIF
TRI_Race_Gate_Activate(TRI_Race, iNewRacerCurrentGate, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = iNewRacerCurrentGate
IF NOT ( IS_PED_IN_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle) OR
IS_PED_GETTING_INTO_A_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver) )
SET_PED_INTO_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle)
ENDIF
fGateHeading = GET_HEADING_BETWEEN_VECTORS(TRI_Race.sGate[iNewRacerCurrentGate].vPos, TRI_Race.sGate[91].vPos)
SWITCH iRacerIndex
CASE 1
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << -3.0, -5.5, 0.0 >>)
BREAK
CASE 2
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << -2.0, -5.5, 0.0 >>)
BREAK
CASE 3
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << -1.0, -5.0, 0.0 >>)
BREAK
CASE 4
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 0.0, -5.0, 0.0 >>)
BREAK
CASE 5
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 1.0, -5.0, 0.0 >>)
BREAK
CASE 6
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 2.0, -5.5, 0.0 >>)
BREAK
CASE 7
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 3.0, -5.5, 0.0 >>)
BREAK
CASE 8
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << -3.5, -5.0, 0.0 >>)
BREAK
CASE 9
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 3.5, -5.0, 0.0 >>)
BREAK
CASE 10
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << -2.5, -5.0, 0.0 >>)
BREAK
CASE 11
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 2.5, -5.0, 0.0 >>)
BREAK
DEFAULT
vGateGotoWithOffset = GET_OFFSET_FROM_COORD_IN_WORLD_COORDS(TRI_Race.sGate[iWarpRacerToThisGate].vPos, fGateHeading, << 0.0, -5.0, 0.0 >>)
BREAK
ENDSWITCH
SET_PED_COORDS_KEEP_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver, vGateGotoWithOffset)
IF NOT (iRacerIndex = 0)
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[iNewRacerCurrentGate].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
ENDSWITCH
BREAK
CASE TRI_TRI_RACE_LEG_RUN
// Warp racer a couple of gates before the end of the race.
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.sGate[TRI_Race.iGateCnt - 2].vPos, TRUE, TRUE)
TRI_Race_Gate_Activate(TRI_Race, TRI_Race.iGateCnt - 2, TRUE)
TRI_Race.Racer[iRacerIndex].iGateCur = TRI_Race.iGateCnt - 2
SET_ENTITY_COORDS(TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.sGate[TRI_Race.iGateCnt - 3].vPos, TRUE)
IF NOT (iRacerIndex = 0)
IF IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver)
TASK_LEAVE_ANY_VEHICLE(TRI_Race.Racer[iRacerIndex].Driver)
SET_VEHICLE_IS_CONSIDERED_BY_PLAYER(TRI_Race.Racer[iRacerIndex].Vehicle, TRUE)
ENDIF
TRI_Race_Racer_Task_Go_To_Next_Gate(TRI_Race, TRI_Race.Racer[iRacerIndex].Driver, TRI_Race.Racer[iRacerIndex].Vehicle,
TRI_Race.sGate[TRI_Race.iGateCnt - 2].vPos, TRI_CHKPT_TRI_RUN, iRacerIndex)
ENDIF
BREAK
ENDSWITCH
ENDIF
ENDIF
ENDREPEAT
ENDIF
ENDPROC
/// PURPOSE:
/// Draw spheres representing the racers' intended destinations
/// in the run leg of the race.
PROC DRAW_TRI_DEBUG_RACERS_RUN_DESTINATIONS()
// World origin position vector.
DRAW_DEBUG_SPHERE(vCurrentGatePos_Debug, 0.5, 0, 0, 0)
// Current gate position vector.
DRAW_DEBUG_SPHERE(vCurrentGatePos_Debug, 0.5, 255, 255, 255)
DRAW_DEBUG_LINE(<< 0, 0, 0 >>, vCurrentGatePos_Debug, 0, 0, 0)
// Next gate position vector.
DRAW_DEBUG_SPHERE(vNextGatePos_Debug, 0.5, 128, 128, 128)
DRAW_DEBUG_LINE(<< 0, 0, 0 >>, vNextGatePos_Debug, 0, 0, 0)
// Vector between current gate position and next gate position.
DRAW_DEBUG_LINE(vNextGatePos_Debug, vCurrentGatePos_Debug, 192, 192, 192)
// Midpoint position vector between current and next gate.
DRAW_DEBUG_SPHERE(vMidPointBetweenCurrentAndNextGate_Debug, 0.5, 192, 192, 192)
// Offset point from current gate position.
DRAW_DEBUG_SPHERE(vGateGotoWithOffset_Debug, 0.5, 161, 0, 255)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->DRAW_TRI_DEBUG_RACERS_RUN_DESTINATIONS] vGateGotoWithOffset_Debug: ", vGateGotoWithOffset_Debug)
ENDPROC
/// PURPOSE:
/// Print output to RAG as fast as timerDebug_A allows.
///
/// bAllowDebugPrint - Allow whether or not to print debug data to RAG.
PROC DRAW_TRI_DEBUG(BOOL bAllowDebugPrint)
IF bAllowDebugPrint
// Draw spheres representing the racers' intended destinations in the run leg of the race.
//DRAW_TRI_DEBUG_RACERS_RUN_DESTINATIONS()
ENDIF
ENDPROC
/// PURPOSE:
/// Print the player's stamina values.
PROC PRINT_TRI_DEBUG_PLAYER_STAMINA_VALUES()
PRINTNL()
// CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_AI.sch->DEBUG_Tri_Print_Player_Stamina_Status] Player's current intensity is: ", Tri_Player_Stamina.iCurrentIntensity)
// CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_AI.sch->DEBUG_Tri_Print_Player_Stamina_Status] Player's max intensity is: ", Tri_Player_Stamina.iMaxIntensity)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_AI.sch->DEBUG_Tri_Print_Player_Stamina_Status] Player's current energy is: ", Tri_Player_Stamina.iCurrentEnergy)
CPRINTLN(DEBUG_TRIATHLON, "[TRI_Triathlon_AI.sch->DEBUG_Tri_Print_Player_Stamina_Status] Player's max energy is: ", Tri_Player_Stamina.iMaxEnergy)
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print whether or not racers are waiting on world collision to load.
///
/// NOTE: I'm not confident about the accuracy of this command.
PROC PRINT_TRI_DEBUG_ARE_RACERS_WAITING_ON_WORLD_COLLISION_TO_LOAD()
PRINTNL()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver)
IF IS_ENTITY_WAITING_FOR_WORLD_COLLISION(TRI_Race.Racer[iRacerCounter].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_ARE_RACERS_WAITING_ON_WORLD_COLLISION] Racer #", iRacerCounter, " is waiting on collision to stream in.")
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_ARE_RACERS_WAITING_ON_WORLD_COLLISION] Racer #", iRacerCounter, " is NOT waiting on collision.")
ENDIF
ENDIF
ENDREPEAT
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print all racers' heights aboveground.
PROC PRINT_TRI_DEBUG_RACERS_HEIGHT_ABOVE_GROUND_IN_METERS()
PRINTNL()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_HEIGHT_ABOVE_GROUND_IN_METERS] Racer #", iRacerCounter, "'s height above ground is ",
GET_ENTITY_HEIGHT_ABOVE_GROUND(TRI_Race.Racer[iRacerCounter].Driver))
ENDIF
ENDREPEAT
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print all racers' positions, ranks, and distance from the player.
PROC PRINT_TRI_DEBUG_RACERS_LOCATION_DATA()
PRINTNL()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver)
IF NOT IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerCounter].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, " is NOT on a bike.")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s position is ",
GET_STRING_FROM_VECTOR(GET_ENTITY_COORDS(TRI_Race.Racer[iRacerCounter].Driver)))
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s rank is ", TRI_Race.Racer[iRacerCounter].iRank)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF NOT IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s distance from player is ",
GET_DISTANCE_BETWEEN_ENTITIES(TRI_Race.Racer[iRacerCounter].Driver, TRI_Race.Racer[0].Driver))
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s distance from player is ",
GET_DISTANCE_BETWEEN_ENTITIES(TRI_Race.Racer[iRacerCounter].Driver, TRI_Race.Racer[0].Vehicle))
ENDIF
ENDIF
ELSE
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Vehicle)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, " IS on a bike.")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s position is ",
GET_STRING_FROM_VECTOR(GET_ENTITY_COORDS(TRI_Race.Racer[iRacerCounter].Vehicle)))
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s rank is ", TRI_Race.Racer[iRacerCounter].iRank)
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
IF NOT IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[0].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s distance from player is ",
GET_DISTANCE_BETWEEN_ENTITIES(TRI_Race.Racer[iRacerCounter].Vehicle, TRI_Race.Racer[0].Driver))
ELSE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_LOCATION_DATA] Racer #", iRacerCounter, "'s distance from player is ",
GET_DISTANCE_BETWEEN_ENTITIES(TRI_Race.Racer[iRacerCounter].Vehicle, TRI_Race.Racer[0].Vehicle))
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print which vehicle recording racers are currently assigned to in Ironman.
PROC PRINT_TRI_DEBUG_RACERS_CURRENT_IRONMAN_VEHICLE_RECORDINGS()
INT iRacerCounter
PRINTNL()
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF ARE_STRINGS_EQUAL(TRI_Race.Racer[iRacerCounter].szCurrentBikeRecordingName, szTriBikeRecordingName_IronMan_0)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_CURRENT_VEHICLE_RECORDINGS] Racer #", iRacerCounter, " is at Ironman 0 recording.")
ELIF ARE_STRINGS_EQUAL(TRI_Race.Racer[iRacerCounter].szCurrentBikeRecordingName, szTriBikeRecordingName_IronMan_1)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_CURRENT_VEHICLE_RECORDINGS] Racer #", iRacerCounter, " is at Ironman 1 recording.")
ELIF ARE_STRINGS_EQUAL(TRI_Race.Racer[iRacerCounter].szCurrentBikeRecordingName, szTriBikeRecordingName_IronMan_2)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_CURRENT_VEHICLE_RECORDINGS] Racer #", iRacerCounter, " is at Ironman 2 recording.")
ELIF ARE_STRINGS_EQUAL(TRI_Race.Racer[iRacerCounter].szCurrentBikeRecordingName, szTriBikeRecordingName_IronMan_3)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_CURRENT_VEHICLE_RECORDINGS] Racer #", iRacerCounter, " is at Ironman 3 recording.")
ELIF ARE_STRINGS_EQUAL(TRI_Race.Racer[iRacerCounter].szCurrentBikeRecordingName, szTriBikeRecordingName_IronMan_4)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_CURRENT_VEHICLE_RECORDINGS] Racer #", iRacerCounter, " is at Ironman 4 recording.")
ENDIF
ENDREPEAT
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print all racers' current compete mode.
PROC PRINT_TRI_DEBUG_RACERS_COMPETE_MODES()
PRINTNL()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
SWITCH (TRI_Race.Racer[iRacerCounter].eCompeteMode)
// The racer is racing normally.
CASE TRI_RACER_COMPETE_MODE_DEFAULT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_COMPETE_MODES] Racer #", iRacerCounter, "'s current complete mode is DEFAULT")
BREAK
// The racer is racing slowly.
CASE TRI_RACER_COMPETE_MODE_TIRED
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_COMPETE_MODES] Racer #", iRacerCounter, "'s current complete mode is TIRED")
BREAK
// The racer is racing at max speed.
CASE TRI_RACER_COMPETE_MODE_AGGRESSIVE
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_COMPETE_MODES] Racer #", iRacerCounter, "'s current complete mode is AGGRESSIVE")
BREAK
// The racer is forced to slow down by a specific condition in the race.
CASE TRI_RACER_COMPETE_MODE_FORCED_TIRED
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_COMPETE_MODES] Racer #", iRacerCounter, "'s current complete mode is FORCED_TIRED")
BREAK
// Should never reach here.
DEFAULT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_COMPETE_MODES] Racer #", iRacerCounter, "'s current complete mode is INVALID")
BREAK
ENDSWITCH
ENDREPEAT
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print all racers' bike speeds, and other useful data.
PROC PRINT_TRI_DEBUG_RACERS_BIKE_SPEED()
PRINTNL()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF IS_TRI_AI_RACER_VALID(TRI_Race, iRacerCounter, TRUE)
IF IS_PED_IN_VEHICLE(TRI_Race.Racer[iRacerCounter].Driver, TRI_Race.Racer[iRacerCounter].Vehicle)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_BIKE_SPEED] Racer's #", iRacerCounter, "'s current bike speed is ",
GET_ENTITY_SPEED(TRI_Race.Racer[iRacerCounter].Vehicle))
/*// Uncomment below for a data-filled version of the output above
// Comment out print above if using more extensive version below.
STRING szCompeteMode
SWITCH (TRI_Race.Racer[iRacerCounter].eCompeteMode)
// The racer is racing normally.
CASE TRI_RACER_COMPETE_MODE_DEFAULT
szCompeteMode = "DEFAULT"
BREAK
// The racer is racing slowly.
CASE TRI_RACER_COMPETE_MODE_TIRED
szCompeteMode = "TIRED"
BREAK
// The racer is racing at max speed.
CASE TRI_RACER_COMPETE_MODE_AGGRESSIVE
szCompeteMode = "AGGRESSIVE"
BREAK
// The racer is forced to slow down by a specific condition in the race.
CASE TRI_RACER_COMPETE_MODE_FORCED_TIRED
szCompeteMode = "FORCED TIRED"
BREAK
// Should never reach here.
DEFAULT
szCompeteMode = "INVALID"
BREAK
ENDSWITCH
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc] Racer's #", iRacerCounter, "'s current bike speed is ",
GET_ENTITY_SPEED(TRI_Race.Racer[iRacerCounter].Vehicle), " at rank ", TRI_Race.Racer[iRacerCounter].iRank, " at ",
GET_DISTANCE_BETWEEN_ENTITIES(TRI_Race.Racer[iRacerCounter].Driver, TRI_Race.Racer[0].Driver), " meters from player, in ",
szCompeteMode, " compete mode, and skill level, ", Race.Racer[iRacerCounter].iSkillPlacement)
CPRINTLN(DEBUG_TRIATHLON, "His minimum allowed speed is ", TRI_Race.Racer[iRacerCounter].fMinBikeSpeed, ", and his maximum allowed speed is ",
TRI_Race.Racer[iRacerCounter].fMaxBikeSpeed)
*/
ELSE
//CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_BIKE_SPEED] Racer's #", iRacerCounter, " is not in a vehicle.")
ENDIF
ELSE
//CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_BIKE_SPEED] Racer's #", iRacerCounter, " is DEAD!")
ENDIF
ENDREPEAT
//CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_BIKE_SPEED] Limit of aggro racers:", iLimitOfAggressiveRacers)
//CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_BIKE_SPEED] Limit of tired racers:", iLimitOfTiredRacers)
//CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_BIKE_SPEED] Limit of forced tired racers:", iLimitOfForcedTiredRacers)
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print all racers' move blend ratio, and other useful data.
/// Useful for getting the speed of racers in the swim and run legs of the race.
PROC PRINT_TRI_DEBUG_RACERS_MOVE_BLEND_RATIO()
PRINTNL()
INT iRacerCounter
REPEAT TRI_Race.iRacerCnt iRacerCounter
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[iRacerCounter].Driver)
IF NOT IS_PED_IN_ANY_VEHICLE(TRI_Race.Racer[iRacerCounter].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->PRINT_TRI_DEBUG_RACERS_MOVE_BLEND_RATIO] Racer #", iRacerCounter, "'s current move blend ratio is ",
GET_PED_DESIRED_MOVE_BLEND_RATIO(TRI_Race.Racer[iRacerCounter].Driver), " with rank ", TRI_Race.Racer[iRacerCounter].iRank,
" and is at ", GET_DISTANCE_BETWEEN_ENTITIES(TRI_Race.Racer[iRacerCounter].Driver, TRI_Race.Racer[0].Driver), " meters from player.")
ENDIF
ENDIF
ENDREPEAT
PRINTNL()
ENDPROC
/// PURPOSE:
/// Print output to RAG as fast as timerDebug_A allows.
///
/// bAllowDebugPrint - Allow whether or not to print debug data to RAG.
///
/// NOTE: Uncomment the command that prints the data you want.
PROC PRINT_TRI_DEBUG(BOOL bAllowDebugPrint)
IF bAllowDebugPrint
// Print all racers' move blend ratio, and other useful data.
//PRINT_TRI_DEBUG_RACERS_MOVE_BLEND_RATIO()
// Print all racers' bike speeds, and other useful data.
//PRINT_TRI_DEBUG_RACERS_BIKE_SPEED()
// Print all racers' current compete mode.
//PRINT_TRI_DEBUG_RACERS_COMPETE_MODES()
// Print which vehicle recording racers are currently assigned to.
//PRINT_TRI_DEBUG_RACERS_CURRENT_IRONMAN_VEHICLE_RECORDINGS()
// Print all racers' positions, ranks, and distance from the player.
//PRINT_TRI_DEBUG_RACERS_LOCATION_DATA()
// Print all racers' heights aboveground.
//PRINT_TRI_DEBUG_RACERS_HEIGHT_ABOVE_GROUND_IN_METERS()
// Print whether or not racers are waiting on world collision to load.
//PRINT_TRI_DEBUG_ARE_RACERS_WAITING_ON_WORLD_COLLISION_TO_LOAD()
// Print the player's stamina values.
//PRINT_TRI_DEBUG_PLAYER_STAMINA_VALUES()
ENDIF
ENDPROC
/// PURPOSE:
/// Manage debug functionality that is only used during
/// the main update loop (i.e. as long as the race is active).
PROC UPDATE_TRI_DEBUG_DURING_ACTIVE_RACE()
IF TRI_Race.eUpdate = TRI_RACE_UPDATE_WAIT
IF TIMER_DO_WHEN_READY(timerDebug_A, 1.0)
// Print output to RAG as fast as timerDebug_A allows
PRINT_TRI_DEBUG(FALSE)
DRAW_TRI_DEBUG(FALSE)
RESTART_TIMER_AT(timerDebug_A, 0.0)
ENDIF
// Update the Z-debug menu.
UPDATE_TRI_STAGE_MENU()
ENDIF
ENDPROC
/// PURPOSE:
/// Process debug input for jumping gates, legs, and passing/failing race, etc.
PROC UPDATE_TRI_DEBUG_INPUT_MANAGER()
// Warp player to next gate.
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J)
#IF IS_DEBUG_BUILD
bCheated = TRUE
#ENDIF
WARP_PLAYER_TO_CURRENT_GATE()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_DEBUG_INPUT_MANAGER] Warping player to current gate.")
ENDIF
// Warp player to previous leg.
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_P)
#IF IS_DEBUG_BUILD
bCheated = TRUE
#ENDIF
IF TRI_Race.Racer[0].iGateCur > Tri_Get_Swim_To_Bike_Transition_Gate()
AND TRI_Race.Racer[0].iGateCur < (Tri_Get_Bike_To_Run_Transition_Gate()+1)
WARP_ALL_TRI_RACERS_TO_LAST_SWIM_GATE()
ELIF TRI_Race.Racer[0].iGateCur > (Tri_Get_Bike_To_Run_Transition_Gate()+1)
WARP_ALL_TRI_RACERS_TO_LAST_BIKE_GATE()
ENDIF
ENDIF
// Pass Triathlon race.
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S) AND TRI_Race.eUpdate = TRI_RACE_UPDATE_WAIT
#IF IS_DEBUG_BUILD
bCheated = TRUE
#ENDIF
CLEANUP_TRI_PED_PROPS()
WARP_PLAYER_END()
S_SKIP_ACTIVATED = TRUE
CPRINTLN(DEBUG_TRIATHLON, "Warped to end of Triathlon, only from WAIT!")
ENDIF
// Fail Triathlon race.
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F)
TRIGGER_SCREENBLUR_FADE_OUT(0)
CLEANUP_TRI_PED_PROPS()
// Cleanup Triathlon and SPR system, and terminate the script.
CLEANUP_ALL_AND_TERMINATE_TRIATHLON(Tri_Race)
ENDIF
// Fail Triathlon race.
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_1)
#IF IS_DEBUG_BUILD
bCheated = TRUE
#ENDIF
IS_CHEATING_ENABLED = NOT IS_CHEATING_ENABLED
ENDIF
/*
// Press a button on the controller to output camera information relative to player.
IF IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_EXIT)
OUTPUT_DEBUG_CAM_RELATIVE_TO_ENTITY(TRI_Race.Racer[0].Driver)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRI_DEBUG] Outputting cam info relative to player.")
ENDIF
*/
ENDPROC
PROC UPDATE_TRI_DEBUG_LABELS()
DRAW_DEBUG_TEXT_ABOVE_ENTITY( vehPlayerDroveBeforeRace, "player vehicle", 0.0 )
ENDPROC
/// PURPOSE:
/// Process SPR Main debug inputs.
PROC UPDATE_TRI_DEBUG()
UPDATE_TRI_DEBUG_LABELS()
// Process debug input for jumping gates, legs, and passing/failing race.
UPDATE_TRI_DEBUG_INPUT_MANAGER()
// Manage debug functionality that is only used during the main update loop (i.e. as long as the race is active).
UPDATE_TRI_DEBUG_DURING_ACTIVE_RACE()
// Warps all racers to next leg, or next set of gates.
WARP_ALL_TRI_RACERS_TO_NEXT_SET_OF_GATES()
// Keep running RAG->Script->Z-Volume. Ensure it's initialized and cleaned up.
// NOTE: This should be commented out when checked in, as it triggers an assert
// when conflicting with the SPR race editor widget.
//UPDATE_ZVOLUME_WIDGETS()
// Reset triathlon banners
RESET_TRI_BANNERS()
ENDPROC
/// PURPOSE
/// Initialize all Triathlon debug functionality.
PROC INIT_TRI_DEBUG()
SET_TRI_MENU_STAGE()
// Initialize running RAG->Script->Z-Volume. Ensure it's being updated and cleaned up.
// NOTE: This should be commented out when checked in, as it triggers an assert
// when conflicting with the SPR race editor widget.
//INIT_ZVOLUME_WIDGETS()
ENDPROC
// ===============================================
// E N D TRI DEBUG FUNCTIONS AND PROCEDURES
// ===============================================
#ENDIF
// ======================================
// STATE MACHINES
// ======================================
/// PURPOSE:
/// Setup SPR system.
///
/// RETURNS:
/// TRUE if still setting up the SPR system.
FUNC BOOL SETUP_TRI_SYSTEM(TRIATHLON_LAUNCH_DATA triLaunchData, CAMERA_INDEX &camTriSky, TRI_RACE_STRUCT &race)
UNUSED_PARAMETER(race)
// Check if player is dead.
IF IS_ENTITY_DEAD(PLAYER_PED_ID())
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] The player is dead. Stop setting up TRI_Main.")
RETURN FALSE
ENDIF
// Setup SPR Main State Machine.
SWITCH (TRI_Main.eSetup)
// Initialize SPR Main setup
CASE TRI_MAIN_SETUP_INIT
TRI_SET_PED_CONFIG_FLAG( PLAYER_PED_ID(), PCF_DisableDeepSurfaceAnims, TRUE )
// This flag is automatically set to FALSE once the mission is terminated.
SET_MISSION_FLAG(TRUE)
DISABLE_SELECTOR()
START_AUDIO_SCENE("TRI_START_SCENE")
// Suppress the runner model
SET_PED_MODEL_IS_SUPPRESSED(A_M_Y_RoadCyc_01, TRUE)
SET_PED_MODEL_IS_SUPPRESSED(A_C_SharkTiger, TRUE)
// TRI_LOAD_COURSE_DATA(TRI_Race
// Setup Master structure for Triathlon Races.
TRI_Master.eRaceType = TRI_RACE_TYPE_TRIATHLON
TRI_Master.PlayerVeh = NULL
TRI_Master.eDefChkPntType = TRI_CHKPT_TRI_SWIM
TRI_Master.eDefDrvType = PEDTYPE_PLAYER1
TRI_Master.eDefDrvModel = A_M_Y_RoadCyc_01
TRI_Master.eDefVehModel = DUMMY_MODEL_FOR_SCRIPT
TRI_Master.szXMLPath = "X:/gta5/titleupdate/dev_ng/common/data/script/xml/"
TRI_Master.szSCHPath = "X:/gta5/script/dev/singleplayer/scripts/Minigames/"
TRI_Master.szTRIPath = "SP_Races/"
TRI_Master.szMainPath = "Triathlon/"
TRI_Master.szRacesPath = "Races/"
TRI_Master.oTable = triLaunchData.oTable
TRI_Master.pedTableGuy = triLaunchData.pedStartPed
TRI_Master.oClipboard = triLaunchData.oClipboard
TRI_Master.oPencil = triLaunchData.oPencil
SET_ENTITY_AS_MISSION_ENTITY( Tri_Master.pedTableGuy, TRUE, TRUE )
// String labels for course titles and race completion goal times
TRI_Master.szRaceName[TRIATHLON_RACE_ALAMO_SEA] = "TRI_BASIC_1"
TRI_Master.szRaceName[TRIATHLON_RACE_VESPUCCI] = "TRI_BASIC_2"
TRI_Master.szRaceName[TRIATHLON_RACE_IRONMAN] = "TRI_BASIC_3"
// Triathlon is not in edit mode, so store it as such.
TRI_Main.iTRIMode = -1
TRI_Master.vDefRcrPos = triLaunchData.raceStartLocation
TRI_Master.fDefRcrHead = 97.0
// Set up the position where the script should load from.
vScriptStartPos = triLaunchData.raceStartLocation
// Store the current race.
TRI_Master.iRaceCur = ENUM_TO_INT(triLaunchdata.raceToLaunch)
eCurrentTriRace = triLaunchData.raceToLaunch
// Initialize Triathlon.
INIT_TRIATHLON()
// Take away player control.
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, SPC_REMOVE_EXPLOSIONS | SPC_REMOVE_FIRES | SPC_REMOVE_PROJECTILES)
// Fade out so we can start populating the race.
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_INIT to TRI_MAIN_SETUP_FADE_OUT")
CPRINTLN(DEBUG_TRIATHLON, "TRI_Master.iRaceCur=", TRI_Master.iRaceCur, ", eCurrentTriRace=", eCurrentTriRace, ", vScriptStartPos=", vScriptStartPos)
REQUEST_TRI_ASSETS()
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_PED_LOD_MULTIPLIER(PLAYER_PED_ID(), TRI_LOD_SETTING)
ENDIF
#IF IS_DEBUG_BUILD
// Load Master XML file.
TRI_Master_Load()
// Set up the race editor widget.
TRI_Widget_Main_Setup_TRI(TRI_Widget)
#ENDIF
TRI_Main.eSetup = TRI_MAIN_SETUP_FADE_OUT
BREAK
// Fade out after player chooses to participate in Triathlon.
CASE TRI_MAIN_SETUP_FADE_OUT
DEBUG_MESSAGE("TRI_MAIN_SETUP_FADE_OUT")
VECTOR vEndPos, vEndRot
IF eCurrentTriRace = TRIATHLON_RACE_ALAMO_SEA
vEndPos = <<2431.6714, 4281.2720, 37.1329>>//<<2408.5266, 4283.1060, 51.5560>>//<<2429.2104, 4284.1646, 45.1134>>
vEndRot = <<-10.7690, 0.0000, -51.5263>>//<<9.2278, -0.0000, 95.4363>>//<<15.0000, 0.0000, 95.1740>>
ELIF eCurrentTriRace = TRIATHLON_RACE_VESPUCCI
vEndPos = <<-1233.3401, -2053.1907, 14.8590>>//<<-1260.5, -2048.5, 15.4>>//<<-1260.4017, -2048.6079, 16.1657>>
vEndRot = <<-23.6826, -0.0000, -58.0414>>//<<16.4, -0.0, 45.2>>//<<17.6129, 0.0000, 41.6385>>
ELIF eCurrentTriRace = TRIATHLON_RACE_IRONMAN
vEndPos = <<1594.5328, 3807.8044, 35.0907>>//<<1595.6, 3822.0, 44.3>> //<<1605.2433, 3822.2114, 53.5891>>
vEndRot = <<-7.4446, -0.0000, -84.6022>>//<<17.7, -0.0, 44.9>>//<<11.9879, 0.0000, 71.2356>>
ENDIF
REQUEST_TRI_ASSETS()
IF HAS_ANIM_DICT_LOADED("mini@triathlonintro")
AND HAS_MODEL_LOADED( A_M_Y_RoadCyc_01 )
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_ENTITY_AS_MISSION_ENTITY(TRI_Master.oPencil, TRUE, TRUE)
ATTACH_ENTITY_TO_ENTITY(TRI_Master.oPencil, PLAYER_PED_ID(), GET_PED_BONE_INDEX( PLAYER_PED_ID(), BONETAG_PH_R_HAND ), <<0.0,0.0,0.0>>, <<0.0,0.0,0.0>> )
ENDIF
IF TRI_ACTIVATE_INTRO_SKY_CAM(camTriSky, vEndPos, vEndRot)
//IF eCurrentCutsceneStage >= TRI_CUTSCENE_STAGE_SETUP
// If the player arrived to the race in a vehicle, or left a vehicle near the starting
// point of the race, store it until the player has completed the race.
STORE_PRE_TRIATHLON_PLAYER_VEHICLE_DURING_RACE()
// Removes ambient traffic from interfering in the race.
// Calling this here to avoid the game temporarily freezing before fade out.
REMOVE_ANY_TRAFFIC_FROM_TRI_RACE_ROADS()
// Clear area of objects and such
race.objErrantBuoy1 = GET_CLOSEST_OBJECT_OF_TYPE((<<-1280.2456, -2005.1273, -3.6539>>), 5.0, prop_dock_bouy_1)
IF DOES_ENTITY_EXIST(race.objErrantBuoy1)
SET_ENTITY_VISIBLE(race.objErrantBuoy1, FALSE)
SET_ENTITY_COLLISION(race.objErrantBuoy1, FALSE)
CPRINTLN(DEBUG_TRIATHLON, "Attmepting to 'remove' objErrantBuoy1!")
ENDIF
race.objErrantBuoy2 = GET_CLOSEST_OBJECT_OF_TYPE((<<-1339.0514, -1975.6548, -8.6079>>), 20.0, prop_dock_bouy_2)
IF DOES_ENTITY_EXIST(race.objErrantBuoy2)
SET_ENTITY_VISIBLE(race.objErrantBuoy2, FALSE)
SET_ENTITY_COLLISION(race.objErrantBuoy2, FALSE)
CPRINTLN(DEBUG_TRIATHLON, "Attmepting to 'remove' objErrantBuoy2!")
ENDIF
// INIT_TRI_BLOCKING_AREAS(eCurrentTriRace)
// Activate scenario groups
IF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_ALAMO_SEA)
SET_SCENARIO_GROUP_ENABLED("Triathlon_1_Start", FALSE)
SET_SCENARIO_GROUP_ENABLED("Triathlon_1", TRUE)
SET_EXCLUSIVE_SCENARIO_GROUP("Triathlon_1")
szExlusiveScenarioGroup = "Triathlon_1"
ELIF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_VESPUCCI)
SET_SCENARIO_GROUP_ENABLED("Triathlon_2_Start", FALSE)
SET_SCENARIO_GROUP_ENABLED("Triathlon_2", TRUE)
SET_EXCLUSIVE_SCENARIO_GROUP("Triathlon_2")
szExlusiveScenarioGroup = "Triathlon_2"
ELIF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_IRONMAN)
SET_SCENARIO_GROUP_ENABLED("Triathlon_3_Start", FALSE)
SET_SCENARIO_GROUP_ENABLED("Triathlon_3", TRUE)
SET_EXCLUSIVE_SCENARIO_GROUP("Triathlon_3")
szExlusiveScenarioGroup = "Triathlon_3"
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_FADE_OUT to TRI_MAIN_SETUP_LOAD_INIT.")
TRI_Main.eSetup = TRI_MAIN_SETUP_LOAD_INIT
ENDIF
ENDIF
BREAK
// Load scene and assets.
CASE TRI_MAIN_SETUP_LOAD_INIT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] TRI_MAIN_SETUP_LOAD_INIT started.")
// Load Triathlon assets and waypoint recordings. Make sure these are requested before loading the race start area scene.
REQUEST_TRI(race)
// Load race start area scene.
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), vScriptStartPos) > 1000
LOAD_SCENE(vScriptStartPos)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] TRI_MAIN_SETUP_LOAD_INIT: Loading race start area scene.")
ENDIF
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_LOAD_INIT to TRI_MAIN_SETUP_LOAD_WAIT")
TRI_Main.eSetup = TRI_MAIN_SETUP_LOAD_WAIT
BREAK
// Wait until all requested assets are loaded.
CASE TRI_MAIN_SETUP_LOAD_WAIT
IF HAVE_TRI_ASSETS_LOADED() AND HAVE_TRI_WAYPOINT_RECORDINGS_LOADED(race)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_LOAD_WAIT to TRI_MAIN_SETUP_CREATE_INIT")
TRI_Main.eSetup = TRI_MAIN_SETUP_CREATE_INIT
ENDIF
BREAK
// Create any entities here.
CASE TRI_MAIN_SETUP_CREATE_INIT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] TRI_MAIN_SETUP_CREATE_INIT started.")
// Create the triathlon race banners
CREATE_TRI_RACE_BANNERS(TRI_Master.iRaceCur)
// Create the swim leg buoys
CREATE_TRI_SWIM_LEG_BUOYS(TRI_Master.iRaceCur, TRI_Race)
// Restart timer to allow the creation of entities to complete.
RESTART_TIMER_NOW(TRI_Main.tSetup)
// Create the Chase Heli
SETUP_TRI_CHASE_HELI(eCurrentTriRace, TRUE)
// Create Triathlon cameras.
CREATE_TRI_CAMERAS(vehChopper)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_CREATE_INIT to TRI_MAIN_SETUP_CREATE_WAIT.")
TRI_Main.eSetup = TRI_MAIN_SETUP_CREATE_WAIT
BREAK
// Wait for the creation of any entities to complete.
CASE TRI_MAIN_SETUP_CREATE_WAIT
IF TIMER_DO_WHEN_READY(TRI_Main.tSetup, 0.5)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_CREATE_WAIT to TRI_MAIN_SETUP_PLACE_INIT.")
TRI_Main.eSetup = TRI_MAIN_SETUP_PLACE_INIT
ENDIF
BREAK
// Initialize placing of race entities.
CASE TRI_MAIN_SETUP_PLACE_INIT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] CASE TRI_MAIN_SETUP_PLACE_INIT started.")
// Teleport player to script start position/heading.
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] CASE TRI_MAIN_SETUP_PLACE_INIT: Warping player to script start position/heading.")
//SET_ENTITY_COORDS(PLAYER_PED_ID(), vScriptStartPos)
// Reset gameplay camera behind player.
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
SET_GAMEPLAY_CAM_RELATIVE_PITCH(-10.0)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_PLACE_INIT to TRI_MAIN_SETUP_PLACE_WAIT.")
TRI_Main.eSetup = TRI_MAIN_SETUP_PLACE_WAIT
RESTART_TIMER_NOW(TRI_Main.tSetup)
BREAK
// Wait for placing race entities to finish.
CASE TRI_MAIN_SETUP_PLACE_WAIT
IF TIMER_DO_WHEN_READY(TRI_Main.tSetup, 0.5)
CANCEL_TIMER(TRI_Main.tSetup)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] From TRI_MAIN_SETUP_PLACE_WAIT to TRI_MAIN_SETUP_CLEANUP.")
TRI_Main.eSetup = TRI_MAIN_SETUP_CLEANUP
ENDIF
BREAK
// Setup completed, no longer running.
CASE TRI_MAIN_SETUP_CLEANUP
ENABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_VEH_EXIT )
IF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_ALAMO_SEA)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] SET_PED_NON_CREATION_AREA((<<2366.7698, 4255.2466, 30.3808>>), (<<2426.4705, 4332.7119, 35.2440>>))")
SET_PED_NON_CREATION_AREA((<<2366.7698, 4255.2466, 30.3808>>), (<<2426.4705, 4332.7119, 35.2440>>))
ELIF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_VESPUCCI)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] SET_PED_NON_CREATION_AREA((<<-1289.1494, -2066.1929, 6.1378>>), (<<-1269.3679, -2017.1382, 0.8296>>))")
SET_PED_NON_CREATION_AREA((<<-1289.1494, -2066.1929, 6.1378>>), (<<-1269.3679, -2017.1382, 0.8296>>))
ELIF TRI_Master.iRaceCur = ENUM_TO_INT(TRIATHLON_RACE_IRONMAN)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] SET_PED_NON_CREATION_AREA((<<1564.8250, 3830.0955, 31.0710>>), (<<1605.5154, 3832.3665, 32.9927>>))")
SET_PED_NON_CREATION_AREA((<<1564.8250, 3830.0955, 31.0710>>), (<<1605.5154, 3832.3665, 32.9927>>))
ENDIF
// SET_TRI_SCENARIO_PAPARAZZI_PEDS()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Setup] TRI_MAIN_SETUP_CLEANUP: Setup has completed. No longer running. Exiting setup state machine.")
RETURN FALSE
BREAK
ENDSWITCH
// Setup is still running.
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Update the main Triathlon loop.
///
/// RETURNS:
/// TRUE if Triathlon loop is still updating.
FUNC BOOL UPDATE_TRIATHLON(INT &iMusicFlags, CAMERA_INDEX &camTriSky)
UPDATE_TRI_DISABLED_CONTROLS()
// Check if the player is dead every frame.
IF IS_ENTITY_DEAD(PLAYER_PED_ID())
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->UPDATE_TRIATHLON] The player is dead. Stop updating Triathlon.")
RETURN FALSE
ENDIF
// Keep boats and the like from spawning near the race
SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0.0)
SET_PED_DENSITY_MULTIPLIER_THIS_FRAME(0.0)
IF NOT bCheated
IF IS_CHEAT_ACTIVE( CHEAT_TYPE_FAST_RUN )
OR IS_CHEAT_ACTIVE( CHEAT_TYPE_FAST_SWIM )
bCheated = TRUE
ENDIF
ENDIF
// Update main Triathlon state machine.
SWITCH (TRI_Main.eUpdate)
// Set up race parameters that will change throughout the race. If player restarts, script will jump back here.
CASE TRI_MAIN_UPDATE_INIT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] CASE TRI_MAIN_UPDATE_INIT started.")
// Setup Triathlon. This will also be called on player restart, so this is
// a good place to reset values and states that change over the course of the race.
SETUP_TRIATHLON()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_INIT to TRI_MAIN_UPDATE_SETUP_RACE_INIT")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_SETUP_RACE_INIT
BREAK
// Create the Triathlon race, competitors, etc.
CASE TRI_MAIN_UPDATE_SETUP_RACE_INIT
// Signal the SPR system to initialize and create the Triathlon entities.
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] CASE TRI_MAIN_UPDATE_SETUP_RACE_INIT: TRI_Race eSetup set to TRI_RACE_SETUP_INIT.")
TRI_Race.eSetup = TRI_RACE_SETUP_INIT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_SETUP_RACE_INIT to TRI_MAIN_UPDATE_SETUP_RACE_WAIT.")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_SETUP_RACE_WAIT
BREAK
// Set up entity-dependent elements of the race after Triathlon entities have been created.
CASE TRI_MAIN_UPDATE_SETUP_RACE_WAIT
// Wait until the Triathlon entities have been created before continuing.
IF NOT TRI_Race_Setup(TRI_Race)
// Create and place the Triathlon bikes, and assign them to each racer.
CREATE_TRI_BIKES(TRI_Race)
// Set up the racers's AI now that entities were created.
SETUP_TRI_AI(TRI_Race)
// Store the player's heading.
IF NOT IS_ENTITY_DEAD(TRI_Race.Racer[0].Driver)
fPlayerHeading = GET_ENTITY_HEADING(TRI_Race.Racer[0].Driver)
ENDIF
// Start a timer to allow the cutscene to play without a pop.
START_TIMER_AT(timerBeforeIntroCutscene, 0.0)
// Check if race is restarting.
IF IS_TRI_CONTROL_FLAG_SET(TCF_RACE_RESTARTING)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] TRI_MAIN_UPDATE_SETUP_RACE_WAIT: Race is restaring. Skip cutscene.")
// Set the camera behind the player before the screen fades in.
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), vScriptStartPos) > 1000
// Load script start area.
LOAD_SCENE(vScriptStartPos)
CPRINTLN(DEBUG_TRIATHLON, "LOAD_SCENE :: TRI_MAIN_UPDATE_SETUP_RACE_WAIT")
ENDIF
eCurrentCutsceneStage = TRI_CUTSCENE_STAGE_HELI_CREATE
SET_TRI_CONTROL_FLAG(TCF_TRI_SKIPPED_CUTSCENE)
// CLEAR_TRI_CONTROL_FLAG(TCF_RACE_RESTARTING)
//
// CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_SETUP_RACE_WAIT to TRI_MAIN_UPDATE_FADE_IN.")
// TRI_Main.eUpdate = TRI_MAIN_UPDATE_ORCUT_LOAD
ENDIF
eCurrentCutsceneStage = TRI_CUTSCENE_STAGE_SETUP
ODDJOB_ENTER_CUTSCENE(DEFAULT,DEFAULT,FALSE) //Don't enable multihead blinders
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_SETUP_RACE_WAIT to TRI_MAIN_UPDATE_ORCUT_LOAD.")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_ORCUT_LOAD
ENDIF
BREAK
// Play cutscene.
CASE TRI_MAIN_UPDATE_ORCUT_LOAD
DISPLAY_RADAR(FALSE)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
Tri_Cutscenes_Play_Intro(vScriptStartPos, TRI_Race, fPlayerHeading, camTriSky, vehChopper, pedPilot)
IF NOT IS_TRI_CONTROL_FLAG_SET(TCF_TRI_CUTSCENE_PLAYING)
DISPLAY_RADAR(TRUE)
// Destroy intro cutscene cameras.
DESTROY_TRI_INTRO_CUTSCENE_CAMERAS()
IF DOES_CAM_EXIST(camTriSky)
DESTROY_CAM(camTriSky)
ENDIF
//TRI_Race.eSetup = TRI_RACE_SETUP_INIT
//eCurrentCutsceneStage = TRI_CUTSCENE_STAGE_SETUP
CPRINTLN(DEBUG_TRIATHLON, "TRI_MAIN_UPDATE ORCUT: Moving to UPDATE_FADE_IN")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_FADE_IN
ENDIF
BREAK
// Fade into the game before intro cutscene plays, or after player chooses to restart race.
CASE TRI_MAIN_UPDATE_FADE_IN
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
// If we're skipping the cutscene as a result of a restart, fade quicker into the race.
IF IS_TRI_CONTROL_FLAG_SET(TCF_SKIP_INTRO_ON_RESTART)
iFadeInMilsecToRaceStart = 500
ELIF
iFadeInMilsecToRaceStart = 1000
// B*-2255133
//If the player has managed to get a wanted level and start the triathlon (not restart), clear the wanted level.
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0)
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
ENDIF
ENDIF
// Wait until fade-in is complete.
IF TRI_FadeIn_Safe(iFadeInMilsecToRaceStart)
// Start the AI timer immediately.
START_TIMER_AT(timerToUpdateAI, fSecondsBeforeUpdateAIAgain)
// Start timer for managing player and racer dialog.
START_TIMER_AT(timerAnyDialogCanPlay, TriDialog.fSecondsBeforeDialogSystemStarts)
START_TIMER_AT(timerPlayerStayInPlaceDialogCanPlay, TriDialog.fSecondsBeforeDialogSystemStarts)
START_TIMER_AT(timerPlayerStayFirstDialogCanPlay, TriDialog.fSecondsBeforeDialogSystemStarts)
START_TIMER_AT(timerPlayerStaySecondDialogCanPlay, TriDialog.fSecondsBeforeDialogSystemStarts)
START_TIMER_AT(timerPlayerStayLastDialogCanPlay, TriDialog.fSecondsBeforeDialogSystemStarts)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From Main Update: TRI_MAIN_UPDATE_FADE_IN to Race Update: TRI_RACE_UPDATE_INIT")
TRI_Race.eUpdate = TRI_RACE_UPDATE_INIT
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_FADE_IN to TRI_MAIN_UPDATE_WAIT")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_WAIT
ENDIF
BREAK
// Main race loop.
CASE TRI_MAIN_UPDATE_WAIT
// If in Debug Mode, update SPR Main Widget.
#IF IS_DEBUG_BUILD
// Check if SPR Main Widget is done updating.
IF NOT TRI_Widget_Main_Update(TRI_Widget)
// If SPR Mode is Race, reset Race.
IF (TRI_Widget_Listbox_Get(TRI_Widget.TRIMode) = 0)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SPR_Main_Update] From SPR_MAIN_UPDATE_WAIT to SPR_RACE_UPDATE_CLEANUP.")
TRI_Race.eUpdate = TRI_RACE_UPDATE_CLEANUP
CANCEL_TIMER(TRI_Race.tUpdate)
// Otherwise, if SPR Mode is Edit, cleanup Race.
ELSE
TRI_Race_Cleanup(TRI_Race, TRUE)
ENDIF
ENDIF
// Set SPR Mode according to value in SPR Main Widget.
TRI_Main.iTRIMode = TRI_Widget_Listbox_Get(TRI_Widget.TRIMode)
#ENDIF
// If SPR Mode isn't Edit, update SPR Race.
IF NOT (TRI_Main.iTRIMode = 1)
// Check if TRI_Race is not updating anymore. If it is, clean up the race.
IF NOT TRI_Race_Update(TRI_Race)
// Reset Triathlon to its initial state.
RESET_TRI(IS_TRI_CONTROL_FLAG_SET(TCF_RACE_RESTARTING))
IF IS_TRI_CONTROL_FLAG_SET(TCF_RACE_RESTARTING)
// Reset the triathlon chase helicopter
RESET_TRI_CHASE_HELI(TRI_Race.sGate[0].vPos + (<<0,0,50>>))
ENDIF
// If current race is still valid, restart the race.
IF IS_TRI_CONTROL_FLAG_SET(TCF_RACE_RESTARTING)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_WAIT to TRI_MAIN_UPDATE_CHOOSE_RACE.")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_INIT
#IF IS_DEBUG_BUILD
S_SKIP_ACTIVATED = FALSE
#ENDIF
// Otherwise, race isn't valid. Clean up main.
ELSE
BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_TRI)//increment number of triathalons participated in
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] From TRI_MAIN_UPDATE_WAIT to TRI_MAIN_UPDATE_CLEANUP.")
TRI_Main.eUpdate = TRI_MAIN_UPDATE_CLEANUP
STOP_TRI_BIG_CHEERS(TRI_Race)
ENDIF
ENDIF
// Update Triathlon from start to end of the race every frame.
IF TRI_Race.eUpdate = TRI_RACE_UPDATE_WAIT
UPDATE_TRIATHLON_DURING_RACE(iMusicFlags)
ENDIF
ENDIF
BREAK
// We're done with the Triathlon script. Clean up the whole script before terminating.
CASE TRI_MAIN_UPDATE_CLEANUP
BOOL bExit
FLOAT fAllowBreakPhase
IF GET_PLAYER_PED_ENUM(PLAYER_PED_ID()) = CHAR_MICHAEL
fAllowBreakPhase = 0.5
ELIF GET_PLAYER_PED_ENUM(PLAYER_PED_ID()) = CHAR_FRANKLIN
fAllowBreakPhase = 0.73
ELIF GET_PLAYER_PED_ENUM(PLAYER_PED_ID()) = CHAR_TREVOR
fAllowBreakPhase = 0.495
ELSE
fAllowBreakPhase = 0.75 // If character ped is wrong, pick safe phase for threshold
ENDIF
IF IS_SYNCHRONIZED_SCENE_RUNNING(sOutroSceneData.iOutroSceneID)
IF (GET_DISABLED_CONTROL_NORMAL(PLAYER_CONTROL, INPUT_MOVE_LR) > 0.2
OR GET_DISABLED_CONTROL_NORMAL(PLAYER_CONTROL, INPUT_MOVE_LR) < -0.2
OR GET_DISABLED_CONTROL_NORMAL(PLAYER_CONTROL, INPUT_MOVE_UD) > 0.2
OR GET_DISABLED_CONTROL_NORMAL(PLAYER_CONTROL, INPUT_MOVE_UD) < -0.2)
AND GET_SYNCHRONIZED_SCENE_PHASE(sOutroSceneData.iOutroSceneID) > fAllowBreakPhase
bExit = TRUE
ENDIF
ENDIF
IF NOT IS_TRI_CONTROL_FLAG_SET(TCF_FINISHED_RACE) OR (IS_SYNCHRONIZED_SCENE_RUNNING(sOutroSceneData.iOutroSceneID) AND GET_SYNCHRONIZED_SCENE_PHASE(sOutroSceneData.iOutroSceneID) >= 1.0)
OR bExit
CLEANUP_TRI_BEFORE_TERMINATING_SCRIPT(Tri_Race, FALSE)
IF DOES_CAM_EXIST(camIntroIECam)
CLEAR_PED_TASKS(PLAYER_PED_ID())
CPRINTLN(DEBUG_TRIATHLON, "CASE TRI_MAIN_UPDATE_CLEANUP :: STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()")
IF IS_PED_ON_FOOT(PLAYER_PED_ID())
IF NOT bExit
//do nothing
ELSE
FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_WALK, TRUE)
SIMULATE_PLAYER_INPUT_GAIT(PLAYER_ID(), PEDMOVEBLENDRATIO_WALK, 500)
ENDIF
ENDIF
IF IS_CAM_RENDERING(camIntroIECam)
DEBUG_PRINTCALLSTACK()
STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP()
ENDIF
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
ENDIF
/*
SWITCH( eCurrentTriRace )
CASE TRIATHLON_RACE_VESPUCCI
IF IS_IPL_ACTIVE("AP1_04_TriAf01")
REMOVE_IPL("AP1_04_TriAf01")
ENDIF
IF IS_IPL_ACTIVE("VB_08_TriAf01")
REMOVE_IPL("VB_08_TriAf01")
ENDIF
BREAK
CASE TRIATHLON_RACE_ALAMO_SEA
IF IS_IPL_ACTIVE("CS2_06_TriAf02")
REMOVE_IPL("CS2_06_TriAf02")
ENDIF
IF IS_IPL_ACTIVE("CS4_08_TriAf02")
REMOVE_IPL("CS4_08_TriAf02")
ENDIF
BREAK
CASE TRIATHLON_RACE_IRONMAN
IF IS_IPL_ACTIVE("CS4_04_TriAf03")
REMOVE_IPL("CS4_04_TriAf03")
ENDIF
IF IS_IPL_ACTIVE("CH1_07_TriAf03")
REMOVE_IPL("CH1_07_TriAf03")
ENDIF
BREAK
ENDSWITCH
*/
// The main race loop is no longer running running.
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->TRI_Main_Update] TRI_MAIN_UPDATE_CLEANUP: The main race loop is no longer running running. Exiting main loop.")
RETURN FALSE
ENDIF
BREAK
ENDSWITCH
// The main race loop is still running.
RETURN TRUE
ENDFUNC
FUNC BOOL VALIDATE_TRI_CAN_CLEANUP()
IF IS_MESSAGE_BEING_DISPLAYED()
RETURN FALSE
ENDIF
IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), "mini@triathlon", "rummage_bag")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
PROC UPDATE_TRI_TOP_OF_FRAME()
IF IS_TRI_CONTROL_FLAG_SET(TCF_UNPATCH_CORONA)
// UNPATCH_DECAL_DIFFUSE_MAP(DECAL_RSID_TRIATHLON_SWIMMING)
// UNPATCH_DECAL_DIFFUSE_MAP(DECAL_RSID_TRIATHLON_CYCLING)
// UNPATCH_DECAL_DIFFUSE_MAP(DECAL_RSID_TRIATHLON_RUNNING)
CLEAR_TRI_CONTROL_FLAG(TCF_UNPATCH_CORONA)
ENDIF
ENDPROC
// ======================================
// E N D STATE MACHINES
// ======================================
// ======================================
// TRIATHLON RACES SCRIPT BLOCK
// ======================================
/// PURPOSE:
/// Triathlon Races starts here.
SCRIPT(TRIATHLON_LAUNCH_DATA triLaunchData)
CPRINTLN(DEBUG_TRIATHLON, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Triathlon First Post ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^")
IF HAS_FORCE_CLEANUP_OCCURRED(DEFAULT_FORCE_CLEANUP_FLAGS|FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_REPEAT_PLAY)
CPRINTLN(DEBUG_TRIATHLON, "Force cleanup occurred in Triathlon")
//RESTORE_PLAYER_PED_VARIATIONS(PLAYER_PED_ID())
//SET_PED_VARIATIONS( PLAYER_PED_ID(), Tri_Master.sPlayerVariation )
// Cleanup Triathlon and SPR system, and terminate the script.
CLEANUP_ALL_AND_TERMINATE_TRIATHLON(Tri_Race)
ENDIF
INT iMusicFlags
TEXT_LABEL_23 emptyLabel = "NONE"
MINIGAME_DISPLAY_MISSION_TITLE(ENUM_TO_INT(MINIGAME_TRIATHLON))
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(FALSE)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0)
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
ENDIF
// Initialize Triathlon state machines.
TRI_Main.eRun = TRI_MAIN_RUN_SETUP
TRI_Main.eSetup = TRI_MAIN_SETUP_INIT
TRI_Main.eUpdate = TRI_MAIN_UPDATE_INIT
TRI_Main.eStartCam = GET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT)
CAMERA_INDEX camTriSky
// Set up the debug stage menu.
#IF IS_DEBUG_BUILD
INIT_TRI_DEBUG()
//TRACE_NATIVE_COMMAND("WAIT")
#ENDIF
// Triathlon Races main loop.
WHILE TRUE
DRAW_DEBUG_BOX((<<2366.7698, 4255.2466, 30.3808>>), (<<2426.4705, 4332.7119, 35.2440>>), default, default, default, 100)
UPDATE_MISSION_NAME_DISPLAYING(emptyLabel)
UPDATE_TRI_TOP_OF_FRAME()
SWITCH (TRI_Main.eRun)
CASE TRI_MAIN_RUN_SETUP
IF NOT SETUP_TRI_SYSTEM(triLaunchData, camTriSky, TRI_Race)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SCRIPT] TRI_Main_Setup finished or stopped setting up SPR Main.")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SCRIPT] From TRI_MAIN_RUN_SETUP To TRI_MAIN_RUN_UPDATE.")
TRI_Main.eRun = TRI_MAIN_RUN_UPDATE
ENDIF
BREAK
CASE TRI_MAIN_RUN_UPDATE
// UPDATE_NAV_AROUND_TRIATHLON_PROPS()
IF NOT UPDATE_TRIATHLON(iMusicFlags, camTriSky)
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SCRIPT] TRI_Main_Update finished or stopped updating SPR Main.")
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SCRIPT] From TRI_MAIN_RUN_UPDATE To TRI_MAIN_RUN_CLEANUP.")
TRI_Main.eRun = TRI_MAIN_RUN_CLEANUP
ENDIF
BREAK
CASE TRI_MAIN_RUN_CLEANUP
IF VALIDATE_TRI_CAN_CLEANUP()
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SCRIPT] TRI_MAIN_RUN_CLEANUP: No god text is displayed. Clean up SPR Main.")
CLEANUP_TRI_SYSTEM_AND_TERMINATE_TRIATHLON()
ENDIF
BREAK
ENDSWITCH
// Process any Triathlon debug functionality.
#IF IS_DEBUG_BUILD
IF NOT S_SKIP_ACTIVATED
UPDATE_TRI_DEBUG()
ENDIF
IF IS_CHEATING_ENABLED
DISPLAY_TEXT_WITH_LITERAL_STRING(0.3, 0.858, "STRING", "hacks enabled")
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_PAD_UP) OR IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_PAD_UP)
CDEBUG2LN(DEBUG_TRIATHLON, "Debug demanding the destruction of the new chopper")
DESTROY_NEWS_CHOPPER = TRUE
ENDIF
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_PAD_DOWN) OR IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_PAD_DOWN)
CPRINTLN(DEBUG_TRIATHLON, "TRIATHLON RACER STATUS:")
CPRINTLN(DEBUG_TRIATHLON, "Racer[0] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[0].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[0].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[1] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[1].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[1].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[2] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[2].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[2].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[3] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[3].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[3].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[4] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[4].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[4].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[5] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[5].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[5].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[6] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[6].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[6].iGateCur)
CPRINTLN(DEBUG_TRIATHLON, "Racer[7] ped index exists: ", PICK_STRING(DOES_ENTITY_EXIST(TRI_Race.Racer[7].Driver), "TRUE", "FALSE"), ", iGateCur=", TRI_Race.Racer[7].iGateCur)
ENDIF
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_PAD_LEFT) OR IS_DISABLED_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_PAD_LEFT)
// nothing
ENDIF
ENDIF
TEXT_LABEL_23 texNum
INT iRacerCounter = 0
REPEAT 8 iRacerCounter
texNum = "Racer_"
texNum += iRacerCounter
IF DOES_ENTITY_EXIST(TRI_Race.Racer[iRacerCounter].Driver) AND NOT IS_PED_INJURED(TRI_Race.Racer[iRacerCounter].Driver)
DEBUG_RECORD_ENTITY(TRI_Race.Racer[iRacerCounter].Driver)
DEBUG_RECORD_ENTITY_STRING(TRI_Race.Racer[iRacerCounter].Driver, texNum, texNum)
DEBUG_RECORD_ENTITY_FLOAT(TRI_Race.Racer[iRacerCounter].Driver, texNum, TO_FLOAT(iRacerCounter))
ENDIF
ENDREPEAT
ENTITY_INDEX entRecordMe = PLAYER_PED_ID()
DEBUG_RECORD_ENTITY(entRecordMe)
DEBUG_RECORD_ENTITY_STRING(entRecordMe, "Player", "myPlayer")
DEBUG_RECORD_ENTITY_FLOAT(entRecordMe, "Player", 0)
#ENDIF
// Wait until next frame.
WAIT(0)
ENDWHILE
REMOVE_NAV_BLOCKING_OBJECTS()
// The script should never reach here.
CPRINTLN(DEBUG_TRIATHLON, "[TriathlonSP.sc->SCRIPT] (!) ERROR (!): Script exited main game loop and reached ENDSCRIPT.")
ENDSCRIPT
// ======================================
// E N D TRIATHLON RACES SCRIPT BLOCK
// ======================================
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// END OF FILE - DO NOT ADD ANYTHING BELOW THIS BLOCK!
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************