// This section holds most/all of the USINGS for native commands and commonly used script helpers USING "rage_builtins.sch" USING "globals.sch" USING "commands_audio.sch" USING "commands_camera.sch" USING "commands_event.sch" USING "commands_clock.sch" USING "commands_debug.sch" USING "commands_fire.sch" USING "commands_graphics.sch" USING "commands_hud.sch" USING "commands_misc.sch" USING "commands_object.sch" USING "commands_pad.sch" USING "commands_player.sch" USING "commands_script.sch" USING "commands_streaming.sch" USING "commands_task.sch" USING "commands_vehicle.sch" USING "commands_interiors.sch" USING "commands_entity.sch" USING "commands_physics.sch" USING "script_maths.sch" USING "script_blips.sch" USING "script_ped.sch" USING "script_player.sch" USING "script_misc.sch" USING "script_drawing.sch" USING "locates_public.sch" USING "timer_public.sch" USING "mission_control_public.sch" USING "brains.sch" USING "ambience_run_checks.sch" USING "flow_public_core_override.sch" USING "model_enums.sch" USING "help_at_location.sch" USING "load_queue_public.sch" /// PURPOSE: Enumeration for control types for minigame players so minigames can be used in both SP and MP ENUM PLAYER_CONTROL_TYPE CONTROL_NONE, HUMAN_LOCAL, HUMAN_LOCAL_MP, HUMAN_NETWORK, COMPUTER ENDENUM /// PURPOSE: /// Helper function to get a color that matches hud /// PARAMS: /// hudColor - The hud color you want to match /// RETURNS: /// The INT_COLOR of the hud color you pass in FUNC INT GetTextColor(HUD_COLOURS hudColor, INT iAlpha = -1) INT iR,iG,iB,iA GET_HUD_COLOUR(hudColor, iR, iG, iB, iA) IF iAlpha = -1 RETURN INT_COLOUR(iR, iG, iB, iA) ELSE RETURN INT_COLOUR(iR, iG, iB, iAlpha) ENDIF ENDFUNC /// PURPOSE: /// Procedure that prints an integer as bits to the console (NOT the game screen) /// Goes from most significant bit to least. /// You'll need to follow it with PRINTNL() if you want to PROC PRINTBITS(INT bits, INT spacing = 4) INT i FOR i=31 TO 0 STEP -1 IF IS_BIT_SET( bits, i) PRINTINT(1) ELSE PRINTINT(0) ENDIF IF i%spacing = 0 AND i > 0 PRINTSTRING(" ") ENDIF ENDFOR ENDPROC //FUNC CONTROL_ACTION TRANSLATE_INSTR_BUTTON_TO_CONTROL_ACTION(TEXT_LABEL_63 instrButton) // SWITCH(instrButton) // CASE ICON_LSTICK_LEFTRIGHT // RETURN INPUT_FRONTEND_AXIS_X //LEFTSTICKX // BREAK // CASE ICON_LSTICK_UPDOWN // RETURN INPUT_FRONTEND_AXIS_Y //LEFTSTICKY // BREAK // CASE ICON_RSTICK_LEFTRIGHT // RETURN INPUT_FRONTEND_RIGHT_AXIS_X //RIGHTSTICKX // BREAK // CASE ICON_RSTICK_UPDOWN // RETURN INPUT_FRONTEND_RIGHT_AXIS_Y //RIGHTSTICKY // BREAK // CASE ICON_UP // CASE ICON_DPAD_UP // RETURN INPUT_FRONTEND_UP // BREAK // CASE ICON_DOWN // CASE ICON_DPAD_DOWN // RETURN INPUT_FRONTEND_DOWN // BREAK // CASE ICON_LEFT // CASE ICON_DPAD_LEFT // RETURN INPUT_FRONTEND_LEFT // BREAK // CASE ICON_RIGHT // CASE ICON_DPAD_RIGHT // RETURN INPUT_FRONTEND_RIGHT // BREAK // CASE ICON_BUTTON_START // RETURN INPUT_FRONTEND_PAUSE // BREAK // CASE ICON_BUTTON_BACK // RETURN INPUT_FRONTEND_SELECT // BREAK // CASE ICON_BUTTON_X // RETURN INPUT_FRONTEND_X // BREAK // CASE ICON_BUTTON_Y // RETURN INPUT_FRONTEND_Y // BREAK // CASE ICON_BUTTON_A // RETURN INPUT_FRONTEND_ACCEPT // BREAK // CASE ICON_BUTTON_B // RETURN INPUT_FRONTEND_CANCEL // BREAK // //CASE ICON_LSTICK_NONE // // //RETURN ? //LEFTSHOCK // //BREAK // //CASE ICON_RSTICK_NONE // // //RETURN ? //RIGHTSHOCK // //BREAK // CASE ICON_BUTTON_LB // RETURN INPUT_FRONTEND_LB // BREAK // CASE ICON_BUTTON_LT // RETURN INPUT_FRONTEND_LT // BREAK // CASE ICON_BUTTON_RB // RETURN INPUT_FRONTEND_RB // BREAK // CASE ICON_BUTTON_RT // RETURN INPUT_FRONTEND_RT // BREAK // ENDSWITCH // // RETURN INT_TO_ENUM(CONTROL_ACTION, -1) //ENDFUNC /// PURPOSE: /// Gets a random float in [mean-deviation, mean+deviation]. Uses trig functions to cluster these around mean and spreads out toward +-deviation. /// PARAMS: /// mean - Value to cluster the randoms around /// deviation - maximum deviator away from mean /// RETURNS: /// A random value in in [mean-deviation, mean+deviation], tending to cluster around mean. FUNC FLOAT GET_RANDOM_FLOAT_POLAR(FLOAT mean = 0.0, FLOAT deviation = 1.0) FLOAT randTri = SIN(GET_RANDOM_FLOAT_IN_RANGE(-180.0, 180)) IF randTri < 0 randTri++ ELSE randTri-- ENDIF RETURN mean + randTri * deviation ENDFUNC /// PURPOSE: /// Fades down and lets us know when it's complete. /// RETURNS: /// TRUE when fully faded. FUNC BOOL FADE_DOWN(INT iFadeTime = DEFAULT_FADE_TIME) DO_SCREEN_FADE_OUT(iFadeTime) WHILE NOT IS_SCREEN_FADED_OUT() WAIT(0) ENDWHILE RETURN TRUE ENDFUNC /// PURPOSE: /// Fades up and lets us know when it's complete. /// RETURNS: /// TRUE when fully faded. FUNC BOOL FADE_UP(INT iFadeTime = DEFAULT_FADE_TIME) DO_SCREEN_FADE_IN(iFadeTime) WHILE NOT IS_SCREEN_FADED_IN() WAIT(0) ENDWHILE RETURN TRUE ENDFUNC /// PURPOSE: /// Make an array of strings point at an array of text labels. PROC POINT_STRINGS_AT_TEXT_LABEL_3(STRING& sStrings[], TEXT_LABEL_3& sLabels[], INT iStrings) INT iCounter REPEAT iStrings iCounter sStrings[iCounter] = TEXT_LABEL_TO_STRING(sLabels[iCounter]) ENDREPEAT ENDPROC /// PURPOSE: /// Make an array of strings point at an array of text labels. PROC POINT_STRINGS_AT_TEXT_LABEL_7(STRING& sStrings[], TEXT_LABEL_7& sLabels[], INT iStrings) INT iCounter REPEAT iStrings iCounter sStrings[iCounter] = TEXT_LABEL_TO_STRING(sLabels[iCounter]) ENDREPEAT ENDPROC /// PURPOSE: /// Make an array of strings point at an array of text labels. PROC POINT_STRINGS_AT_TEXT_LABEL_15(STRING& sStrings[], TEXT_LABEL_15& sLabels[], INT iStrings) INT iCounter REPEAT iStrings iCounter sStrings[iCounter] = TEXT_LABEL_TO_STRING(sLabels[iCounter]) ENDREPEAT ENDPROC /// PURPOSE: /// Make an array of strings point at an array of text labels. PROC POINT_STRINGS_AT_TEXT_LABEL_23(STRING& sStrings[], TEXT_LABEL_23& sLabels[], INT iStrings) INT iCounter REPEAT iStrings iCounter sStrings[iCounter] = TEXT_LABEL_TO_STRING(sLabels[iCounter]) ENDREPEAT ENDPROC /// PURPOSE: /// Make an array of strings point at an array of text labels. PROC POINT_STRINGS_AT_TEXT_LABEL_31(STRING& sStrings[], TEXT_LABEL_31& sLabels[], INT iStrings) INT iCounter REPEAT iStrings iCounter sStrings[iCounter] = TEXT_LABEL_TO_STRING(sLabels[iCounter]) ENDREPEAT ENDPROC /// PURPOSE: /// Make an array of strings point at an array of text labels. PROC POINT_STRINGS_AT_TEXT_LABEL_63(STRING& sStrings[], TEXT_LABEL_63& sLabels[], INT iStrings) INT iCounter REPEAT iStrings iCounter sStrings[iCounter] = TEXT_LABEL_TO_STRING(sLabels[iCounter]) ENDREPEAT ENDPROC /// PURPOSE: /// Prints the name of the script, and then the printed message /// PARAMS: /// strMessage - Message to print /// strMessage[2-6] - Optional messages to print /// separator - optional separator, will go between messages 2-6. DEBUGONLY PROC DEBUG_MESSAGE(STRING strMessage, STRING strMessage2 = NULL, STRING strMessage3 = NULL, STRING strMessage4 = NULL, STRING strMessage5 = NULL, STRING strMessage6 = NULL, STRING separator = NULL ) PRINTSTRING(GET_THIS_SCRIPT_NAME()) PRINTSTRING(": ") PRINTINT(GET_GAME_TIMER()) PRINTSTRING(": ") IF NOT IS_STRING_NULL( strMessage ) PRINTSTRING(strMessage) ENDIF IF NOT IS_STRING_NULL( strMessage2 ) PRINTSTRING( strMessage2 ) ENDIF IF NOT IS_STRING_NULL( separator ) PRINTSTRING( separator ) ENDIF IF NOT IS_STRING_NULL( strMessage3 ) PRINTSTRING( strMessage3 ) ENDIF IF NOT IS_STRING_NULL( separator ) PRINTSTRING( separator ) ENDIF IF NOT IS_STRING_NULL( strMessage4 ) PRINTSTRING( strMessage4 ) ENDIF IF NOT IS_STRING_NULL( separator ) PRINTSTRING( separator ) ENDIF IF NOT IS_STRING_NULL( strMessage5 ) PRINTSTRING( strMessage5 ) ENDIF IF NOT IS_STRING_NULL( separator ) PRINTSTRING( separator ) ENDIF IF NOT IS_STRING_NULL( strMessage6 ) PRINTSTRING( strMessage6 ) ENDIF PRINTNL() ENDPROC /// PURPOSE: /// Convert a given vector into a printable string format. Similar (but clunkier) usage to V2STR from RDR2. /// PARAMS: /// v - valid vector to be converted to prinatable format /// RETURNS: /// text label containing FUNC TEXT_LABEL_31 V2STR(VECTOR v) TEXT_LABEL_31 retVal = "<< " retVal += CEIL(v.x) retVal += ", " retVal += CEIL(v.y) retVal += ", " retVal += CEIL(v.z) retVal += " >>" RETURN retVal ENDFUNC /// PURPOSE: /// Prints the name of the script, and then the printed message. Throttles the given print to once a second /// PARAMS: /// strMessage - Message to print /// messageThrottle /// strMessage[2-6] - Optional messages to print /// separator - optional separator, will go between messages 2-6. /// throttleFrequency - sets how often it'll print (1 second or so) PROC DEBUG_MESSAGE_PERIODIC(STRING strMessage, INT &fMessageThrottle, STRING strMessage2 = NULL, STRING strMessage3 = NULL, STRING strMessage4 = NULL, STRING strMessage5 = NULL, STRING strMessage6 = NULL, STRING separator = NULL, INT throttleFrequency = 1000 ) IF GET_GAME_TIMER() < fMessageThrottle + throttleFrequency EXIT ENDIF fMessageThrottle = GET_GAME_TIMER() DEBUG_MESSAGE( strMessage, strMessage2, strMessage3, strMessage4, strMessage5, strMessage6, separator ) ENDPROC /// PURPOSE: /// Prints the name of the script, and then the printed message. Throttles the given print to once a second /// PARAMS: /// strMessage - Message to print /// messageThrottle /// throttleFrequency - sets how often it'll print (1 second or so) PROC CDEBUG_MESSAGE_OJ_TAXI_PERIODIC(STRING strMessage, INT &fMessageThrottle,INT throttleFrequency = 1000) IF GET_GAME_TIMER() < fMessageThrottle + throttleFrequency EXIT ENDIF fMessageThrottle = GET_GAME_TIMER() CDEBUG1LN(DEBUG_OJ_TAXI,strMessage) ENDPROC /// PURPOSE: /// Checks if a string is null/empty. /// PARAMS: /// sString - String to check if null/empty /// RETURNS: /// TRUE if string is null/empty, FALSE otherwise. FUNC BOOL IS_STRING_EMPTY(STRING sString) IF IS_STRING_NULL(sString) //DEBUG_MESSAGE("IS_STRING_EMPTY: String is null!") RETURN TRUE ENDIF IF (GET_LENGTH_OF_LITERAL_STRING(sString) <= 0) //DEBUG_MESSAGE("IS_STRING_EMPTY: String is empty!") RETURN TRUE ENDIF RETURN FALSE ENDFUNC //FUNC VECTOR CONVERT_ROTATION_TO_DIRECTION_VECTOR(VECTOR v_rot) // RETURN <<-SIN(v_rot.z) * COS(v_rot.x), COS(v_rot.z) * COS(v_rot.x), SIN(v_rot.x)>> //ENDFUNC /// PURPOSE: Struct for building streaming helpers (if needed) STRUCT STREAMED_MODEL MODEL_NAMES thisModel = DUMMY_MODEL_FOR_SCRIPT ENDSTRUCT /// PURPOSE: /// Finds the first uninitialized element in a streaming array. Returns -1 if the array is full. /// PARAMS: /// streamedModel - streaming array to search in /// RETURNS: /// The index of the first uninitialized element in a streaming array. -1 if the array is full. The return value must be tested before being used! FUNC INT GET_EMPTY_STREAMED_MODEL(STREAMED_MODEL &streamedModel[]) INT modelIndex REPEAT COUNT_OF(streamedModel) modelIndex IF streamedModel[modelIndex].thisModel = DUMMY_MODEL_FOR_SCRIPT // IS THIS THE CORRECT NULL CHECK?? RETURN modelIndex ENDIF ENDREPEAT RETURN -1 ENDFUNC /// PURPOSE: /// Adds a model to the first uninitialized element of a streaming array. /// PARAMS: /// streamedModel - Streaming array to add to /// newModel - MODEL_NAMES to add /// RETURNS: /// TRUE if the model was successfully added, FALSE otherwise (the array was full) FUNC BOOL ADD_STREAMED_MODEL(STREAMED_MODEL &streamedModel[], MODEL_NAMES newModel) INT iModelIndex REPEAT COUNT_OF(streamedModel) iModelIndex IF streamedModel[iModelIndex].thisModel != DUMMY_MODEL_FOR_SCRIPT IF streamedModel[iModelIndex].thisModel = newModel DEBUG_MESSAGE("ADD_STREAMED_MODEL returning FALSE, model already in the index") RETURN FALSE ENDIF ENDIF ENDREPEAT INT modelIndex = GET_EMPTY_STREAMED_MODEL(streamedModel) IF modelIndex < 0 OR modelIndex >= COUNT_OF(streamedModel) RETURN FALSE ENDIF streamedModel[modelIndex].thisModel = newModel RETURN TRUE ENDFUNC /// PURPOSE: /// Requests all initialized models in a streaming array /// PARAMS: /// streamedModel - Streaming array to request PROC REQUEST_ALL_MODELS(STREAMED_MODEL &streamedModel[]) INT modelIndex REPEAT COUNT_OF(streamedModel) modelIndex IF streamedModel[modelIndex].thisModel != DUMMY_MODEL_FOR_SCRIPT // IS THIS THE CORRECT NULL CHECK?? REQUEST_MODEL(streamedModel[modelIndex].thisModel) // REQUEST_COLLISION_FOR_MODEL(streamedModel[modelIndex].thisModel) ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Checks to see if all models in a streaming array are in memory /// PARAMS: /// streamedModel - Streaming array to check /// RETURNS: /// TRUE if every initialized element in a streaming array is in memory, FALSE if at least one is not in memory FUNC BOOL ARE_MODELS_STREAMED(STREAMED_MODEL &streamedModel[]) INT modelIndex REPEAT COUNT_OF(streamedModel) modelIndex IF streamedModel[modelIndex].thisModel != DUMMY_MODEL_FOR_SCRIPT // IS THIS THE CORRECT NULL CHECK?? IF NOT HAS_MODEL_LOADED(streamedModel[modelIndex].thisModel) //OR NOT HAS_COLLISION_FOR_MODEL_LOADED(streamedModel[modelIndex].thisModel) IF NOT HAS_MODEL_LOADED(streamedModel[modelIndex].thisModel) #IF IS_DEBUG_BUILD DEBUG_MESSAGE("Waiting to stream model ", GET_MODEL_NAME_FOR_DEBUG(streamedModel[modelIndex].thisModel)) #ENDIF // IS_DEBUG_BUILD ENDIF // IF NOT HAS_COLLISION_FOR_MODEL_LOADED(streamedModel[modelIndex].thisModel) // DEBUG_MESSAGE("Waiting to stream collision for ", GET_MODEL_NAME_FOR_DEBUG(streamedModel[modelIndex].thisModel)) // ENDIF RETURN FALSE ELSE #IF IS_DEBUG_BUILD DEBUG_MESSAGE("STREAMED IN ", GET_MODEL_NAME_FOR_DEBUG(streamedModel[modelIndex].thisModel)) #ENDIF // IS_DEBUG_BUILD ENDIF ENDIF ENDREPEAT RETURN TRUE ENDFUNC /// PURPOSE: /// Sets all of the models in the streaming array as no longer needed /// Only necessary for streaming in and out during missions...scripts auto-do this when they clean up /// PARAMS: /// streamedModel - Streaming array to request PROC SET_ALL_MODELS_AS_NO_LONGER_NEEDED(STREAMED_MODEL &streamedModel[]) INT modelIndex REPEAT COUNT_OF(streamedModel) modelIndex IF streamedModel[modelIndex].thisModel != DUMMY_MODEL_FOR_SCRIPT // IS THIS THE CORRECT NULL CHECK?? SET_MODEL_AS_NO_LONGER_NEEDED(streamedModel[modelIndex].thisModel) ENDIF ENDREPEAT ENDPROC /// PURPOSE: Struct for building streaming helpers STRUCT STREAMED_ANIM STRING thisAnim ENDSTRUCT /// PURPOSE: /// Finds the first uninitialized element in a streaming array. Returns -1 if the array is full. /// PARAMS: /// streamedAnim - streaming array to search in /// RETURNS: /// The index of the first uninitialized element in a streaming array. -1 if the array is full. The return value must be tested before being used! FUNC INT GET_EMPTY_STREAMED_ANIM(STREAMED_ANIM &streamedAnim[]) INT animIndex REPEAT COUNT_OF(streamedAnim) animIndex IF IS_STRING_NULL(streamedAnim[animIndex].thisAnim) RETURN animIndex ENDIF ENDREPEAT RETURN -1 ENDFUNC /// PURPOSE: /// Adds an anim dict to the first uninitialized element of a streaming array. /// PARAMS: /// streamedAnim - Streaming array to add to /// newAnim- STRING of anim name to add /// RETURNS: /// TRUE if the anim string was successfully added, FALSE otherwise (the array was full) FUNC BOOL ADD_STREAMED_ANIM(STREAMED_ANIM &streamedAnim[], STRING newAnim) INT iAnimIndex REPEAT COUNT_OF(streamedAnim) iAnimIndex IF NOT IS_STRING_NULL(streamedAnim[iAnimIndex].thisAnim) IF ARE_STRINGS_EQUAL(streamedAnim[iAnimIndex].thisAnim, newAnim) DEBUG_MESSAGE("ADD_STREAMED_ANIM returning FALSE, anim already in the index") RETURN FALSE ENDIF ENDIF ENDREPEAT INT animIndex = GET_EMPTY_STREAMED_ANIM(streamedAnim) IF animIndex < 0 OR animIndex >= COUNT_OF(streamedAnim) DEBUG_MESSAGE("ADD_STREAMED_ANIM returning FALSE, array is full") RETURN FALSE ENDIF streamedAnim[animIndex].thisAnim = newAnim RETURN TRUE ENDFUNC /// PURPOSE: /// Requests all initialized anims in a streaming array /// PARAMS: /// streamedAnim - Streaming array to request PROC REQUEST_ALL_ANIMS(STREAMED_ANIM &streamedAnim[], LoadQueueLarge &sLoadQueue) INT animIndex REPEAT COUNT_OF(streamedAnim) animIndex IF NOT IS_STRING_NULL(streamedAnim[animIndex].thisAnim) LOAD_QUEUE_LARGE_ADD_ANIM_DICT(sLoadQueue, streamedAnim[animIndex].thisAnim) DEBUG_MESSAGE("ADDING ANIM DICT TO QUEUE: ", streamedAnim[animIndex].thisAnim) ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Checks to see if all anims in a streaming array are in memory /// PARAMS: /// streamedAnim - Streaming array to check /// RETURNS: /// TRUE if every initialized element in a streaming array is in memory, FALSE if at least one is not in memory FUNC BOOL ARE_ANIMS_STREAMED(LoadQueueLarge &sLoadQueue) RETURN HAS_LOAD_QUEUE_LARGE_LOADED(sLoadQueue) ENDFUNC /// PURPOSE: /// Sets all of the models in the streaming array as no longer needed /// Only necessary for streaming in and out during missions...scripts auto-do this when they clean up /// PARAMS: /// streamedModel - Streaming array to request PROC SET_ALL_ANIMS_AS_NO_LONGER_NEEDED(STREAMED_ANIM &streamedAnim[]) INT animIndex REPEAT COUNT_OF(streamedAnim) animIndex IF NOT IS_STRING_NULL_OR_EMPTY(streamedAnim[animIndex].thisAnim) REMOVE_ANIM_DICT(streamedAnim[animIndex].thisAnim) ENDIF ENDREPEAT ENDPROC /* /// PURPOSE: Struct for building streaming helpers STRUCT STREAMED_VEHICLE_RECORDING INT thisRecordingIndex STRING thisRecording ENDSTRUCT /// PURPOSE: /// Finds the first uninitialized element in a streaming array. Returns -1 if the array is full. /// PARAMS: /// streamedRecordings - streaming array to search in /// RETURNS: /// The index of the first uninitialized element in a streaming array. -1 if the array is full. The return value must be tested before being used! FUNC INT GET_EMPTY_STREAMED_VEHICLE_RECORDING(STREAMED_VEHICLE_RECORDING &streamedRecordings[]) INT recordingIndex REPEAT COUNT_OF(streamedRecordings) recordingIndex IF IS_STRING_NULL(streamedRecordings[recordingIndex].thisRecording) RETURN recordingIndex ENDIF ENDREPEAT RETURN -1 ENDFUNC /// PURPOSE: /// Adds an anim dict to the first uninitialized element of a streaming array. /// PARAMS: /// streamedRecordings - Streaming array to add to /// newAnim- STRING of anim name to add /// RETURNS: /// TRUE if the anim string was successfully added, FALSE otherwise (the array was full) FUNC BOOL ADD_STREAMED_VEHICLE_RECORDING(STREAMED_VEHICLE_RECORDING &streamedRecordings[], INT iNewRecording, STRING newRecording) IF NOT DOES_VEHICLE_RECORDING_FILE_EXIST_IN_CDIMAGE(iNewRecording, newRecording) TEXT_LABEL_63 tlTempAssert = "\n\nVehicle recording doesn't exist: " tlTempAssert += iNewRecording tlTempAssert += " in " tlTempAssert += newRecording SCRIPT_ASSERT(tlTempAssert) RETURN FALSE ENDIF INT iRecordingIndex REPEAT COUNT_OF(streamedRecordings) iRecordingIndex IF NOT IS_STRING_NULL(streamedRecordings[iRecordingIndex].thisRecording) IF ARE_STRINGS_EQUAL(streamedRecordings[iRecordingIndex].thisRecording, newRecording) AND streamedRecordings[iRecordingIndex].thisRecordingIndex = iNewRecording DEBUG_MESSAGE("ADD_STREAMED_VEHICLE_RECORDING returning FALSE, recording already in the index") RETURN FALSE ENDIF ENDIF ENDREPEAT INT recordingIndex = GET_EMPTY_STREAMED_VEHICLE_RECORDING(streamedRecordings) IF recordingIndex < 0 OR recordingIndex >= COUNT_OF(streamedRecordings) DEBUG_MESSAGE("ADD_STREAMED_VEHICLE_RECORDING returning FALSE, couldn't find empty array index") RETURN FALSE ENDIF IF iNewRecording < 0 DEBUG_MESSAGE("ADD_STREAMED_VEHICLE_RECORDING returning FALSE, iNewRecording is less than 0") RETURN FALSE ENDIF streamedRecordings[recordingIndex].thisRecording = newRecording streamedRecordings[recordingIndex].thisRecordingIndex = iNewRecording RETURN TRUE ENDFUNC /// PURPOSE: /// Requests all initialized anims in a streaming array /// PARAMS: /// streamedRecordings - Streaming array to request PROC REQUEST_ALL_VEHICLE_RECORDINGS(STREAMED_VEHICLE_RECORDING &streamedRecordings[]) INT recordingIndex REPEAT COUNT_OF(streamedRecordings) recordingIndex IF NOT IS_STRING_NULL(streamedRecordings[recordingIndex].thisRecording) REQUEST_VEHICLE_RECORDING(streamedRecordings[recordingIndex].thisRecordingIndex, streamedRecordings[recordingIndex].thisRecording) #IF IS_DEBUG_BUILD DEBUG_MESSAGE("REQUESTING RECORDING ", streamedRecordings[recordingIndex].thisRecording, " index ", GET_STRING_FROM_INT(streamedRecordings[recordingIndex].thisRecordingIndex)) #ENDIF // IS_DEBUG_BUILD ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Checks to see if all anims in a streaming array are in memory /// PARAMS: /// streamedRecordings - Streaming array to check /// RETURNS: /// TRUE if every initialized element in a streaming array is in memory, FALSE if at least one is not in memory FUNC BOOL ARE_VEHICLE_RECORDINGS_STREAMED(STREAMED_VEHICLE_RECORDING &streamedRecordings[]) INT recordingIndex REPEAT COUNT_OF(streamedRecordings) recordingIndex IF NOT IS_STRING_NULL(streamedRecordings[recordingIndex].thisRecording) IF NOT HAS_VEHICLE_RECORDING_BEEN_LOADED(streamedRecordings[recordingIndex].thisRecordingIndex, streamedRecordings[recordingIndex].thisRecording) #IF IS_DEBUG_BUILD IF NOT DOES_VEHICLE_RECORDING_FILE_EXIST(streamedRecordings[recordingIndex].thisRecordingIndex, streamedRecordings[recordingIndex].thisRecording) DEBUG_MESSAGE("Vehicle recording doesn't exist ", streamedRecordings[recordingIndex].thisRecording, " index ", GET_STRING_FROM_INT(streamedRecordings[recordingIndex].thisRecordingIndex)) ELSE DEBUG_MESSAGE("Waiting to stream recording ", streamedRecordings[recordingIndex].thisRecording, " index ", GET_STRING_FROM_INT(streamedRecordings[recordingIndex].thisRecordingIndex)) ENDIF #ENDIF // IS_DEBUG_BUILD RETURN FALSE ELSE DEBUG_MESSAGE("STREAMED IN RECORDING ", streamedRecordings[recordingIndex].thisRecording) ENDIF ENDIF ENDREPEAT RETURN TRUE ENDFUNC /// PURPOSE: /// Removes a streamed vehicle recording /// PARAMS: /// streamedRecordings - Streaming array to check PROC REMOVE_STREAMED_VEHICLE_RECORDING(STREAMED_VEHICLE_RECORDING& streamedRecording) IF NOT IS_STRING_NULL(streamedRecording.thisRecording) REMOVE_VEHICLE_RECORDING(streamedRecording.thisRecordingIndex, streamedRecording.thisRecording) streamedRecording.thisRecording = NULL streamedRecording.thisRecordingIndex = -1 #IF IS_DEBUG_BUILD DEBUG_MESSAGE("Removed vehicle recording ", streamedRecording.thisRecording, " index ", GET_STRING_FROM_INT(streamedRecording.thisRecordingIndex)) #ENDIF // IS_DEBUG_BUILD ENDIF ENDPROC /// PURPOSE: /// Removes a streamed vehicle recording from memory and clears all recoridng references from the array /// PARAMS: /// streamedRecordings - Streaming array to check PROC SET_STREAMED_VEHICLE_RECORDING_AS_NO_LONGER_NEEDED(STREAMED_VEHICLE_RECORDING &streamedRecordings[], INT iRecordingIndex, STRING sRecording) INT recordingIndex REPEAT COUNT_OF(streamedRecordings) recordingIndex IF NOT IS_STRING_NULL(streamedRecordings[recordingIndex].thisRecording) IF streamedRecordings[recordingIndex].thisRecordingIndex = iRecordingIndex AND ARE_STRINGS_EQUAL(streamedRecordings[recordingIndex].thisRecording, sRecording) REMOVE_STREAMED_VEHICLE_RECORDING(streamedRecordings[recordingIndex]) ENDIF ENDIF ENDREPEAT ENDPROC */ /// PURPOSE: /// Draws a vector from V1 to V2, and takes the flat heading of that vector. /// PARAMS: /// V1 - /// V2 - /// RETURNS: /// FUNC FLOAT GET_HEADING_BETWEEN_VECTORS(VECTOR V1, VECTOR V2) RETURN GET_HEADING_FROM_VECTOR_2D(V2.x-V1.x,V2.y-V1.y) ENDFUNC /// PURPOSE: /// Prints a help message once if the bit in the bitfieldis not set, and sets the passed in bit so I won't be set again /// PARAMS: /// msg - message to print /// bitField - bitfield that stores the permanent print status /// bit - bit to check PROC PRINT_HELP_ONCE(STRING msg, INT &bitField, ENUM_TO_INT bit, BOOL bForever = FALSE) IF IS_BITMASK_SET(ENUM_TO_INT(bitField), ENUM_TO_INT(bit)) EXIT ENDIF IF NOT bForever PRINT_HELP(msg) ELSE PRINT_HELP_FOREVER(msg) ENDIF SET_BITMASK(bitField, ENUM_TO_INT(bit)) ENDPROC /// bit - bit to check PROC PRINT_HELP_ONCE_AT_WORLD_POSITION(STRING msg, INT &bitField, ENUM_TO_INT bit, VECTOR vWorldPosition, eARROW_DIRECTION iArrowPosition = 0, BOOL bForever = FALSE) BOOL bUpdatePosition IF IS_BITMASK_SET(ENUM_TO_INT(bitField), ENUM_TO_INT(bit)) IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED(msg) EXIT ENDIF bUpdatePosition = TRUE ENDIF IF NOT bUpdatePosition HELP_AT_LOCATION(msg, vWorldPosition, iArrowPosition, PICK_INT(bForever, FLOATING_HELP_PRINT_FOREVER, DEFAULT_GOD_TEXT_TIME), FLOATING_HELP_FIND_NEXT_FREE_SLOT) SET_BITMASK(bitField, ENUM_TO_INT(bit)) ENDIF UPDATE_FLOATING_HELP_WORLD_POSITION(msg, vWorldPosition) ENDPROC /// bit - bit to check PROC PRINT_HELP_ONCE_AT_ENTITY(STRING msg, INT &bitField, ENUM_TO_INT bit, ENTITY_INDEX eEntityPrint, eARROW_DIRECTION iArrowPosition = 0, BOOL bForever = FALSE) BOOL bUpdatePosition IF IS_BITMASK_SET(ENUM_TO_INT(bitField), ENUM_TO_INT(bit)) IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED(msg) EXIT ENDIF bUpdatePosition = TRUE ENDIF IF NOT bUpdatePosition HELP_AT_ENTITY(msg, eEntityPrint, iArrowPosition, PICK_INT(bForever, FLOATING_HELP_PRINT_FOREVER, DEFAULT_GOD_TEXT_TIME), FLOATING_HELP_FIND_NEXT_FREE_SLOT) SET_BITMASK(bitField, ENUM_TO_INT(bit)) ENDIF ENDPROC /// bit - bit to check PROC PRINT_HELP_ONCE_AT_ENTITY_OFFSET(STRING msg, INT &bitField, ENUM_TO_INT bit, ENTITY_INDEX eEntityPrint, VECTOR vOffsetPosition, eARROW_DIRECTION iArrowPosition = 0, BOOL bForever = FALSE) BOOL bUpdatePosition IF IS_BITMASK_SET(ENUM_TO_INT(bitField), ENUM_TO_INT(bit)) IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED(msg) EXIT ENDIF bUpdatePosition = TRUE ENDIF IF NOT bUpdatePosition HELP_AT_ENTITY_OFFSET(msg, eEntityPrint, vOffsetPosition, iArrowPosition, PICK_INT(bForever, FLOATING_HELP_PRINT_FOREVER, DEFAULT_GOD_TEXT_TIME), FLOATING_HELP_FIND_NEXT_FREE_SLOT) SET_BITMASK(bitField, ENUM_TO_INT(bit)) ENDIF UPDATE_FLOATING_HELP_ENTITY_OFFSET(msg, eEntityPrint, vOffsetPosition) ENDPROC /// bit - bit to check PROC PRINT_HELP_ONCE_AT_SCREEN_POSITION(STRING msg, INT &bitField, ENUM_TO_INT bit, FLOAT fScreenX, FLOAT fScreenY, eARROW_DIRECTION iArrowPosition = 0, BOOL bForever = FALSE) BOOL bUpdatePosition IF IS_BITMASK_SET(ENUM_TO_INT(bitField), ENUM_TO_INT(bit)) IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED(msg) EXIT ENDIF bUpdatePosition = TRUE ENDIF IF NOT bUpdatePosition HELP_AT_SCREEN_LOCATION(msg, fScreenX, fScreenY, iArrowPosition, PICK_INT(bForever, FLOATING_HELP_PRINT_FOREVER, DEFAULT_GOD_TEXT_TIME), FLOATING_HELP_FIND_NEXT_FREE_SLOT) SET_BITMASK(bitField, ENUM_TO_INT(bit)) ENDIF UPDATE_FLOATING_HELP_SCREEN_POSITION(msg, fScreenX, fScreenY) ENDPROC /// PURPOSE: /// Prints an objective once if the bit in the bitfield is not set, and sets the passed in bit so I won't be set again /// PARAMS: /// msg - message to print // Duration is an INT in milliseconds (1000 = 1 sec). // Colour is an INT and should correspond to the person that speaks. //PARAM NOTES: Colour 0 = White // 1 = Red // 2 = Green // 3 = Blue // 4 = Purple // 5 = Yellow // 6 = Black /// bitField - bitfield that stores the permanent print status /// bit - bit to check PROC PRINT_NOW_ONCE(STRING msg, INT Duration, INT Colour, INT &bitField, ENUM_TO_INT bit) IF IS_BITMASK_SET(ENUM_TO_INT(bitField), ENUM_TO_INT(bit)) EXIT ENDIF PRINT_NOW(msg, Duration, Colour) SET_BITMASK(bitField, ENUM_TO_INT(bit)) ENDPROC /// PURPOSE: /// Extract the minutes and seconds from a struct timer PROC GET_TIMER_TIME(structTimer myTimer, INT& hours, INT& minutes, INT& seconds) FLOAT totalSeconds hours = 0 totalSeconds = GET_TIMER_IN_SECONDS(myTimer) minutes = FLOOR(totalSeconds / 60) seconds = FLOOR(totalSeconds - (minutes * 60)) ENDPROC /// PURPOSE: /// To check if there are alive entities in an array /// PARAMS: /// myEntities - an array of entities /// RETURNS: /// BOOL - True if any entities are alive, False if all entities are dead FUNC BOOL IS_ANY_ENTITY_ALIVE(ENTITY_INDEX& myEntities[]) INT idx REPEAT COUNT_OF(myEntities) idx IF NOT IS_ENTITY_DEAD(myEntities[idx]) RETURN TRUE ENDIF ENDREPEAT RETURN FALSE ENDFUNC /* duplicate function - already in script_ped.sch /// PURPOSE: /// To get the distance between two entities /// PARAMS: /// ENTITY_INDEX ent1 - First ped /// ENTITY_INDEX ent2 - Second ped /// RETURNS: /// FLOAT - Distance between entities, -1 if any entity is invalid FUNC FLOAT GET_DISTANCE_BETWEEN_ENTITIES(ENTITY_INDEX ent1, ENTITY_INDEX ent2, BOOL bCheck3d = TRUE) IF IS_ENTITY_DEAD(ent1) OR IS_ENTITY_DEAD(ent2) SCRIPT_ASSERT("GET_DISTANCE_BETWEEN_ENTITIES: Invalid entity passed in") RETURN -1.0 ELSE RETURN GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(ent1), GET_ENTITY_COORDS(ent2), bCheck3d) ENDIF ENDFUNC */ /// PURPOSE: /// To find the closest location to the current vector /// PARAMS: /// VECTOR vArray[] - Array of locations /// VECTOR myCurLocation - The current location we're comparing against /// RETURNS: /// INT - the index of the closest location FUNC INT FIND_CLOSEST_LOCATION_INDEX(VECTOR& vArray[], VECTOR myCurLocation, FLOAT minDistance = 0.0) INT idx INT closestIndex = 0 FLOAT fClosestDist = 1000000000 //VDIST2(vArray[0], myCurLocation) //assumes first locaiton is valid FLOAT fDist REPEAT COUNT_OF(vArray) idx IF NOT IS_VECTOR_ZERO(vArray[idx]) fDist = VDIST2(vArray[idx], myCurLocation) IF fDist < fClosestDist AND fDist > minDistance fClosestDist = fDist closestIndex = idx ENDIF ENDIF ENDREPEAT IF closestIndex = -1 SCRIPT_ASSERT("FIND_CLOSEST_LOCATION_INDEX returning -1") ENDIF RETURN closestIndex ENDFUNC /// PURPOSE: /// To get the distance between an entity and a vector /// PARAMS: /// ENTITY_INDEX ent1 - First entity /// VECTOR - vLocation /// RETURNS: /// FLOAT - Distance between an entity and vector, -1 if the entity is invalid FUNC FLOAT GET_ENTITY_DISTANCE_FROM_LOCATION(ENTITY_INDEX ped1, VECTOR vLocation, BOOL bCheck3d = TRUE) IF IS_ENTITY_DEAD(ped1) PRINTLN("GET_ENTITY_DISTANCE_FROM_LOCATION: Invalid ped passed in") RETURN -1.0 ELSE RETURN GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(ped1),vLocation, bCheck3d) ENDIF ENDFUNC /// RETURNS: /// INT - the index of the closest location, -1 if no valid location found FUNC INT FIND_CLOSEST_ENTITY_INDEX(ENTITY_INDEX& eArray[], VECTOR myCurLocation) INT idx INT closestIndex = -1 FLOAT fClosestDist = -1.0 VECTOR vTempCoord FLOAT fCurDist REPEAT COUNT_OF(eArray) idx IF NOT IS_ENTITY_DEAD(eArray[idx]) vTempCoord = GET_ENTITY_COORDS(eArray[idx]) fCurDist = VDIST2(vTempCoord, myCurLocation) IF closestIndex = -1 fClosestDist = fCurDist closestIndex = idx ELIF fCurDist < fClosestDist fClosestDist = fCurDist closestIndex = idx ENDIF ENDIF ENDREPEAT // IF closestIndex = -1 // SCRIPT_ASSERT("FIND_CLOSEST_ENTITY_INDEX returning -1") // ENDIF RETURN closestIndex ENDFUNC FUNC FLOAT GET_PLAYER_DISTANCE_FROM_ENTITY(ENTITY_INDEX myObject, BOOL bCheck3d = TRUE) RETURN GET_DISTANCE_BETWEEN_ENTITIES(GET_PLAYER_PED(GET_PLAYER_INDEX()), myObject, bCheck3d) ENDFUNC FUNC FLOAT GET_PLAYER_DISTANCE_FROM_LOCATION(VECTOR vLocation, BOOL bCheck3d = TRUE) RETURN GET_ENTITY_DISTANCE_FROM_LOCATION(GET_PLAYER_PED(GET_PLAYER_INDEX()), vLocation, bCheck3d) ENDFUNC /// PURPOSE: /// Fly a plane level at desired speed indefinately /// PARAMS: /// Plane - The plane to fly in auto-pilot /// fSpeed - The speed to fly the plane in auto-pilot /// bRotInterp - Whether or not to interpolate the plane rotating PROC PLANE_AUTOPILOT(VEHICLE_INDEX Plane, FLOAT fSpeed, BOOL bRotInterp, FLOAT xRot = 0.0, FLOAT yRot = 0.0) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT) // Error checking. IF IS_ENTITY_DEAD(Plane) DEBUG_MESSAGE("PLANE_AUTOPILOT: Plane not alive, exiting!") EXIT ENDIF // TODO: May want to add a check to see if vehicle is a plane. // If Plane speed is below desired speed change it. IF (GET_ENTITY_SPEED(Plane) < fSpeed) SET_VEHICLE_FORWARD_SPEED(Plane, fSpeed) ENDIF // If Plane isn't level, rotate it (interp if desired). VECTOR vRot = GET_ENTITY_ROTATION(Plane) BOOL bPlaneRotated = FALSE IF bRotInterp FLOAT fRotInterp = GET_FRAME_TIME() * 45.0 IF (vRot.x < -fRotInterp) bPlaneRotated = TRUE vRot.x += fRotInterp ELIF (vRot.x < xRot) bPlaneRotated = TRUE vRot.x = xRot ELIF (vRot.x > fRotInterp) bPlaneRotated = TRUE vRot.x -= fRotInterp ELIF (vRot.x > xRot) bPlaneRotated = TRUE vRot.x = xRot ENDIF IF (vRot.y < -fRotInterp) bPlaneRotated = TRUE vRot.y += fRotInterp ELIF (vRot.y < yRot) bPlaneRotated = TRUE vRot.y = yRot ELIF (vRot.y > fRotInterp) bPlaneRotated = TRUE vRot.y -= fRotInterp ELIF (vRot.y > yRot) bPlaneRotated = TRUE vRot.y = yRot ENDIF ELSE IF (vRot.x <> xRot) bPlaneRotated = TRUE vRot.x = xRot ENDIF IF (vRot.y <> yRot) bPlaneRotated = TRUE vRot.y = yRot ENDIF ENDIF IF bPlaneRotated SET_ENTITY_ROTATION(Plane, vRot) ENDIF ENDPROC /// PURPOSE: /// Fly a plane circling at desired speed indefinately /// PARAMS: /// Plane - The plane to fly in auto-circle /// fSpeed - The speed to fly the plane in auto-circle /// bRotInterp - Whether or not to interpolate the plane rotating PROC PLANE_AUTOCIRCLE(VEHICLE_INDEX Plane, FLOAT fSpeed, BOOL bRotInterp) // Error checking. IF IS_ENTITY_DEAD(Plane) DEBUG_MESSAGE("PLANE_AUTOCIRCLE: Plane not alive, exiting!") EXIT ENDIF // TODO: May want to add a check to see if vehicle is a plane. // If Plane speed is below desired speed change it. IF (GET_ENTITY_SPEED(Plane) < fSpeed) SET_VEHICLE_FORWARD_SPEED(Plane, fSpeed) ENDIF // If Plane isn't circling, rotate it (interp if desired). VECTOR vRot = GET_ENTITY_ROTATION(Plane) BOOL bPlaneRotated = FALSE FLOAT fPitch = 5.0 FLOAT fRoll = 45.0 IF bRotInterp FLOAT fRotInterp = GET_FRAME_TIME() * 45.0 IF (vRot.x < (fPitch - fRotInterp)) bPlaneRotated = TRUE vRot.x += fRotInterp ELIF (vRot.x < fPitch) bPlaneRotated = TRUE vRot.x = fPitch ELIF (vRot.x > (fPitch + fRotInterp)) bPlaneRotated = TRUE vRot.x -= fRotInterp ELIF (vRot.x > fPitch) bPlaneRotated = TRUE vRot.x = fPitch ENDIF IF (vRot.y < (fRoll - fRotInterp)) bPlaneRotated = TRUE vRot.y += fRotInterp ELIF (vRot.y < fRoll) bPlaneRotated = TRUE vRot.y = fRoll ELIF (vRot.y > (fRoll + fRotInterp)) bPlaneRotated = TRUE vRot.y -= fRotInterp ELIF (vRot.y > fRoll) bPlaneRotated = TRUE vRot.y = fRoll ENDIF ELSE IF (vRot.x <> fPitch) bPlaneRotated = TRUE vRot.x = fPitch ENDIF IF (vRot.y <> fRoll) bPlaneRotated = TRUE vRot.y = fRoll ENDIF ENDIF IF bPlaneRotated SET_ENTITY_ROTATION(Plane, vRot) ENDIF ENDPROC /// PURPOSE: /// Snaps a position to the ground /// PARAMS: /// vSnappedPos - position to snap to the ground /// fAddHeight - additional height to add after the snap, defaults to 0.0 /// RETURNS: /// TRUE if the ground z was found, FALSE if it wasn't found and vector didn't change FUNC BOOL SNAP_3D_COORD_TO_GROUND(VECTOR& vSnappedPos, FLOAT fAddHeight = 0.0) FLOAT fGroundZ = 0.0 IF GET_GROUND_Z_FOR_3D_COORD(vSnappedPos, fGroundZ) vSnappedPos.z = fGroundZ vSnappedPos.z += fAddHeight RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Given an array of numbers, gets a random number inside a range that's not already inside of the array. /// RETURNS: /// A number if found, -1 otherwise. FUNC INT GET_RANDOM_INT_IN_RANGE_NOT_IN_ARRAY(INT & iArray[], INT iArraySize, INT intMin, INT intMax) BOOL bAlreadyPresent = TRUE INT index, iRuns = 0, iResult WHILE bAlreadyPresent AND iRuns < 50 bAlreadyPresent = FALSE iResult = (GET_RANDOM_INT_IN_RANGE(0, 50000) % (intMax - intMin)) + intMin PRINTLN("Trying number ", iResult) FOR index = 0 TO iArraySize - 1 IF (iArray[index] = iResult) bAlreadyPresent = TRUE index = 999999 ENDIF ENDFOR iRuns += 1 ENDWHILE IF iRuns = 50 RETURN -1 ENDIF RETURN iResult ENDFUNC ENUM COUNTDOWN_UI_FLAGS CNTDWN_UI_Played_3 = BIT0, CNTDWN_UI_Played_2 = BIT1, CNTDWN_UI_Played_1 = BIT2, CNTDWN_UI_Played_Go = BIT3, CNTDWN_UI_Played_Race_Go = BIT4 ENDENUM STRUCT COUNTDOWN_UI SCALEFORM_INDEX uiCountdown INT iBitFlags structTimer CountdownTimer ENDSTRUCT /// PURPOSE: /// Provides the scripter with a handle to the countdown UI. PROC REQUEST_MINIGAME_COUNTDOWN_UI(COUNTDOWN_UI & uiToRequest) uiToRequest.uiCountdown = REQUEST_SCALEFORM_MOVIE("COUNTDOWN") REQUEST_SCRIPT_AUDIO_BANK("HUD_321_GO") ENDPROC /// PURPOSE: /// Lets the scripter know if the countdown UI is ready for use. Should be done in streaming checks. FUNC BOOL HAS_MINIGAME_COUNTDOWN_UI_LOADED(COUNTDOWN_UI & uiToCheck) RETURN (HAS_SCALEFORM_MOVIE_LOADED(uiToCheck.uiCountdown) AND REQUEST_SCRIPT_AUDIO_BANK("HUD_321_GO")) ENDFUNC /// PURPOSE: /// Clears the scritpers handle to the countdown UI. PROC RELEASE_MINIGAME_COUNTDOWN_UI(COUNTDOWN_UI & uiToRelease) SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(uiToRelease.uiCountdown) RELEASE_SCRIPT_AUDIO_BANK() ENDPROC /// PURPOSE: /// Private minigame countdown UI func. PROC SET_MINIGAME_COUNTDOWN_UI_NUMBER(COUNTDOWN_UI & uiToUpdate, INT iNum) INT iR, iG, iB, iA GET_HUD_COLOUR(HUD_COLOUR_YELLOW, iR, iG, iB, iA) BEGIN_SCALEFORM_MOVIE_METHOD(uiToUpdate.uiCountdown, "SET_MESSAGE") SET_COLOUR_OF_NEXT_TEXT_COMPONENT(INT_TO_ENUM(HUD_COLOURS, -1)) BEGIN_TEXT_COMMAND_SCALEFORM_STRING("NUMBER") ADD_TEXT_COMPONENT_INTEGER(ABSI(iNum)) END_TEXT_COMMAND_SCALEFORM_STRING() SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iR) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iG) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iB) SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(TRUE) END_SCALEFORM_MOVIE_METHOD() ENDPROC /// PURPOSE: /// Display an on-screen countdown UI /// PARAMS: /// uiToUpdate - Your countdown UI struct. /// iCountdownLength - Between 0 and 3 /// bLoudVersion - Use the sounds in the HUD_MINIGAME_SOUNDSET or the ... /// RETURNS: /// TRUE one second after the countdown is done. FUNC BOOL UPDATE_MINIGAME_COUNTDOWN_UI(COUNTDOWN_UI & uiToUpdate, BOOL bWaitExtraSec = TRUE, BOOL bSkipOnButtonPress = FALSE, BOOL bCancelTimerAtEnd = TRUE, INT iCountdownLength = 3, BOOL bLoudVersionSounds = TRUE, BOOL bTriggerGoQuick = FALSE, BOOL bIsRaceCreator = FALSE) // Make sure we have a timer. IF bIsRaceCreator FORCE_TIMER_TO_USE_GAME_TIME(uiToUpdate.CountdownTimer, TRUE) ENDIF IF NOT IS_TIMER_STARTED(uiToUpdate.CountdownTimer) PRINTLN("[TimerBroken] RESTARTING TIMER") RESTART_TIMER_NOW(uiToUpdate.CountdownTimer) ENDIF // Always draw the movie. SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_BEFORE_HUD) DRAW_SCALEFORM_MOVIE(uiToUpdate.uiCountdown, 0.5, 0.5, 1.0, 1.0, 255, 255, 255, 100) //Make sure Countdown Length is within limits IF iCountdownLength > 3 iCountdownLength = 3 ELIF iCountdownLength < 0 iCountdownLength = 0 ENDIF //select sfx STRING sCountSound, sGoSound, sSoundSet IF bLoudVersionSounds sCountSound = "3_2_1" sGoSound = "GO" sSoundSet = "HUD_MINI_GAME_SOUNDSET" ELSE sCountSound = "3_2_1" sGoSound = "GO" sSoundSet = "321_GO_LOW_VOL_SOUNDSET" ENDIF // Get the timer values. FLOAT fScratchTime INT iTimerVal IF bisRaceCreator IF IS_TIMER_STARTED(uiToUpdate.CountdownTimer) IF IS_TIMER_PAUSED(uiToUpdate.CountdownTimer) PRINTLN("[TimerBroken] IS_TIMER_PAUSED : YES" ) fScratchTime = uiToUpdate.CountdownTimer.PauseTime ELSE fScratchTime = (GetGameTimerSeconds(TRUE) - uiToUpdate.CountdownTimer.StartTime) IF fScratchTime < 0 PRINTLN("[TimerBroken] Timer is fucked, rebooting it") fScratchTime = 0 CANCEL_TIMER(uiToUpdate.CountdownTimer) IF IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_3) SET_BITMASK_AS_ENUM(uiToUpdate.iBitFlags, CNTDWN_UI_Played_Go) INT iR, iG, iB, iA GET_HUD_COLOUR(HUD_COLOUR_GREEN, iR, iG, iB, iA) BEGIN_SCALEFORM_MOVIE_METHOD(uiToUpdate.uiCountdown, "SET_MESSAGE") SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("CNTDWN_GO") SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iR) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iG) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iB) SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(TRUE) END_SCALEFORM_MOVIE_METHOD() PRINTLN("[TimerBroken] Failsafe Bail" ) RETURN TRUE ENDIF RESTART_TIMER_NOW(uiToUpdate.CountdownTimer) ENDIF ENDIF ELSE PRINTLN("[TimerBroken] IS_TIMER_STARTED : NO" ) fScratchTime = uiToUpdate.CountdownTimer.StartTime ENDIF PRINTLN("[TimerBroken] fScratchTime ", fScratchTime) iTimerVal = FLOOR(fScratchTime) ELSE iTimerVal = FLOOR(GET_TIMER_IN_SECONDS(uiToUpdate.CountdownTimer)) ENDIF INT iSeconds = iTimerVal - iCountdownLength BOOL bForceEnd = FALSE PRINTLN("[TimerBroken] UPDATE_MINIGAME_COUNTDOWN_UI iTimerVal = ", iTimerVal, ", iSeconds = ", iSeconds, " uiToUpdate.CountdownTimer.StartTime = ", uiToUpdate.CountdownTimer.StartTime ) IF NOT IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_Go) // See if we're due to update. IF (iSeconds >= -3) AND NOT IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_3) SET_BITMASK_AS_ENUM(uiToUpdate.iBitFlags, CNTDWN_UI_Played_3) PRINTLN("Playing SFX for NUMBER 3") PLAY_SOUND_FRONTEND(-1, sCountSound, sSoundSet) SET_MINIGAME_COUNTDOWN_UI_NUMBER(uiToUpdate, iSeconds) ELIF (iSeconds >= -2) AND NOT IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_2) SET_BITMASK_AS_ENUM(uiToUpdate.iBitFlags, CNTDWN_UI_Played_2) PRINTLN("Playing SFX for NUMBER 2") PLAY_SOUND_FRONTEND(-1, sCountSound, sSoundSet) SET_MINIGAME_COUNTDOWN_UI_NUMBER(uiToUpdate, iSeconds) ELIF (iSeconds >= -1) AND NOT IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_1) SET_BITMASK_AS_ENUM(uiToUpdate.iBitFlags, CNTDWN_UI_Played_1) PRINTLN("Playing SFX for NUMBER 1") PLAY_SOUND_FRONTEND(-1, sCountSound, sSoundSet) SET_MINIGAME_COUNTDOWN_UI_NUMBER(uiToUpdate, iSeconds) ELIF (iSeconds >= -1) AND NOT IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_Race_Go) IF ABSF(GET_TIMER_IN_SECONDS(uiToUpdate.CountdownTimer) - iCountdownLength) < 0.65 //countdown timer is going BACKWARDS! IF bLoudVersionSounds OR bTriggerGoQuick PRINTLN("Playing SFX for RACE GO") SET_BITMASK_AS_ENUM(uiToUpdate.iBitFlags, CNTDWN_UI_Played_Race_Go) PLAY_SOUND_FRONTEND(-1, sGoSound, sSoundSet) ENDIF ENDIF ELIF (iSeconds >= 0) AND NOT IS_BITMASK_AS_ENUM_SET(uiToUpdate.iBitFlags, CNTDWN_UI_Played_Go) IF NOT bLoudVersionSounds AND NOT bTriggerGoQuick // These get played a but later, for some reason... Not going to change the architecture... PRINTLN("Playing SFX for GO") PLAY_SOUND_FRONTEND(-1, sGoSound, sSoundSet) ENDIF SET_BITMASK_AS_ENUM(uiToUpdate.iBitFlags, CNTDWN_UI_Played_Go) INT iR, iG, iB, iA GET_HUD_COLOUR(HUD_COLOUR_GREEN, iR, iG, iB, iA) BEGIN_SCALEFORM_MOVIE_METHOD(uiToUpdate.uiCountdown, "SET_MESSAGE") SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("CNTDWN_GO") SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iR) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iG) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iB) SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(TRUE) END_SCALEFORM_MOVIE_METHOD() IF NOT bWaitExtraSec bForceEnd = TRUE ENDIF ENDIF ELSE IF (iSeconds = 1) bForceEnd = TRUE ENDIF ENDIF //check for a button press to skip the countdown IF (bSkipOnButtonPress AND IS_CUTSCENE_SKIP_BUTTON_PRESSED()) OR iTimerVal > 5 bForceEnd = TRUE ENDIF // If we've been ordered to leave, do so. IF bForceEnd IF bCancelTimerAtEnd // Reset our vars. uiToUpdate.iBitFlags = 0 CANCEL_TIMER(uiToUpdate.CountdownTimer) ENDIF // We're done. RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Packs a vector into a single INT /// Bits 0-14 are the X value, and Bits 15-29 are the Y value. /// Z value is dropped /// Bit 30 is sign X and Bit 31 is SignY /// All values are currently rounded, giving you ~1m accuracy /// Does not work for values outside of (-32767, 32767) /// PARAMS: /// vPos - Vector to pack /// RETURNS: /// The packed int FUNC INT VECTOR_FLAT_PACK(VECTOR vPacked) //Truncate the x value to the first fifteen bits // Or is with the Truncated 15 bits of Z, shifted up to the next 15 bits INT retVal = (ROUND(ABSF(vPacked.x)) & 32767) | SHIFT_LEFT((ROUND(ABSF(vPacked.y)) & 32767), 15) IF vPacked.x > 0 retVal |= BIT30 ENDIF IF vPacked.y > 0 retVal |= (BIT30 * 2) ENDIF RETURN retVal ENDFUNC /// PURPOSE: /// Unpacks an int that was packed with PACK_POSITION_FLAT /// PARAMS: /// packedPosition - /// RETURNS: /// FUNC VECTOR VECTOR_FLAT_UNPACK(INT packedPosition) VECTOR retVal INT unpackedX = packedPosition & 32767 INT unpackedZ = SHIFT_RIGHT(packedPosition, 15) & 32767 retVal.x = TO_FLOAT(unpackedX) // Mask off all but the first 15 bits retVal.y = TO_FLOAT(unpackedZ) // Shift the next 15 bits down to first 15, then mask them off IF (packedPosition & BIT30) = 0 // Reset the sign of the X value retVal.x *= -1 ENDIF IF (packedPosition & (BIT30 * 2)) = 0 // Reset the sign of the Z value retVal.y *= -1 ENDIF RETURN retVal ENDFUNC /// PURPOSE: /// To convert the INT packed by VECTOR_FLAT_PACK to a world position, using the ground check /// RETURNS: /// FUNC VECTOR GET_WORLD_POSITION_FROM_PACKED_INT(INT packedPosition) VECTOR retVal = VECTOR_FLAT_UNPACK(packedPosition) IF NOT GET_GROUND_Z_FOR_3D_COORD(retVal, retVal.z) SCRIPT_ASSERT("GET_GROUND_Z_FOR_3D_COORD failed in the designer defined func: GET_WORLD_POSITION_FROM_PACKED_INT") ENDIF RETURN retVal ENDFUNC /// PURPOSE: /// Stops peds from spawning, walking, and activating scenarios in an area. Rectangle created is axis aligned. /// Does cause some awkward standing around from peds /// PARAMS: /// vMin - /// vMax - /// RETURNS: /// A scenario blocking index, store this and use it to remove the blocking area when the script cleans up FUNC SCENARIO_BLOCKING_INDEX PREVENT_PEDS_FROM_BEING_IN_AREA(VECTOR vMin, VECTOR vMax) SET_PED_NON_CREATION_AREA(vMin, vMax) DISABLE_NAVMESH_IN_AREA(vMin, vMax, TRUE) RETURN ADD_SCENARIO_BLOCKING_AREA(vMin, vMax) ENDFUNC /// PURPOSE: /// Clean up all the work done by PREVENT_PEDS_FROM_BEING_IN_AREA /// PARAMS: /// sbi - /// vMin - /// vMax - PROC ALLOW_PEDS_TO_BE_IN_AREA(SCENARIO_BLOCKING_INDEX sbi, VECTOR vMin, VECTOR vMax) REMOVE_SCENARIO_BLOCKING_AREA(sbi) CLEAR_PED_NON_CREATION_AREA() DISABLE_NAVMESH_IN_AREA(vMin, vMax, FALSE) ENDPROC STRUCT SCRIPT_SCALEFORM_MEDAL_TOAST SCALEFORM_INDEX siMovie INT iDuration structTimer movieTimer ENDSTRUCT FUNC SCALEFORM_INDEX REQUEST_MG_MEDAL_TOAST() RETURN REQUEST_SCALEFORM_MOVIE("MP_MEDAL_FREEMODE") ENDFUNC PROC CLEAR_MG_MEDAL_TOAST(SCRIPT_SCALEFORM_MEDAL_TOAST& medalToast) IF HAS_SCALEFORM_MOVIE_LOADED(medalToast.siMovie) BEGIN_SCALEFORM_MOVIE_METHOD(medalToast.siMovie, "RESET_AWARDS_MOVIE") END_SCALEFORM_MOVIE_METHOD() ENDIF ENDPROC PROC CLEANUP_MG_MEDAL_TOAST(SCRIPT_SCALEFORM_MEDAL_TOAST& medalToast) SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(medalToast.siMovie) medalToast.siMovie = NULL ENDPROC PROC SET_MG_MEDAL_TOAST(SCRIPT_SCALEFORM_MEDAL_TOAST &medalToast, STRING TexDict, STRING TexName, STRING sAward, STRING sTitle, STRING sSubTitle, INT iDuration) medalToast.iDuration = iDuration BEGIN_SCALEFORM_MOVIE_METHOD(medalToast.siMovie, "SHOW_AWARD_AND_MESSAGE") SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(sAward) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(sTitle) SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME(TexDict)//DisplayStruct.TextureDictionary SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME(TexName)//DisplayStruct.TextureName) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(sSubTitle) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) // 107 = Bronze, 108 = Silver, 109 = gold, 110 = Plat // SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("FAKESTRING") END_SCALEFORM_MOVIE_METHOD() ENDPROC FUNC BOOL UPDATE_MG_MEDAL_TOAST(SCRIPT_SCALEFORM_MEDAL_TOAST &medalToast) IF NOT IS_TIMER_STARTED(medalToast.movieTimer) RESTART_TIMER_NOW(medalToast.movieTimer) ENDIF // Hide the reticle. HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_RETICLE) DRAW_SCALEFORM_MOVIE_FULLSCREEN(medalToast.siMovie, 255, 255, 255, 255) //always return true if the duration is -1 IF (medalToast.iDuration = -1) RETURN TRUE ENDIF // Is it time to leave? IF (GET_TIMER_IN_SECONDS(medalToast.movieTimer) * 1000.0 > TO_FLOAT(medalToast.iDuration)) CANCEL_TIMER(medalToast.movieTimer) RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// prepares a music event /// PARAMS: eBitMask is for a flag to make sure that we dont prepare/trigger more than once. /// RETURNS: /// Whether we were successful /// FUNC BOOL MG_PREPARE_MUSIC_EVENT(STRING sMusicEvent, INT &iBitField, ENUM_TO_INT eBitMask) IF NOT IS_BIT_SET(iBitField, ENUM_TO_INT(eBitmask)) IF PREPARE_MUSIC_EVENT(sMusicEvent) PRINTLN("PREPARED MUSIC EVENT: ", sMusicEvent) SET_BIT(iBitField, ENUM_TO_INT(eBitmask)) RETURN TRUE ENDIF ELSE RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL MG_TRIGGER_MUSIC_EVENT(STRING sMusicEvent, INT &iBitField, ENUM_TO_INT eBitMask) IF NOT IS_BIT_SET(iBitField, ENUM_TO_INT(eBitmask)) IF PREPARE_MUSIC_EVENT(sMusicEvent) IF TRIGGER_MUSIC_EVENT(sMusicEvent) PRINTLN("TRIGGERED MUSIC EVENT: ", sMusicEvent) SET_BIT(iBitField, ENUM_TO_INT(eBitmask)) RETURN TRUE ELSE PRINTLN("Couldn't trigger music event this frame: ", sMusicEvent) ENDIF ELSE PRINTLN("music event not prepared") ENDIF ELSE RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// starts audio scene /// PARAMS: eBitMask is for a flag to make sure that we dont prepare/trigger more than once. /// RETURNS: /// Whether we were successful /// FUNC BOOL MG_START_AUDIO_SCENE(STRING sAudioSceneToStart, STRING sAudioSceneToStop, INT &iBitField, ENUM_TO_INT eBitMask) IF NOT IS_STRING_NULL_OR_EMPTY(sAudioSceneToStop) IF IS_AUDIO_SCENE_ACTIVE(sAudioSceneToStop) STOP_AUDIO_SCENE(sAudioSceneToStop) PRINTLN("STOPPED AUDIO SCENE: ", sAudioSceneToStop) ELSE PRINTLN("CANT STOP AN INACTIVE AUDIO SCENE: ", sAudioSceneToStop) ENDIF ELSE PRINTLN("NULL STRING. NO AUDIO SCENE TO STOP ") ENDIF IF NOT IS_BIT_SET(iBitField, ENUM_TO_INT(eBitmask)) IF START_AUDIO_SCENE(sAudioSceneToStart) PRINTLN("STARTED AUDIO SCENE: ", sAudioSceneToStart) SET_BIT(iBitField, ENUM_TO_INT(eBitmask)) RETURN TRUE ENDIF PRINTLN("ATTEMPTING TO START AUDIO SCENE: ", sAudioSceneToStart) ELSE RETURN TRUE ENDIF RETURN FALSE ENDFUNC PROC MG_STOP_AUDIO_SCENE(STRING sAudioScene, INT &iBitField, ENUM_TO_INT eBitMask) IF NOT IS_BIT_SET(iBitField, ENUM_TO_INT(eBitmask)) STOP_AUDIO_SCENE(sAudioScene) PRINTLN("STOPPED AUDIO SCENE: ", sAudioScene) SET_BIT(iBitField, ENUM_TO_INT(eBitmask)) ENDIF ENDPROC CONST_INT MG_FAIL_BLUR_EFFECT_TIME 3000 CONST_FLOAT MG_FAIL_BLUR_FAIL_EFFECT_SLO_MO 0.02 CONST_FLOAT MG_FAIL_BLUR_FAIL_OUT_EFFECT_SLO_MO 0.05 INT iFailScreenBits = 0 INT iDelayTimer = 0 ENUM MG_FAIL_BLUR_EFFECT_FLAGS MG_FAIL_BLUR_HAS_BEEN_TRIGGERED, MG_FAIL_BLUR_FAIL_OUT_HAS_BEEN_TRIGGERED, MG_FAIL_BLUR_SLOW_MO_HAS_BEEN_TRIGGERED, MG_FAIL_BLUR_PAUSED_GAME, MG_FAIL_BLUR_DELAY_TIMER_SET ENDENUM PROC MG_RESET_FAIL_EFFECT_VARS() iFailScreenBits = 0 iDelayTimer = 0 SET_SCRIPTS_SAFE_FOR_CUTSCENE(FALSE) DISABLE_CELLPHONE(TRUE) ENDPROC PROC MG_DO_PAUSE_EFFECT(BOOL bPause) BOOL bIgnore = FALSE #IF IS_DEBUG_BUILD bIgnore = g_bFlowAutoplayInProgress #ENDIF IF bIgnore = FALSE // don't pause the game if we are doing an auto playthrough IF bPause = TRUE // pause the game IF NOT IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_PAUSED_GAME)) PRINTLN("MG_DO_PAUSE_EFFECT() is pausing the game.") SET_GAME_PAUSED(TRUE) SET_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_PAUSED_GAME)) ENDIF ELSE // unpause the game IF IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_PAUSED_GAME)) PRINTLN( "MG_DO_PAUSE_EFFECT() is unpausing the game.") SET_GAME_PAUSED(FALSE) CLEAR_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_PAUSED_GAME)) ENDIF ENDIF ENDIF ENDPROC PROC MG_DO_SLOW_MO_EFFECT(BOOL bStart, INT iFailEffect = 1, BOOL bIgnoreTriggeredFlags = FALSE) IF bStart = TRUE PRINTLN("MG_DO_SLOW_MO_EFFECT() is starting slo-mo now") SET_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_SLOW_MO_HAS_BEEN_TRIGGERED)) // start slow motion #IF USE_TU_CHANGES IF NOT NETWORK_IS_GAME_IN_PROGRESS() IF iFailEffect = 1 SET_TIME_SCALE(FAIL_EFFECT_SLO_MO) ELSE SET_TIME_SCALE(FAIL_OUT_EFFECT_SLO_MO) ENDIF ENDIF #ENDIF // USE_TU_CHANGES #IF NOT USE_TU_CHANGES IF iFailEffect = 1 SET_TIME_SCALE(FAIL_EFFECT_SLO_MO) ELSE SET_TIME_SCALE(FAIL_OUT_EFFECT_SLO_MO) ENDIF #ENDIF // NOT USE_TU_CHANGES ELSE IF IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_SLOW_MO_HAS_BEEN_TRIGGERED)) OR bIgnoreTriggeredFlags PRINTLN( "MG_DO_SLOW_MO_EFFECT() is disabling slo-mo now") #IF USE_TU_CHANGES IF NOT NETWORK_IS_GAME_IN_PROGRESS() SET_TIME_SCALE(1.0) ENDIF #ENDIF // USE_TU_CHANGES #IF NOT USE_TU_CHANGES SET_TIME_SCALE(1.0) #ENDIF // NOT USE_TU_CHANGES ENDIF CLEAR_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_SLOW_MO_HAS_BEEN_TRIGGERED)) ENDIF ENDPROC PROC MG_DO_FAIL_EFFECT(BOOL bStart, BOOL bIgnoreTriggeredFlags = FALSE) STRING sEffect SWITCH GET_CURRENT_PLAYER_PED_ENUM() CASE CHAR_MICHAEL sEffect = "DeathFailMichaelIn" BREAK CASE CHAR_FRANKLIN sEffect = "DeathFailFranklinIn" BREAK CASE CHAR_TREVOR sEffect = "DeathFailTrevorIn" BREAK ENDSWITCH IF bStart = TRUE IF NOT IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_HAS_BEEN_TRIGGERED)) OR bIgnoreTriggeredFlags PRINTLN("MG_DO_FAIL_OUT_EFFECT() is starting effect now: ", sEffect) ANIMPOSTFX_PLAY(sEffect, 0, FALSE) SET_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_HAS_BEEN_TRIGGERED)) MG_DO_SLOW_MO_EFFECT(TRUE, 1) // trigger slow motion camera effect SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_INTRO) ENDIF ELSE IF IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_HAS_BEEN_TRIGGERED)) OR bIgnoreTriggeredFlags PRINTLN("MG_DO_FAIL_OUT_EFFECT() is disabling fail effect now: ", sEffect) ANIMPOSTFX_STOP(sEffect) MG_DO_SLOW_MO_EFFECT(FALSE, 1, TRUE) SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_INACTIVE) ENDIF CLEAR_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_HAS_BEEN_TRIGGERED)) ENDIF ENDPROC PROC MG_DO_FAIL_OUT_EFFECT(BOOL bStart, BOOL bIgnoreTriggeredFlags = FALSE) IF bStart = TRUE MG_DO_FAIL_EFFECT(FALSE) PRINTLN("MG_DO_FAIL_OUT_EFFECT() is starting fail out effect now") ANIMPOSTFX_PLAY("DeathFailOut", 0, FALSE) SET_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_FAIL_OUT_HAS_BEEN_TRIGGERED)) // super slow motion MG_DO_SLOW_MO_EFFECT(TRUE, 2) // trigger camera effect SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_OUTRO) ELSE IF IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_FAIL_OUT_HAS_BEEN_TRIGGERED)) OR bIgnoreTriggeredFlags PRINTLN("MG_DO_FAIL_OUT_EFFECT() is disabling fail out effect now") ANIMPOSTFX_STOP("DeathFailOut") MG_DO_SLOW_MO_EFFECT(FALSE, 2, TRUE) SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_INACTIVE) ENDIF CLEAR_BIT(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_FAIL_OUT_HAS_BEEN_TRIGGERED)) ENDIF ENDPROC //PROC MG_START_FAIL_BLUR_EFFECT(BOOL bStart) // // //ENDPROC FUNC BOOL MG_DO_FAIL_BLUR_EFFECT() //trigger blur effect and reset timer IF NOT IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_HAS_BEEN_TRIGGERED)) AND NOT IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_FAIL_OUT_HAS_BEEN_TRIGGERED)) SETTIMERA(0) MG_DO_FAIL_EFFECT(TRUE) ENDIF // things we need to block every frame // remove any god text / subtitles IF NOT IS_CUTSCENE_PLAYING() CLEAR_PRINTS() ENDIF // disable the pause menu during fail screen DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_MOVE_LR) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_MOVE_UD) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_AIM) SUPPRESS_AMBIENT_PED_AGGRESSIVE_CLEANUP_THIS_FRAME() IF TIMERA() > 1500 * FAIL_EFFECT_SLO_MO IF NOT IS_BIT_SET(iFailScreenBits, ENUM_TO_INT(MG_FAIL_BLUR_FAIL_OUT_HAS_BEEN_TRIGGERED)) // not started fail out effect, do it now + pause the game MG_DO_FAIL_OUT_EFFECT(TRUE) SETTIMERB(0) ELSE IF TIMERB() > 1500 * FAIL_OUT_EFFECT_SLO_MO OR IS_SCREEN_FADED_OUT() // used for skipping fail cut-scenes // --------finished fail out effect ------------------------------ // start fading out IF NOT IS_SCREEN_FADED_OUT() IF NOT IS_SCREEN_FADING_OUT() DO_SCREEN_FADE_OUT(1500) ENDIF ELSE IF iDelayTimer = 0 iDelayTimer = GET_GAME_TIMER() + 1000 // -------------screen has faded out-------------------------- // Do necessary setup, and then move on to showing the replay screen PRINTLN("Fail effect for script [", GET_THIS_SCRIPT_NAME(), "] completed.") // disable player control IF IS_PLAYER_PLAYING(PLAYER_ID()) SET_PLAYER_CONTROL(PLAYER_ID(), FALSE) ENDIF MG_DO_SLOW_MO_EFFECT(FALSE, 2, TRUE) SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE) DISABLE_CELLPHONE(TRUE) SET_FRONTEND_ACTIVE(FALSE) SET_PAUSE_MENU_ACTIVE(FALSE) CLEAR_HELP() CLEAR_PRINTS() // disable player control IF IS_PLAYER_PLAYING(PLAYER_ID()) SET_PLAYER_CONTROL(PLAYER_ID(), FALSE) ENDIF MG_DO_FAIL_EFFECT(FALSE) MG_DO_PAUSE_EFFECT(FALSE) ELSE IF GET_GAME_TIMER() < iDelayTimer RETURN TRUE ENDIF ENDIF ENDIF ELSE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Gets appropriate checkpoint alpha based on the player's distance from the checkpoint FUNC INT MG_GET_CHECKPOINT_ALPHA(VECTOR vCheckpointPos, INT iAMin = 25, INT iAMax = 200) FLOAT fDistMaxAlpha = 100.0 INT iA = 50 //add special min/max alpha distances depending on type of MG? FLOAT fDist IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) fDist = GET_DISTANCE_BETWEEN_COORDS(vCheckpointPos, GET_ENTITY_COORDS(PLAYER_PED_ID())) IF fDist > fDistMaxAlpha iA = iAMax ELSE FLOAT fMod = ( (fDistMaxAlpha-fDist) / (fDistMaxAlpha) ) iA = iAMax - CEIL((iAMax-iAMin) * fMod) //PRINTLN("MG_GET_CHECKPOINT_ALPHA: ", iA, " and fDis: ", fDist, "and fMod: ", fMod) ENDIF ENDIF IF iA < iAMin iA = iAMin ENDIF RETURN iA ENDFUNC /// PURPOSE: Gets appropriate checkpoint colour based on chevron type FUNC HUD_COLOURS MG_GET_RACE_CHECKPOINT_DEFAULT_COLOUR() RETURN HUD_COLOUR_YELLOW ENDFUNC /// PURPOSE: /// Checks if the vehicle is very large and needs its own respawn space /// Checks for blimps and helicopters. And some Planes. /// Please add vehicles as needed. /// PARAMS: /// vehPlayer - player's saved vehicle index /// RETURNS: /// TRUE if the vehicle should be moved to more open space for respawn. FUNC BOOL MINIGAME_DOES_VEHICLE_NEED_LARGE_RESPAWN_SPACE( VEHICLE_INDEX vehPlayer ) MODEL_NAMES eModel = GET_ENTITY_MODEL( vehPlayer ) SWITCH eModel CASE BLIMP RETURN TRUE CASE BLIMP2 RETURN TRUE CASE CARGOBOB RETURN TRUE CASE CARGOBOB2 RETURN TRUE CASE CARGOBOB3 RETURN TRUE CASE BUZZARD RETURN TRUE CASE BUZZARD2 RETURN TRUE CASE MAVERICK RETURN TRUE CASE POLMAV RETURN TRUE CASE SWIFT RETURN TRUE CASE VALKYRIE RETURN TRUE CASE ANNIHILATOR RETURN TRUE CASE FROGGER RETURN TRUE CASE FROGGER2 RETURN TRUE CASE DODO RETURN TRUE ENDSWITCH RETURN FALSE ENDFUNC // END OF FILE! DO NOT ADD ANYTHING BELOW THIS LINE!