//Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. USING "rage_builtins.sch" USING "globals.sch" USING "commands_script.sch" USING "script_clock.sch" USING "script_player.sch" USING "randomChar_private.sch" USING "blip_control_public.sch" USING "flow_public_core.sch" USING "RC_Setup_public.sch" // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // MISSION NAME : RandomChar_Controller.sc // AUTHOR : Keith // MAINTAINED : Andrew Minghella // DESCRIPTION : The Random Character Controller - ensures Random Characters // are allowed to activate at appropriate times. // // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** CONST_INT MAX_FRAMES_TO_PROCESS_MISSIONS 60 CONST_INT MAX_RC_BLIPS 20 INT iCurrentMissionFrame INT iRCMission, iBit, iBitset BOOL bRCBlipActive[MAX_RC_BLIPS] STATIC_BLIP_NAME_ENUM eRCBlips[MAX_RC_BLIPS] BOOL bRCBlipsTurnedOff TIMEOFDAY eTonya1HelpTime = INVALID_TIMEOFDAY #IF IS_DEBUG_BUILD g_eRC_MissionIDs eRCMissionToDebug = NO_RC_MISSION // Set this to print debug info for a particular RC mission only #ENDIF // -----------------------DEBUG FUNCTIONS --------------------------------------------- #IF IS_DEBUG_BUILD BOOL bOutputStates, bCompleteAll, bUnlockSpecificRC /// PURPOSE: /// Prints specified debug string if the RC mission being processed is the one specifed in eRCMissionToDebug /// PARAMS: /// eRCMission - the rc mission being processed /// sDebugString - the string to print PROC RC_CONTROLLER_DEBUG_PRINT(g_eRC_MissionIDs eRCMission, STRING sDebugString) IF eRCMissionToDebug <> NO_RC_MISSION AND eRCMission = eRCMissionToDebug CPRINTLN(DEBUG_RANDOM_CHAR, sDebugString) ENDIF ENDPROC /// PURPOSE: /// Creates RC Controller debug widgets PROC Setup_RC_Debug_Widgets() START_WIDGET_GROUP("Random Character Controller") ADD_WIDGET_BOOL("Output states", bOutputStates) ADD_WIDGET_BOOL("Complete All", bCompleteAll) ADD_WIDGET_BOOL("Unlock Barry 4", bUnlockSpecificRC) STOP_WIDGET_GROUP() ENDPROC /// PURPOSE: /// Maintains the RC Controller debug widgets PROC Maintain_RC_Debug_Widgets() IF bOutputStates CPRINTLN(DEBUG_RANDOM_CHAR, "Random Character States") INT iMission g_eRC_MissionIDs eRCMission g_structRCMissionsStatic sRCMissionDetails TEXT_LABEL_23 tlMissionName REPEAT MAX_RC_MISSIONS iMission eRCMission = INT_TO_ENUM(g_eRC_MissionIDs, iMission) Retrieve_Random_Character_Static_Mission_Details(eRCMission, sRCMissionDetails) tlMissionName = "'" tlMissionName += sRCMissionDetails.rcScriptName tlMissionName += "':" WHILE GET_LENGTH_OF_LITERAL_STRING(tlMissionName) < 20 tlMissionName+=" " ENDWHILE CPRINTLN(DEBUG_RANDOM_CHAR, "RC Mission ", tlMissionName, ": ", PICK_STRING(IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED)), "[Activated]", "[---------]"), PICK_STRING(IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY)), "[Ready To Play]", "[-------------]"), PICK_STRING(IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)), "[Completed]", "[---------]"), PICK_STRING(IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED_IN_FLOW)),"[Available In Flow]", "[-----------------]")) ENDREPEAT bOutputStates = FALSE ENDIF IF bCompleteAll = TRUE // debug for completing all RCs // Can skip flow to after all story missions and use this too // so all repeatable missions are available INT iMission FOR iMission = 0 TO ENUM_TO_INT(MAX_RC_MISSIONS)-1 Activate_RC_Mission(INT_TO_ENUM(g_eRC_MissionIDs, iMission), TRUE) ENDFOR bCompleteAll = FALSE ENDIF IF bUnlockSpecificRC = TRUE // sets certain RCs as complete so we can force one to unloc Activate_RC_Mission(RC_BARRY_1, TRUE) Activate_RC_Mission(RC_BARRY_2, TRUE) Activate_RC_Mission(RC_BARRY_3, TRUE) Activate_RC_Mission(RC_BARRY_3A, TRUE) Activate_RC_Mission(RC_BARRY_3C, TRUE) Execute_Code_ID(CID_BARRY4_TEXT_RECEIVED) bUnlockSpecificRC = FALSE ENDIF ENDPROC #ENDIF // -------------------FUNCTIONS--------------------------------------------------------- /// PURPOSE: Determines if the controller is allowed to run FUNC BOOL Is_Controller_Safe_To_Run() // Debug suspend checks #IF IS_DEBUG_BUILD IF NOT g_savedGlobals.sFlow.isGameflowActive AND NOT g_bRandomCharsAvailableInDebug RETURN FALSE ENDIF IF g_flowUnsaved.bUpdatingGameflow RETURN FALSE ENDIF IF g_disable_for_smoketest RETURN FALSE ENDIF #ENDIF // No issues found so assume it is safe to run RETURN TRUE ENDFUNC // =========================================================================================================== // Initialise // =========================================================================================================== /// PURPOSE: /// Intialises the default Random Character mission blip states PROC Initialise_Random_Character_Mission_Blips() // A pool of blips have been setup for all RC missions. // When an RC mission requires a blip, it must request one from the pool. eRCBlips[0] = STATIC_BLIP_RANDOMCHAR_00 eRCBlips[1] = STATIC_BLIP_RANDOMCHAR_01 eRCBlips[2] = STATIC_BLIP_RANDOMCHAR_02 eRCBlips[3] = STATIC_BLIP_RANDOMCHAR_03 eRCBlips[4] = STATIC_BLIP_RANDOMCHAR_04 eRCBlips[5] = STATIC_BLIP_RANDOMCHAR_05 eRCBlips[6] = STATIC_BLIP_RANDOMCHAR_06 eRCBlips[7] = STATIC_BLIP_RANDOMCHAR_07 eRCBlips[8] = STATIC_BLIP_RANDOMCHAR_08 eRCBlips[9] = STATIC_BLIP_RANDOMCHAR_09 eRCBlips[10] = STATIC_BLIP_RANDOMCHAR_10 eRCBlips[11] = STATIC_BLIP_RANDOMCHAR_11 eRCBlips[12] = STATIC_BLIP_RANDOMCHAR_12 eRCBlips[13] = STATIC_BLIP_RANDOMCHAR_13 eRCBlips[14] = STATIC_BLIP_RANDOMCHAR_14 eRCBlips[15] = STATIC_BLIP_RANDOMCHAR_15 eRCBlips[16] = STATIC_BLIP_RANDOMCHAR_16 eRCBlips[17] = STATIC_BLIP_RANDOMCHAR_17 eRCBlips[18] = STATIC_BLIP_RANDOMCHAR_18 eRCBlips[19] = STATIC_BLIP_RANDOMCHAR_19 INT iBlip REPEAT MAX_RC_BLIPS iBlip bRCBlipActive[iBlip] = FALSE SET_STATIC_BLIP_ACTIVE_STATE(eRCBlips[iBlip], FALSE) SET_STATIC_BLIP_MISSION_LAUNCH_LEVEL_LOCKED(eRCBlips[iBlip],MISSION_TYPE_RANDOM_CHAR) SET_STATIC_BLIP_CATEGORY(eRCBlips[iBlip], STATIC_BLIP_CATEGORY_RANDOMCHAR) SET_STATIC_BLIP_LONG_RANGE(eRCBlips[iBlip]) SET_STATIC_BLIP_COLOUR(eRCBlips[iBlip], BLIP_COLOUR_DEFAULT) SET_STATIC_BLIP_ICON(eRCBlips[iBlip], RADAR_TRACE_RANDOM_CHARACTER) RESET_STATIC_BLIP_CHARACTER_VISIBILITY(eRCBlips[iBlip]) ENDREPEAT ENDPROC /// PURPOSE: /// Checks to see if there are any free Random Character mission blip indexes /// PARAMS: /// iBlipIndex - the available blip index /// RETURNS: /// Returns TRUE if a valid index was found or already set FUNC BOOL Setup_Random_Character_Mission_Blip_Index(INT &iBlipIndex) // Already using a valid blip index IF iBlipIndex <> -1 RETURN TRUE ENDIF // Attempt to find a free blip INT iBlip REPEAT MAX_RC_BLIPS iBlip IF NOT bRCBlipActive[iBlip] iBlipIndex = iBlip bRCBlipActive[iBlip] = TRUE CPRINTLN(DEBUG_RANDOM_CHAR, "Setup_Random_Character_Mission_Blip_Index - Using index[", iBlipIndex, "].") RETURN TRUE ENDIF ENDREPEAT // Unable to find a valid blip index from the pool SCRIPT_ASSERT("Ran out of RC mission blips. Tell Andy Minghella.") RETURN FALSE ENDFUNC /// PURPOSE: /// Frees up the specified Random Character mission blip index /// PARAMS: /// iBlipIndex - the blip index you want to clear PROC Clear_Random_Character_Mission_Blip_Index(INT &iBlipIndex) IF iBlipIndex > -1 AND iBlipIndex < MAX_RC_BLIPS bRCBlipActive[iBlipIndex] = FALSE CPRINTLN(DEBUG_RANDOM_CHAR, "Clear_Random_Character_Mission_Blip_Index - Clearing index[", iBlipIndex, "].") ENDIF iBlipIndex = -1 ENDPROC // =========================================================================================================== // Process // =========================================================================================================== /// PURPOSE: /// Returns TRUE the mission isn't available during Exile and Michael and Trevor are currently exiled FUNC BOOL IS_MISSION_BLOCKED_DUE_TO_EXILE(BOOL bIsBlocked) IF bIsBlocked IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_TREVOR_EXILE_STARTED) AND NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_TREVOR_EXILE_FINISHED) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Returns true if the current time of day is within the specified range /// PARAMS: /// iStartTime - start of range /// iEndTime - end of range /// RETURNS: /// BOOL: true if in range, false otherwise FUNC BOOL IS_CURRENT_TIME_IN_RANGE(INT iStartTime, INT iEndTime) // Check the current time is valid INT iCurrentTime = ((GET_TIMEOFDAY_HOUR(GET_CURRENT_TIMEOFDAY())*100) + GET_TIMEOFDAY_MINUTE(GET_CURRENT_TIMEOFDAY())) // AM->PM IF iEndTime > iStartTime IF iCurrentTime < iStartTime OR iCurrentTime > iEndTime RETURN FALSE ENDIF // PM->AM ELSE IF iCurrentTime < iStartTime AND iCurrentTime > iEndTime RETURN FALSE ENDIF ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Return blip origin for area mission FUNC VECTOR GET_ORIGIN_FOR_AREA_MISSION(g_eRC_MissionIDs eRCMission) // Weed Stash IF eRCMission = RC_BARRY_3A RETURN << 1161.31, -1326.52, 34.23 >> ELIF eRCMission = RC_BARRY_3C RETURN << -533.15, -1691.25, 18.21 >> // Celebrity Theft ELIF eRCMission = RC_NIGEL_1A RETURN << -565.80, 293.14, 90.80 >> ELIF eRCMission = RC_NIGEL_1B RETURN << -1036.65, 363.59, 79.82 >> ELIF eRCMission = RC_NIGEL_1C RETURN << -620.37, -264.39, 37.81 >> ELIF eRCMission = RC_NIGEL_1D RETURN << -1115.96, 31.42, 53.80 >> // Photo Ops ELIF eRCMission = RC_PAPARAZZO_3A RETURN << 305.52, 157.19, 102.94 >> ELIF eRCMission = RC_PAPARAZZO_3B RETURN << 1040.96, -534.42, 60.17 >> ENDIF SCRIPT_ASSERT("RandomChar_Controller: Invalid mission passed to GET_ORIGIN_FOR_AREA_MISSION()") RETURN <<0,0,0>> ENDFUNC /// PURPOSE: /// Return blip origin for area mission FUNC FLOAT GET_RADIUS_FOR_AREA_MISSION(g_eRC_MissionIDs eRCMission) // Weed Stash IF eRCMission = RC_BARRY_3A OR eRCMission = RC_BARRY_3C RETURN 250.0 // Celebrity Theft ELIF eRCMission = RC_NIGEL_1A RETURN 35.0 ELIF eRCMission = RC_NIGEL_1B RETURN 37.5 ELIF eRCMission = RC_NIGEL_1C RETURN 45.0 ELIF eRCMission = RC_NIGEL_1D RETURN 150.0 // Photo Op ELIF eRCMission = RC_PAPARAZZO_3A OR eRCMission = RC_PAPARAZZO_3B RETURN 90.0 ENDIF SCRIPT_ASSERT("RandomChar_Controller: Invalid mission passed to GET_RADIUS_FOR_AREA_MISSION()") RETURN 250.0 ENDFUNC /// PURPOSE: /// Is the blip for this mission represented by an area? FUNC BOOL IS_AREA_MISSION(g_eRC_MissionIDs eRCMission) IF eRCMission = RC_BARRY_3A OR eRCMission = RC_BARRY_3C OR eRCMission = RC_NIGEL_1A OR eRCMission = RC_NIGEL_1B OR eRCMission = RC_NIGEL_1C OR eRCMission = RC_NIGEL_1D OR eRCMission = RC_PAPARAZZO_3A OR eRCMission = RC_PAPARAZZO_3B RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Set RC blip name once character has been discovered FUNC BOOL IS_RAMPAGE_MISSION(g_eRC_MissionIDs eRCMission) IF eRCMission = RC_RAMPAGE_1 OR eRCMission = RC_RAMPAGE_2 OR eRCMission = RC_RAMPAGE_3 OR eRCMission = RC_RAMPAGE_4 OR eRCMission = RC_RAMPAGE_5 RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL DOES_RAMPAGE_MISSION_NEED_A_CHECKMARK(g_eRC_MissionIDs eRCMission) IF NOT IS_RAMPAGE_MISSION(eRCMission) RETURN FALSE ENDIF INT iFirstRCPercentIndex = ENUM_TO_INT(CP_OJ_RAM1) INT i = ENUM_TO_INT(eRCMission) - ENUM_TO_INT(RC_RAMPAGE_1) IF (GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_ALL_RAMPAGES_UNLOCKED) = TRUE) RETURN TRUE ENDIF IF (g_savedGlobals.sRampageData.playerData[i].iMedalIndex >= ENUM_TO_INT(RAMPAGE_BRONZE)) RETURN TRUE ENDIF IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) RETURN TRUE ENDIF RETURN HAS_THIS_SCRIPT_BEEN_REGISTERED_IN_COMPLETION_PERCENTAGE_TOTAL(INT_TO_ENUM(enumCompletionPercentageEntries, iFirstRCPercentIndex + i), FALSE) ENDFUNC /// PURPOSE: /// Do multiple RC's exist at the same mission trigger FUNC BOOL ARE_MULTIPLE_MISSIONS_AVAILABLE_AT_SAME_LOCATE(g_eRC_MissionIDs eRCMission) IF eRCMission = RC_BARRY_1 OR eRCMission = RC_BARRY_2 // Both missions have been activated IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_1].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED)) AND IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_2].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED)) // Both missions haven't yet been completed IF NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) AND NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_2].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Has a RCM just completed at the same location as another RC trigger? FUNC BOOL HAS_MISSION_JUST_COMPLETED_AT_SAME_LOCATE(g_eRC_MissionIDs eRCMission) IF eRCMission = RC_BARRY_1 IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_2].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) AND g_RandomChars[RC_BARRY_2].rcLeaveAreaCheck = TRUE RETURN TRUE ENDIF ELIF eRCMission = RC_BARRY_2 IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) AND g_RandomChars[RC_BARRY_1].rcLeaveAreaCheck = TRUE RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Set RC blip name once character has been discovered PROC SET_BLIP_NAME_AND_COLOUR_FOR_RC_MISSION(STATIC_BLIP_NAME_ENUM name, g_eRC_MissionIDs eRCMission) // Set blip colour SET_STATIC_BLIP_COLOUR(name, BLIP_COLOUR_DEFAULT) // Blip name IF eRCMission = RC_ABIGAIL_2 SET_STATIC_BLIP_NAME(name, "B_ABI") ELIF eRCMission = RC_BARRY_1 OR eRCMission = RC_BARRY_2 OR eRCMission = RC_BARRY_3 OR eRCMission = RC_BARRY_4 // Barry is blipped by name if any Barry missions have been completed IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_2].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_3].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) SET_STATIC_BLIP_NAME(name, "B_BAR") ELSE SET_STATIC_BLIP_NAME(name, "BLIP_66") SET_STATIC_BLIP_ICON(name, RADAR_TRACE_RANDOM_CHARACTER) ENDIF ELIF eRCMission = RC_BARRY_3A OR eRCMission = RC_BARRY_3C SET_STATIC_BLIP_NAME(name, "B_STA") ELIF eRCMission = RC_DREYFUSS_1 SET_STATIC_BLIP_NAME(name, "B_DRE") ELIF eRCMission = RC_EPSILON_2 OR eRCMission = RC_EPSILON_3 OR eRCMission = RC_EPSILON_4 OR eRCMission = RC_EPSILON_5 OR eRCMission = RC_EPSILON_6 OR eRCMission = RC_EPSILON_7 OR eRCMission = RC_EPSILON_8 SET_STATIC_BLIP_NAME(name, "B_EPS") ELIF eRCMission = RC_EXTREME_2 OR eRCMission = RC_EXTREME_3 OR eRCMission = RC_EXTREME_4 SET_STATIC_BLIP_NAME(name, "B_EXT") ELIF eRCMission = RC_FANATIC_1 OR eRCMission = RC_FANATIC_2 OR eRCMission = RC_FANATIC_3 // Mary-Ann is blipped by name if any Fanatic missions have been completed IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_FANATIC_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_FANATIC_2].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_FANATIC_3].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) SET_STATIC_BLIP_NAME(name, "B_FAN") ELSE SET_STATIC_BLIP_NAME(name, "BLIP_66") SET_STATIC_BLIP_ICON(name, RADAR_TRACE_RANDOM_CHARACTER) ENDIF ELIF eRCMission = RC_HUNTING_2 SET_STATIC_BLIP_NAME(name, "B_HUN") ELIF eRCMission = RC_JOSH_2 OR eRCMission = RC_JOSH_3 OR eRCMission = RC_JOSH_4 SET_STATIC_BLIP_NAME(name, "B_JOS") ELIF eRCMission = RC_MINUTE_2 OR eRCMission = RC_MINUTE_3 SET_STATIC_BLIP_NAME(name, "B_MIN") ELIF eRCMission = RC_NIGEL_1A OR eRCMission = RC_NIGEL_1B OR eRCMission = RC_NIGEL_1C OR eRCMission = RC_NIGEL_1D SET_STATIC_BLIP_NAME(name, "B_CEL") ELIF eRCMission = RC_NIGEL_2 OR eRCMission = RC_NIGEL_3 SET_STATIC_BLIP_NAME(name, "B_NIG") ELIF eRCMission = RC_OMEGA_2 SET_STATIC_BLIP_NAME(name, "B_OME") ELIF eRCMission = RC_PAPARAZZO_2 OR eRCMission = RC_PAPARAZZO_3 OR eRCMission = RC_PAPARAZZO_4 SET_STATIC_BLIP_NAME(name, "B_PAP") ELIF eRCMission = RC_PAPARAZZO_3A OR eRCMission = RC_PAPARAZZO_3B SET_STATIC_BLIP_NAME(name, "B_PHO") ELIF eRCMission = RC_RAMPAGE_1 SET_STATIC_BLIP_NAME(name, "BLIP_66") ELIF eRCMission = RC_RAMPAGE_2 OR eRCMission = RC_RAMPAGE_3 OR eRCMission = RC_RAMPAGE_4 OR eRCMission = RC_RAMPAGE_5 SET_STATIC_BLIP_NAME(name, "BLIP_84") ELIF eRCMission = RC_TONYA_2 OR eRCMission = RC_TONYA_3 OR eRCMission = RC_TONYA_4 OR eRCMission = RC_TONYA_5 SET_STATIC_BLIP_NAME(name, "B_TON") ELSE SET_STATIC_BLIP_NAME(name, "BLIP_66") ENDIF ENDPROC /// PURPOSE: /// Checks for the moment at which the player reveals RC mission locations in the FOW, /// saves these results, and alters RC blip range settings appropriately. Optimised to /// check 1 RC per frame and save results into an extendable bitset. PROC UPDATE_RC_REVEALED_IN_FOW_CHECKS() //Step through one RC mission per frame and precalculate which bit and bitset to query for FOW visiblity. iRCMission++ iBit++ IF iRCMission >= ENUM_TO_INT(MAX_RC_MISSIONS) iRCMission = 0 iBit = 0 iBitset = 0 ELIF iBit > 31 iBit = 0 iBitset++ //Check we haven't overrun the number of bitsets we have. #IF IS_DEBUG_BUILD IF iBitset >= RC_MAX_FOW_VISIBLE_BITSETS SCRIPT_ASSERT("UPDATE_RC_VISIBLE_IN_FOW_CHECKS: Not enough bitsets to track FOW state of all RC missions. Increase RC_MAX_FOW_VISIBLE_BITSETS.") ENDIF #ENDIF ENDIF //CDEBUG3LN(DEBUG_RANDOM_CHAR, " Mission:", iRCMission, " Bit:", iBit, " Bitset:", iBitset) g_eRC_MissionIDs eRCMission = INT_TO_ENUM(g_eRC_MissionIDs, iRCMission) // Rampages 2-5 are not affected by the fog of war IF NOT IS_RAMPAGE_MISSION(eRCMission) OR eRCMission = RC_RAMPAGE_1 // Every frame check one RC mission to see if it has been revealed on the map. IF NOT IS_BIT_SET(g_savedGlobals.sRandomChars.g_iVisibleInFOWBitset[iBitset], iBit) CDEBUG3LN(DEBUG_RANDOM_CHAR, " Checking if ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission), " has been revealed in the FOW.") g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(eRCMission, sRCMissionDetails) // Automatically reveal Tonya 1. IF eRCMission = RC_TONYA_1 CPRINTLN(DEBUG_RANDOM_CHAR, " Flagging ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission), " as having been revealed in the FOW.") SET_BIT(g_savedGlobals.sRandomChars.g_iVisibleInFOWBitset[iBitset], iBit) // Query the FOW state to see if this RC has been revealed yet. ELIF GET_MINIMAP_FOW_COORDINATE_IS_REVEALED(sRCMissionDetails.rcCoords) CPRINTLN(DEBUG_RANDOM_CHAR, " Flagging ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission), " as having been revealed in the FOW.") SET_BIT(g_savedGlobals.sRandomChars.g_iVisibleInFOWBitset[iBitset], iBit) // If the RC hasn't been revealed and it's blip is long range then make it short range for now. ELIF g_RandomChars[eRCMission].rcBlipIndex != -1 IF bRCBlipActive[g_RandomChars[eRCMission].rcBlipIndex] IF IS_BIT_SET(g_GameBlips[eRCBlips[g_RandomChars[eRCMission].rcBlipIndex]].iSetting, STATIC_BLIP_SETTING_RADAR_LONG) CPRINTLN(DEBUG_RANDOM_CHAR, " Setting blip short range for ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission), ".") SET_STATIC_BLIP_SHORT_RANGE(eRCBlips[g_RandomChars[eRCMission].rcBlipIndex]) //SET_STATIC_BLIP_VISIBLE_STATE(eRCBlips[g_RandomChars[eRCMission].rcBlipIndex], FALSE) ENDIF ENDIF ENDIF //If the RC has been revealed and it's blip is short range then make it long range from now on. ELIF g_RandomChars[eRCMission].rcBlipIndex != -1 IF bRCBlipActive[g_RandomChars[eRCMission].rcBlipIndex] IF NOT IS_BIT_SET(g_GameBlips[eRCBlips[g_RandomChars[eRCMission].rcBlipIndex]].iSetting, STATIC_BLIP_SETTING_RADAR_LONG) CPRINTLN(DEBUG_RANDOM_CHAR, " Setting blip long range for ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission), ".") SET_STATIC_BLIP_LONG_RANGE(eRCBlips[g_RandomChars[eRCMission].rcBlipIndex]) //SET_STATIC_BLIP_VISIBLE_STATE(eRCBlips[g_RandomChars[eRCMission].rcBlipIndex], TRUE) ENDIF ENDIF ENDIF ENDIF ENDPROC PROC UPDATE_BEVERLY_UNLOCK_WILDLIFE_PHOTOGRAPHY() IF IS_LAST_GEN_PLAYER() IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_BEVERLY_SENT_WILDLIFE_TEXT) IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_PAPARAZZO_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) CPRINTLN(DEBUG_RANDOM_CHAR, "Paparazzo 1 completed and the player is from last-gen. Queueing Beverly text for Wildlife Photography.") #IF IS_FINAL_BUILD REGISTER_TEXT_MESSAGE_FROM_CHARACTER_TO_PLAYER(TEXT_PAP1_WILDLIFE_UNLOCK, CT_AMBIENT, BIT_FRANKLIN, CHAR_BEVERLY, 60000, 10000, VID_BLANK, CID_PAPARAZZO1_SEND_WILDLIFE_EMAIL) #ENDIF #IF IS_DEBUG_BUILD IF NOT g_flowUnsaved.bUpdatingGameflow IF NOT IS_BIT_SET(g_iDebugLaunchBlockCommunication, BIT_DBG_LNCH_COMM_BLOCK_WILDLIFE_PHOTO) REGISTER_TEXT_MESSAGE_FROM_CHARACTER_TO_PLAYER(TEXT_PAP1_WILDLIFE_UNLOCK, CT_AMBIENT, BIT_FRANKLIN, CHAR_BEVERLY, 60000, 10000, VID_BLANK, CID_PAPARAZZO1_SEND_WILDLIFE_EMAIL) ENDIF ENDIF CLEAR_BIT(g_iDebugLaunchBlockCommunication, BIT_DBG_LNCH_COMM_BLOCK_WILDLIFE_PHOTO) #ENDIF SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_BEVERLY_SENT_WILDLIFE_TEXT, TRUE) ENDIF ELSE // Check for Beverly being dead. If he is remove his text and jump straight to the Tourist Board email. IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_WILDLIFE_PHOTOGRAPHY_UNLOCKED) IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_PAPARAZZO_4].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) IF IS_COMMUNICATION_REGISTERED(TEXT_PAP1_WILDLIFE_UNLOCK) CPRINTLN(DEBUG_RANDOM_CHAR, "Beverly text for Wildlife Photography queued after Beverly has died.") CPRINTLN(DEBUG_RANDOM_CHAR, "Skipping directly to the Los Santos Tourist Board email.") CANCEL_COMMUNICATION(TEXT_PAP1_WILDLIFE_UNLOCK) Execute_Code_ID(CID_PAPARAZZO1_SEND_WILDLIFE_EMAIL, 0) ENDIF ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Handles making sure the help displays after passing Josh 1. PROC Do_Josh1_For_Sale_Signs_Help() IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_JOSH1_FOR_SALE) IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_JOSH_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) IF GET_FLOW_HELP_MESSAGE_STATUS("FS_HELP1") = FHS_EXPIRED ADD_HELP_TO_FLOW_QUEUE("FS_HELP1", FHP_MEDIUM, 0, 2000) ELIF GET_FLOW_HELP_MESSAGE_STATUS("FS_HELP1") = FHS_DISPLAYED SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_JOSH1_FOR_SALE) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Reminder help text when first entering an area blip for one of the Barry stash missions PROC Do_Barry3_Reminder_Help() // Reminder help text IF IS_PLAYER_PLAYING(PLAYER_ID()) IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_BARRY3_REMINDER_HELP) IF IS_RC_MISSION_AVAILABLE(RC_BARRY_3A) AND GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), GET_ORIGIN_FOR_AREA_MISSION(RC_BARRY_3A)) < GET_RADIUS_FOR_AREA_MISSION(RC_BARRY_3A) OR IS_RC_MISSION_AVAILABLE(RC_BARRY_3C) AND GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), GET_ORIGIN_FOR_AREA_MISSION(RC_BARRY_3C)) < GET_RADIUS_FOR_AREA_MISSION(RC_BARRY_3C) // Areas where you can find vehicles with a hidden stash are marked on the map. Search them to find vehicles for Barry. IF GET_FLOW_HELP_MESSAGE_STATUS("BARSTASH2") = FHS_EXPIRED ADD_HELP_TO_FLOW_QUEUE("BARSTASH2", FHP_MEDIUM, 0, 2000, DEFAULT_HELP_TEXT_TIME, BIT_FRANKLIN) ELIF GET_FLOW_HELP_MESSAGE_STATUS("BARSTASH2") = FHS_DISPLAYED SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_BARRY3_REMINDER_HELP) ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Reminder the player that they need to do Tonya1 to progress the gameflow. Keeps displaying /// if Tonya1 isn't completed after Family1. PROC Do_Tonya1_Reminder_Help() IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_RC_TONYA1_REMINDER) IF IS_PLAYER_PLAYING(PLAYER_ID()) IF GET_MISSION_COMPLETE_STATE(SP_MISSION_FAMILY_1) IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_RES_AND_RCS_UNLOCKED) IF eTonya1HelpTime = INVALID_TIMEOFDAY eTonya1HelpTime = GET_CURRENT_TIMEOFDAY() ADD_TIME_TO_TIMEOFDAY(eTonya1HelpTime, 0, 5) ELIF IS_NOW_AFTER_TIMEOFDAY(eTonya1HelpTime) CPRINTLN(DEBUG_RANDOM_CHAR, "Attempting to display Tonya1 blip reminder this frame.") BOOL bFoundBlip = FALSE INT iBlipIndex g_structRCMissionsStatic sRCMissionDetails FOR iBlipIndex = ENUM_TO_INT(STATIC_BLIP_RANDOMCHAR_00) TO ENUM_TO_INT(STATIC_BLIP_RANDOMCHAR_19) STATIC_BLIP_NAME_ENUM eRCBlip = INT_TO_ENUM(STATIC_BLIP_NAME_ENUM, iBlipIndex) Retrieve_Random_Character_Static_Mission_Details(RC_TONYA_1, sRCMissionDetails) IF ARE_VECTORS_EQUAL(sRCMissionDetails.rcCoords, GET_STATIC_BLIP_POSITION(eRCBlip)) IF DOES_BLIP_EXIST(g_GameBlips[eRCBlip].biBlip) CPRINTLN(DEBUG_RANDOM_CHAR, "Found Tonya1 blip. Displaying reminder.") //Found Tonya blip. Display help and flash blip. SET_BLIP_FLASHES(g_GameBlips[eRCBlip].biBlip, TRUE) SET_BLIP_FLASH_TIMER(g_GameBlips[eRCBlip].biBlip, 10000) SWITCH GET_CURRENT_PLAYER_PED_ENUM() CASE CHAR_FRANKLIN ADD_HELP_TO_FLOW_QUEUE("AM_H_RCFS", FHP_HIGH, 0, 1000) BREAK CASE CHAR_MICHAEL ADD_HELP_TO_FLOW_QUEUE("AM_H_RCFS_M", FHP_HIGH, 0, 1000) BREAK ENDSWITCH //Display help again in 5 game hours. eTonya1HelpTime = GET_CURRENT_TIMEOFDAY() ADD_TIME_TO_TIMEOFDAY(eTonya1HelpTime, 0, 0, 8) bFoundBlip = TRUE ENDIF ENDIF ENDFOR //Blip not found this pass. Try again in 5 game minutes. IF NOT bFoundBlip CPRINTLN(DEBUG_RANDOM_CHAR, "Couldn't find Tonya1 blip. Delaying next attempt for 5 in-game minutes.") eTonya1HelpTime = GET_CURRENT_TIMEOFDAY() ADD_TIME_TO_TIMEOFDAY(eTonya1HelpTime, 0, 5) ENDIF ENDIF ELSE SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_RC_TONYA1_REMINDER) ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Updates the flags and blip state for the specified Random Character mission /// PARAMS: /// eRCMission - the RC mission we are processing PROC Process_Random_Character_Mission_State(g_eRC_MissionIDs eRCMission) IF (eRCMission = NO_RC_MISSION) SCRIPT_ASSERT("ERROR: Process_Random_Character_Mission_State has been passed an illegal Random Character mission ID") EXIT ENDIF // Grab the mission details g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(eRCMission, sRCMissionDetails) //----- -----Mission flags-------------------------------------- // Clear the global force update flag seeing as we are now processing the mission g_RandomChars[eRCMission].rcForceStateUpdate = FALSE IF NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED_IN_FLOW)) IF NOT sRCMissionDetails.rcMustBeActivatedInFlow SET_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED_IN_FLOW)) ENDIF ENDIF IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED)) AND NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) // Set time delay when first activated IF NOT g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReqSet // Set the time TIMEOFDAY sStartTime = GET_CURRENT_TIMEOFDAY() ADD_TIME_TO_TIMEOFDAY(sStartTime, 0, 0, sRCMissionDetails.rcHoursToWaitReq, 0, 0, 0) // Last One mission unlocks a random time after 100% complete IF eRCMission = RC_THELASTONE // Unlocks between 3 and 10 hours INT iRandomHours = GET_RANDOM_INT_IN_RANGE(3, 11) iRandomHours *= 30 //B*1589468 get real hours CPRINTLN(DEBUG_RANDOM_CHAR, "The Last One RCM unlocking after ", iRandomHours, " hours") ADD_TIME_TO_TIMEOFDAY(sStartTime, 0, 0, iRandomHours, 0, 0, 0) ENDIF #IF IS_DEBUG_BUILD TEXT_LABEL_63 tlTime = TIMEOFDAY_TO_TEXT_LABEL(sStartTime) TEXT_LABEL_7 tlName = GET_RC_MISSION_NAME_LABEL(eRCMission) CPRINTLN(DEBUG_RANDOM_CHAR,"RC Mission ",tlName," set to start on ",tlTime) #ENDIF g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReq = sStartTime g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReqSet = TRUE ENDIF IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED_IN_FLOW)) IF NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY)) // Set ready to play and then check for any fail conditions BOOL bReadyToPlay = TRUE // Check flow flag state IF sRCMissionDetails.rcFlowFlagReq <> FLOWFLAG_NONE IF NOT Get_Mission_Flow_Flag_State(sRCMissionDetails.rcFlowFlagReq) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "Get_Mission_Flow_Flag_State = FALSE, set bReadyToPlay as FALSE") #ENDIF bReadyToPlay = FALSE ENDIF ENDIF // Check whether mission is blocked due to a specific story mission IF Random_Character_Blocked_Due_To_Mission(eRCMission) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "Random_Character_Blocked_Due_To_Mission, set bReadyToPlay as FALSE") #ENDIF bReadyToPlay = FALSE ENDIF // Check whether mission is blocked due to being wanted IF Random_Character_Blocked_Due_To_Wanted_Level(eRCMission) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "Random_Character_Blocked_Due_To_Wanted_Level, set bReadyToPlay as FALSE") #ENDIF bReadyToPlay = FALSE ENDIF // Check whether mission is blocked due to Michael and Trevor IF IS_MISSION_BLOCKED_DUE_TO_EXILE(sRCMissionDetails.bBlockedInExile) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "IS_MISSION_BLOCKED_DUE_TO_EXILE, set bReadyToPlay as FALSE") #ENDIF bReadyToPlay = FALSE ENDIF // Check the time delay requirement IF sRCMissionDetails.rcHoursToWaitReq > 0 AND bReadyToPlay IF NOT IS_NOW_AFTER_TIMEOFDAY(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReq) //Check if the time left to wait is not absurdly large (> 2 weeks in-game) INT iSec, iMinute, iHour, iDays,iMonths, iYears GET_DIFFERENCE_BETWEEN_NOW_AND_TIMEOFDAY(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReq,iSec, iMinute,iHour,iDays,iMonths,iYears) IF (iYears>0) OR (iMonths > 0) OR (iDays > 10) TEXT_LABEL_63 strTod TEXT_LABEL_7 strRCM = GET_RC_MISSION_NAME_LABEL(INT_TO_ENUM(g_eRC_MissionIDs,eRCMission)) #IF IS_DEBUG_BUILD GET_TIMEOFDAY_STRING(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReq,strTod,TRUE,TRUE) PRINT_TIMEOFDAY(GET_CURRENT_TIMEOFDAY(),debug_random_char) #ENDIF CERRORLN(DEBUG_RANDOM_CHAR,"See bug 2135359: Time till random char mission '", strRCM ,"' is very long (over 10 days), supposed to start on ", strTod," resetting to current + wait time (",sRCMissionDetails.rcHoursToWaitReq,")") g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReq = GET_CURRENT_TIMEOFDAY() ADD_TIME_TO_TIMEOFDAY(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcTimeReq, 0, 0, sRCMissionDetails.rcHoursToWaitReq, 0, 0, 0) ENDIF #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "IS_NOW_AFTER_TIMEOFDAY, set bReadyToPlay as FALSE") #ENDIF bReadyToPlay = FALSE ENDIF ENDIF // Check the current time is valid IF NOT IS_CURRENT_TIME_IN_RANGE(sRCMissionDetails.rcStartTime, sRCMissionDetails.rcEndTime) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "Time of day outside restrictions, set bReadyToPlay as FALSE") #ENDIF bReadyToPlay = FALSE ENDIF // Mark as Ready To Play if no issues found IF bReadyToPlay CPRINTLN(DEBUG_RANDOM_CHAR, "RC mission ", sRCMissionDetails.rcScriptName, " is ready to launch.") SET_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY)) g_RandomChars[eRCMission].rcIsRunning = FALSE g_RandomChars[eRCMission].rcFailed = FALSE g_RandomChars[eRCMission].rcPassed = FALSE #IF IS_DEBUG_BUILD IF g_eDebugLaunchingToRCMission = eRCMission CPRINTLN(DEBUG_RANDOM_CHAR, "Leave area check for RC mission ", sRCMissionDetails.rcScriptName, " was skipped due to debug launch.") ELSE #ENDIF // Special cases IF eRCMission = RC_MRS_PHILIPS_1 // We want it to appear when player gets control at the end of the game. g_RandomChars[eRCMission].rcLeaveAreaCheck = FALSE REACTIVATE_NAMED_WORLD_BRAINS_WAITING_TILL_OUT_OF_RANGE("launcher_MrsPhilips") ELIF eRCMission = RC_TONYA_1 // We want it to appear as soon as we finish Armenian 2 to encourage the player to trigger it immediately. g_RandomChars[eRCMission].rcLeaveAreaCheck = FALSE REACTIVATE_NAMED_WORLD_BRAINS_WAITING_TILL_OUT_OF_RANGE("launcher_Tonya") ELSE // Fix for bug #324493 - Force player to leave area before activating the blip CPRINTLN(DEBUG_RANDOM_CHAR, "Leave area flag set for RC mission ", sRCMissionDetails.rcScriptName, ".") g_RandomChars[eRCMission].rcLeaveAreaCheck = TRUE ENDIF #IF IS_DEBUG_BUILD ENDIF #ENDIF ENDIF ENDIF ENDIF ENDIF // Check some runtime flags IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY)) AND NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) BOOL bOkToLaunch = TRUE // Check whether mission is blocked due to a specific story mission IF Random_Character_Blocked_Due_To_Mission(eRCMission) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "Random_Character_Blocked_Due_To_Mission, set bReadyToPlay as FALSE") #ENDIF bOkToLaunch = FALSE ENDIF // Check for wanted update IF Random_Character_Blocked_Due_To_Wanted_Level(eRCMission) bOkToLaunch = FALSE ENDIF // Check for Exile flag update... IF IS_MISSION_BLOCKED_DUE_TO_EXILE(sRCMissionDetails.bBlockedInExile) bOkToLaunch = FALSE ENDIF // Still ok? IF bOkToLaunch // Are we still within the required time of day? IF NOT IS_CURRENT_TIME_IN_RANGE(sRCMissionDetails.rcStartTime, sRCMissionDetails.rcEndTime) #IF IS_DEBUG_BUILD RC_CONTROLLER_DEBUG_PRINT(eRCMission, "Time of day outside restrictions, set bOkToLaunch as FALSE") #ENDIF bOkToLaunch = FALSE ENDIF ENDIF // Mission no longer ready as either blocked by exile or gone past TOD restriction... IF NOT bOkToLaunch CPRINTLN(DEBUG_RANDOM_CHAR, "RC mission ", sRCMissionDetails.rcScriptName, " is no longer ready to play.") CLEAR_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY)) ENDIF ENDIF // RC Missions set the rcIsAwaitingTrigger flag to TRUE when waiting for the player // to trigger the created ped. // To keep things clean we have made this a reset flag, which means that it will only // stay TRUE for the frame that it was set. With this in mind, we can set the appropriate // blip state and force a mission update the following frame. BOOL bReadyToTrigger = TRUE // Should always display unless still in range and no longer triggerable IF g_RandomChars[eRCMission].rcIsAwaitingTrigger // We reach this point every frame that the character is ready to trigger, // as well as the first frame after the mission has cleaned up. g_RandomChars[eRCMission].rcForceStateUpdate = TRUE g_RandomChars[eRCMission].rcIsAwaitingTrigger = FALSE g_RandomChars[eRCMission].rcLeaveAreaCheck = TRUE ELSE IF g_RandomChars[eRCMission].rcLeaveAreaCheck // RCM strands can now have different brain activation ranges FLOAT fRCActivationRange IF sRCMissionDetails.rcStrandID = RCS_ABIGAIL OR sRCMissionDetails.rcStrandID = RCS_DREYFUSS OR sRCMissionDetails.rcStrandID = RCS_EPSILON OR sRCMissionDetails.rcStrandID = RCS_MRS_PHILIPS OR sRCMissionDetails.rcStrandID = RCS_THELASTONE OR sRCMissionDetails.rcStrandID = RCS_TONYA fRCActivationRange = RC_BRAIN_ACTIVATION_RANGE_NORMAL ELSE fRCActivationRange = RC_BRAIN_ACTIVATION_RANGE_EXTRA ENDIF // Don't do this check if a replay is being processed- to prevent this being reset whilst things for replay load (player warp etc) IF NOT IS_REPLAY_BEING_PROCESSED() AND (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), sRCMissionDetails.rcCoords, FALSE) > fRCActivationRange) // If the blips are appearing too soon then we need to add some sort of timer here. // We would also need to tie the timer into the 'is rc mission safe to run' checks. CPRINTLN(DEBUG_RANDOM_CHAR, "Player left area for RC mission ", sRCMissionDetails.rcScriptName) g_RandomChars[eRCMission].rcLeaveAreaCheck = FALSE ELSE // Still waiting for player to leave so not safe to trigger CPRINTLN(DEBUG_RANDOM_CHAR, "RC mission ", sRCMissionDetails.rcScriptName, " is waiting for player to leave the area.") // Below IF statement - fixes B*2204739 - Random Char controller was waiting for the player to leave, but the door was unlocked and quicksaves allowed IF eRCMission = RC_EPSILON_2 AND g_savedGlobals.sBuildingData.eDoorState[DOORNAME_EPSILON2_STORAGE_ROOM] <> DOORSTATE_LOCKED CPRINTLN(DEBUG_RANDOM_CHAR, "Locking Epsilon 2 storeroom door...") SET_DOOR_STATE(DOORNAME_EPSILON2_STORAGE_ROOM, DOORSTATE_LOCKED) ENDIF bReadyToTrigger = FALSE ENDIF ENDIF ENDIF // ----------------Mission blips-------------------------------------------------------- g_eRC_BlipState eBlipState = RC_BLIP_TURNED_OFF IF bReadyToTrigger AND NOT (IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))) AND (IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED))) AND (IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED_IN_FLOW))) AND (IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY))) // B*1306406 - Don't display first Tonya blip until Armenian 2 results screen has finished IF eRCMission = RC_TONYA_1 AND IS_RESULT_SCREEN_DISPLAYING() ELSE eBlipState = RC_BLIP_READY_TO_TRIGGER ENDIF ENDIF // Only process if the state has changed IF g_RandomChars[eRCMission].rcBlipState <> eBlipState // Make sure we have a valid blip index from the pool IF Setup_Random_Character_Mission_Blip_Index(g_RandomChars[eRCMission].rcBlipIndex) // Ignore in the event that the RC mission doesn't have a defined blip (e.g. Tonya 3&4) IF ARE_VECTORS_EQUAL(sRCMissionDetails.rcCoords, <<0,0,0>>) ELSE STATIC_BLIP_NAME_ENUM eBlip = eRCBlips[g_RandomChars[eRCMission].rcBlipIndex] IF eBlipState = RC_BLIP_TURNED_OFF // Turn off the blip and free up the blip index CPRINTLN(DEBUG_RANDOM_CHAR, "RC_BLIP_TURNED_OFF ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission)) SET_STATIC_BLIP_ACTIVE_STATE(eBlip, FALSE) SET_STATIC_BLIP_HAS_CHECKMARK(eBlip, FALSE) Clear_Random_Character_Mission_Blip_Index(g_RandomChars[eRCMission].rcBlipIndex) ELIF eBlipState = RC_BLIP_READY_TO_TRIGGER CPRINTLN(DEBUG_RANDOM_CHAR, "RC_BLIP_READY_TO_TRIGGER ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(eRCMission)) // Area blips for Barry weed stash and Nigel theft missions IF IS_AREA_MISSION(eRCMission) SET_STATIC_BLIP_AS_AREA_BLIP(eBlip, TRUE) SET_STATIC_BLIP_POSITION(eBlip, GET_ORIGIN_FOR_AREA_MISSION(eRCMission)) SET_STATIC_BLIP_RADIUS(eBlip, GET_RADIUS_FOR_AREA_MISSION(eRCMission)) ELSE SET_STATIC_BLIP_AS_AREA_BLIP(eBlip, FALSE) SET_STATIC_BLIP_ICON(eBlip, sRCMissionDetails.rcBlipSprite) SET_STATIC_BLIP_POSITION(eBlip, sRCMissionDetails.rcCoords) ENDIF // Set blip name based on character name SET_BLIP_NAME_AND_COLOUR_FOR_RC_MISSION(eBlip, eRCMission) // Set up the blip states that are specific to this mission, this includes // character visibility, icon, colour, position etc. RESET_STATIC_BLIP_CHARACTER_VISIBILITY(eBlip) IF IS_MISSION_TRIGGERABLE_BY_CHARACTER(sRCMissionDetails.rcPlayableChars, CHAR_FRANKLIN) SET_STATIC_BLIP_CHARACTER_VISIBILITY(eBlip, TRUE, CHAR_FRANKLIN) ENDIF IF IS_MISSION_TRIGGERABLE_BY_CHARACTER(sRCMissionDetails.rcPlayableChars, CHAR_MICHAEL) SET_STATIC_BLIP_CHARACTER_VISIBILITY(eBlip, TRUE, CHAR_MICHAEL) ENDIF IF IS_MISSION_TRIGGERABLE_BY_CHARACTER(sRCMissionDetails.rcPlayableChars, CHAR_TREVOR) SET_STATIC_BLIP_CHARACTER_VISIBILITY(eBlip, TRUE, CHAR_TREVOR) ENDIF // B*1566342: Rampage 2-5 are short range IF IS_RAMPAGE_MISSION(eRCMission) AND eRCMission <> RC_RAMPAGE_1 SET_STATIC_BLIP_SHORT_RANGE(eBlip) ENDIF // B*1565201: Rampage Blips Should have a tick mark if completed IF IS_RAMPAGE_MISSION(eRCMission) IF DOES_RAMPAGE_MISSION_NEED_A_CHECKMARK(eRCMission) SET_STATIC_BLIP_HAS_CHECKMARK(eBlip, TRUE) ENDIF ENDIF // Set category and activate. IF eRCMission = RC_TONYA_1 SET_STATIC_BLIP_CATEGORY(eBlip, STATIC_BLIP_CATEGORY_MISSION) //Tonya 1 blip should behave like a mission blip. ELSE SET_STATIC_BLIP_CATEGORY(eBlip, STATIC_BLIP_CATEGORY_RANDOMCHAR) ENDIF SET_STATIC_BLIP_ACTIVE_STATE(eBlip, TRUE) ENDIF ENDIF // Update the stored state so we only perform blip updates once g_RandomChars[eRCMission].rcBlipState = eBlipState ENDIF ENDIF // Display blip help text if we haven't done so already IF NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_BLIP_HELP_DISPLAYED)) // No help text for this mission IF GET_HASH_KEY(sRCMissionDetails.rcBlipHelp) = GET_HASH_KEY("") SET_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_BLIP_HELP_DISPLAYED)) ELSE // RCM ready to trigger... IF eBlipState = RC_BLIP_READY_TO_TRIGGER IF Is_Mission_Triggerable_By_Character(sRCMissionDetails.rcPlayableChars, GET_CURRENT_PLAYER_PED_ENUM()) // Prevent from triggering if timetable scene or player switch is in progress IF NOT Is_Player_Timetable_Scene_In_Progress() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() // Help message isn't already onscreen IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() // Flash Tonya 1 blip IF eRCMission = RC_TONYA_1 IF IS_STATIC_BLIP_CURRENTLY_VISIBLE_TO_SYSTEM(STATIC_BLIP_RANDOMCHAR_00) IF IS_STATIC_BLIP_CURRENTLY_VISIBLE(STATIC_BLIP_RANDOMCHAR_00) ADD_HELP_TO_FLOW_QUEUE(sRCMissionDetails.rcBlipHelp, FHP_MEDIUM, 0, FLOW_HELP_NEVER_EXPIRES, DEFAULT_HELP_TEXT_TIME, sRCMissionDetails.rcPlayableChars) EXECUTE_CODE_ID(CID_FLASH_RANDOM_CHAR_BLIPS, 1000) SET_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_BLIP_HELP_DISPLAYED)) ENDIF ENDIF // Area sub-mission help text delayed by 5 seconds (afeter text/email is received) ELIF (eRCMission = RC_BARRY_3A OR eRCMission = RC_NIGEL_1A OR eRCMission = RC_PAPARAZZO_3A) ADD_HELP_TO_FLOW_QUEUE(sRCMissionDetails.rcBlipHelp, FHP_MEDIUM, 5000, FLOW_HELP_NEVER_EXPIRES, DEFAULT_HELP_TEXT_TIME, sRCMissionDetails.rcPlayableChars) SET_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_BLIP_HELP_DISPLAYED)) // Otherwise display help text as soon as possible ELSE ADD_HELP_TO_FLOW_QUEUE(sRCMissionDetails.rcBlipHelp, FHP_MEDIUM, 0, FLOW_HELP_NEVER_EXPIRES, DEFAULT_HELP_TEXT_TIME, sRCMissionDetails.rcPlayableChars) SET_BIT(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_BLIP_HELP_DISPLAYED)) ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF // Check for being near RCM blip as an incorrect character IF IS_PLAYER_PLAYING(PLAYER_ID()) IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_NEAR_FIRST_RCM_AS_WRONG_CHAR) // Make sure this mission hasn't already been completed IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_READY_TO_PLAY)) AND NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) IF NOT IS_MISSION_TRIGGERABLE_BY_CHARACTER(sRCMissionDetails.rcPlayableChars, GET_CURRENT_PLAYER_PED_ENUM()) AND NOT IS_AREA_MISSION(eRCMission) AND NOT IS_RAMPAGE_MISSION(eRCMission) AND NOT ARE_MULTIPLE_MISSIONS_AVAILABLE_AT_SAME_LOCATE(eRCMission) AND NOT HAS_MISSION_JUST_COMPLETED_AT_SAME_LOCATE(eRCMission) AND NOT g_RandomChars[eRCMission].rcLeaveAreaCheck IF VDIST2(sRCMissionDetails.rcCoords, GET_ENTITY_COORDS(PLAYER_PED_ID())) < 81 STRING strHelp = "" IF IS_BIT_SET(sRCMissionDetails.rcPlayableChars, ENUM_TO_INT(CHAR_FRANKLIN)) strHelp = "TRIG_RC_F" ELIF IS_BIT_SET(sRCMissionDetails.rcPlayableChars, ENUM_TO_INT(CHAR_MICHAEL)) strHelp = "TRIG_RC_M" ELSE strHelp = "TRIG_RC_T" ENDIF IF NOT IS_STRING_NULL_OR_EMPTY(strHelp) SWITCH GET_FLOW_HELP_MESSAGE_STATUS(strHelp) CASE FHS_EXPIRED ADD_HELP_TO_FLOW_QUEUE(strHelp, FHP_MEDIUM, 0, 1000, DEFAULT_HELP_TEXT_TIME, GET_CURRENT_PLAYER_PED_BIT()) BREAK CASE FHS_DISPLAYED SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_NEAR_FIRST_RCM_AS_WRONG_CHAR) g_txtFlowHelpLastDisplayed = "" BREAK ENDSWITCH ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Turns off all Random Character mission blips PROC Turn_Off_Random_Character_Mission_Blips() g_eRC_MissionIDs eRCMission INT iBlip REPEAT MAX_RC_BLIPS iBlip SET_STATIC_BLIP_ACTIVE_STATE(eRCBlips[iBlip], FALSE) bRCBlipActive[iBlip] = FALSE ENDREPEAT INT iMission REPEAT MAX_RC_MISSIONS iMission eRCMission = INT_TO_ENUM(g_eRC_MissionIDs, iMission) IF g_RandomChars[eRCMission].rcBlipIndex <> -1 SET_STATIC_BLIP_ACTIVE_STATE(eRCBlips[g_RandomChars[eRCMission].rcBlipIndex], FALSE) Clear_Random_Character_Mission_Blip_Index(g_RandomChars[eRCMission].rcBlipIndex) ENDIF g_RandomChars[eRCMission].rcBlipState = RC_BLIP_TURNED_OFF ENDREPEAT bRCBlipsTurnedOff = TRUE ENDPROC // =========================================================================================================== // Cleanup // =========================================================================================================== /// PURPOSE: /// Ensures script gets a chance to cleanup under specific circumstances (ie: moving from SP to MP) PROC Script_Cleanup() Turn_Off_Random_Character_Mission_Blips() CPRINTLN(DEBUG_RANDOM_CHAR, "RandomChar_controller cleaned up.") TERMINATE_THIS_THREAD() ENDPROC // =========================================================================================================== // Script Loop // =========================================================================================================== SCRIPT // This script needs to cleanup only when the game moves from SP to MP IF (HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_MAGDEMO)) CPRINTLN(DEBUG_RANDOM_CHAR, "RandomChar_controller.sc has been forced to cleanup (SP to MP)") Script_Cleanup() ENDIF #IF IS_DEBUG_BUILD Setup_RC_Debug_Widgets() #ENDIF // Initialise RC missions + blips Initialise_Random_Character_Dynamic_Mission_Details() Initialise_Random_Character_Mission_Blips() WHILE (TRUE) WAIT(0) // We have gone on mission IF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_RANDOM_CHAR) OR g_bPlayerLockedInToTrigger CPRINTLN(DEBUG_RANDOM_CHAR, "RandomChar_controller cleaning up as we have gone on mission...") Script_Cleanup() ENDIF #IF IS_DEBUG_BUILD Maintain_RC_Debug_Widgets() #ENDIF IF Is_Controller_Safe_To_Run() // Allow the blips when controller is safe to run bRCBlipsTurnedOff = FALSE // Update the frame that we are processing iCurrentMissionFrame = (iCurrentMissionFrame+1) % MAX_FRAMES_TO_PROCESS_MISSIONS INT iMission REPEAT MAX_RC_MISSIONS iMission // Only perform an update if this mission matches the current frame or has global update flag set IF (iMission % MAX_FRAMES_TO_PROCESS_MISSIONS) = iCurrentMissionFrame OR g_RandomChars[iMission].rcForceStateUpdate Process_Random_Character_Mission_State(INT_TO_ENUM(g_eRC_MissionIDs, iMission)) ENDIF ENDREPEAT UPDATE_RC_REVEALED_IN_FOW_CHECKS() UPDATE_BEVERLY_UNLOCK_WILDLIFE_PHOTOGRAPHY() // Mission help text Do_Barry3_Reminder_Help() Do_Josh1_For_Sale_Signs_Help() Do_Tonya1_Reminder_Help() ELSE // Controller not safe to run so turn off all blips IF NOT bRCBlipsTurnedOff Turn_Off_Random_Character_Mission_Blips() ENDIF ENDIF ENDWHILE // Script should never reach here. Always terminate with cleanup function. ENDSCRIPT