// ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // 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! // // ***************************************************************************************** // ***************************************************************************************** // *****************************************************************************************