4850 lines
188 KiB
Python
Executable File
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!
|
|
//
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|