////////////////////////////////////////////////////////////////////////////////////////// // // // SCRIPT NAME : forSaleSigns.sc // // AUTHOR : Kenneth Ross // // DESCRIPTION : Sets up 15 For Sale signs around the map for the player to // // smash up. // // // ////////////////////////////////////////////////////////////////////////////////////////// //Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. // Includes USING "rage_builtins.sch" USING "globals.sch" USING "commands_script.sch" USING "commands_entity.sch" USING "commands_streaming.sch" USING "commands_object.sch" USING "dialogue_public.sch" USING "script_player.sch" USING "flow_public_core.sch" USING "CompletionPercentage_public.sch" USING "savegame_public.sch" USING "common_packages.sch" USING "RC_helper_functions.sch" // Variables MISSION_STAGE eStage = STAGE_INITIALISE MODEL_NAMES eSignModel = PROP_FORSALE_LENNY_01 BOOL bDisplayMessage = FALSE INT iMessageStage = 0 SCALEFORM_INDEX siMessage BOOL bDoPostJosh1 = FALSE INT iConvTimer PED_INDEX pedJosh structPedsForConversation ConvStruct SCRAP_PICKUP_DATA sSign[NUMBER_OF_FOR_SALE_SIGNS] BOOL bMessageOnDisplay // Debug #IF IS_DEBUG_BUILD USING "shared_debug.sch" // Widgets WIDGET_GROUP_ID widgetGroup BOOL bOutputAllTempCoords BOOL bOutputTempCoords[NUMBER_OF_FOR_SALE_SIGNS] BOOL bUpdatePositions BOOL bResetTempPositions BOOL bWarpToSign[NUMBER_OF_FOR_SALE_SIGNS] BOOL bUseTempPos[NUMBER_OF_FOR_SALE_SIGNS] FLOAT fTempScrapHeading[NUMBER_OF_FOR_SALE_SIGNS] VECTOR vTempScrapCoords[NUMBER_OF_FOR_SALE_SIGNS] BOOL bMapAllsSign BOOL bDestroyAllSigns /// PURPOSE: /// Creates widgets to teleport Player to the locations, blip locations etc PROC SETUP_FOR_SALE_WIDGETS() INT iScrap TEXT_LABEL_63 tlTemp widgetGroup = START_WIDGET_GROUP("For Sale Signs") ADD_WIDGET_BOOL("Show all signs on map", bMapAllsSign) ADD_WIDGET_BOOL("Destroy all signs", bDestroyAllSigns) START_WIDGET_GROUP("Positions") ADD_WIDGET_BOOL("bUpdatePositions", bUpdatePositions) ADD_WIDGET_BOOL("bResetTempPositions", bResetTempPositions) ADD_WIDGET_BOOL("bOutputAllTempCoords", bOutputAllTempCoords) REPEAT NUMBER_OF_FOR_SALE_SIGNS iScrap tlTemp = "Sign[" tlTemp += iScrap tlTemp += "]" START_WIDGET_GROUP(tlTemp) ADD_WIDGET_BOOL("bWarp", bWarpToSign[iScrap]) ADD_WIDGET_BOOL("bUseTempPos", bUseTempPos[iScrap]) ADD_WIDGET_FLOAT_SLIDER("fHeading", fTempScrapHeading[iScrap], 0.0, 360.0, 1.0) ADD_WIDGET_VECTOR_SLIDER("vCoords", vTempScrapCoords[iScrap], -4000.0, 4000.0, 0.1) ADD_WIDGET_BOOL("bOutputTempCoords", bOutputTempCoords[iScrap]) STOP_WIDGET_GROUP() ENDREPEAT STOP_WIDGET_GROUP() START_WIDGET_GROUP("Flags") ADD_BIT_FIELD_WIDGET("iForSaleSignDestroyedFlags", g_savedGlobals.sAmbient.iForSaleSignDestroyedFlags) STOP_WIDGET_GROUP() STOP_WIDGET_GROUP() ENDPROC /// PURPOSE: /// Sorts out the correct functionality depending on if any widgets are selected PROC MAINTAIN_FOR_SALE_WIDGETS() INT iScrap REPEAT NUMBER_OF_FOR_SALE_SIGNS iScrap // Some signs need different wrap coords to make sure the Playeris warped safely IF (iScrap = 5) CHECK_WARP_TO_PACKAGE(bWarpToSign[iScrap], <<-381.1934, 430.2234, 111.2149>>) ELIF (iScrap = 6) CHECK_WARP_TO_PACKAGE(bWarpToSign[iScrap], <<-161.3442, 990.9147, 233.8630>>) ELIF (iScrap = 14) CHECK_WARP_TO_PACKAGE(bWarpToSign[iScrap], <<-1164.6997, 321.7902, 68.1655>>) ELSE CHECK_WARP_TO_PACKAGE(bWarpToSign[iScrap], sSign[iScrap].vCoords) ENDIF MAP_SCRAP_CHECK(bMapAllsSign, sSign[iScrap].blip, iScrap, NUMBER_OF_FOR_SALE_SIGNS, SCRAP_SALE_SIGNS, sSign[iScrap].vCoords) IF bDestroyAllSigns SET_BIT(g_savedGlobals.sAmbient.iForSaleSignDestroyedFlags, iScrap) bDisplayMessage = TRUE ENDIF IF bUpdatePositions IF DOES_ENTITY_EXIST(sSign[iScrap].obj) IF bUseTempPos[iScrap] SAFE_TELEPORT_ENTITY(sSign[iScrap].obj, vTempScrapCoords[iScrap], fTempScrapHeading[iScrap]) SET_ENTITY_HEADING(sSign[iScrap].obj, fTempScrapHeading[iScrap]) ELSE SAFE_TELEPORT_ENTITY(sSign[iScrap].obj, sSign[iScrap].vCoords, sSign[iScrap].fHeading) ENDIF ENDIF ENDIF IF bOutputTempCoords[iScrap] OR bOutputAllTempCoords OUTPUT_TEMP_DATA(vTempScrapCoords[iScrap], fTempScrapHeading[iScrap], iScrap) bOutputTempCoords[iScrap] = FALSE ENDIF IF bResetTempPositions vTempScrapCoords[iScrap] = sSign[iScrap].vCoords fTempScrapHeading[iScrap] = sSign[iScrap].fHeading ENDIF ENDREPEAT bDestroyAllSigns = FALSE bResetTempPositions = FALSE bOutputAllTempCoords = FALSE ENDPROC #ENDIF /// PURPOSE: /// Tries to grab Josh from the 32 closest peds around the player when called /// RETURNS: /// True if found Josh FUNC BOOL GrabJosh() INT cnt INT i PED_INDEX tmpArray[32] IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) cnt = GET_PED_NEARBY_PEDS(PLAYER_PED_ID(), tmpArray) ENDIF REPEAT cnt i IF IS_ENTITY_ALIVE(tmpArray[i]) IF (GET_ENTITY_MODEL(tmpArray[i]) = GET_NPC_PED_MODEL(CHAR_JOSH)) CPRINTLN(DEBUG_AMBIENT, "For Sale Signs: - Josh get!") pedJosh = tmpArray[i] IF NOT IS_ENTITY_A_MISSION_ENTITY(pedJosh) SET_ENTITY_AS_MISSION_ENTITY(pedJosh) ENDIF SET_PED_MONEY(pedJosh, 0) SET_PED_CAN_BE_TARGETTED(pedJosh, FALSE) SET_PED_NAME_DEBUG(pedJosh, "POSTJOSH") SET_PED_RELATIONSHIP_GROUP_HASH(pedJosh, RELGROUPHASH_PLAYER) ADD_PED_FOR_DIALOGUE(ConvStruct, 5, pedJosh, "JOSH", TRUE) RETURN TRUE ENDIF ENDIF ENDREPEAT RETURN FALSE ENDFUNC /// PURPOSE: /// Sets up the "For Sale" sign locations PROC DO_INITIALISE() CPRINTLN(DEBUG_AMBIENT, "For Sale Signs: DO_INITIALISE()") // If we've grabbed Josh when starting this script, it must be being launched after completing Josh 1, so let's use this to control him bDoPostJosh1 = GrabJosh() IF NOT HAVE_ALL_SCRAPS_BEEN_COMPLETED(SCRAP_SALE_SIGNS) sSign[0].vCoords = <<-1569.5250, 444.0400, 108.1350>> sSign[0].fHeading = 80.0000 sSign[1].vCoords = <<-1352.8800, 613.7700, 134.3400>> sSign[1].fHeading = 198.0000 // Updated 07/10/11 sSign[2].vCoords = <<-1467.0, -5.5, 53.1050>> sSign[2].fHeading = 104.0000 sSign[3].vCoords = <<-1632.8329, -413.8573, 39.9441>> sSign[3].fHeading = 321.5000 // Updated 18/11/11 sSign[4].vCoords = <<-1765.6779, -423.9763, 41.5>> sSign[4].fHeading = 256.2500 sSign[5].vCoords = <<-380.7500, 427.7900, 110.9700>> sSign[5].fHeading = 286.5000 // Updated 07/10/11 sSign[6].vCoords = <<-163.2826, 989.2324, 234.0641>> sSign[6].fHeading = 0.00 // Updated 18/11/11 sSign[7].vCoords = <<-493.0830, 588.6333, 122.48499>> sSign[7].fHeading = 177.2061 // Updated 02/08/12 sSign[8].vCoords = <<-818.8400, 434.7400, 88.1500>> sSign[8].fHeading = 91.5000 sSign[9].vCoords = << -913.24, 785.40, 184.66 >> sSign[9].fHeading = 96.26 sSign[10].vCoords = <<-825.9200, -26.6700, 38.6800>> sSign[10].fHeading = 15.0000 sSign[11].vCoords = <<-1103.5000, 587.2900, 103.25>> sSign[11].fHeading = 305.5000 sSign[12].vCoords = << -1253.4395, 491.05, 94.3706 >> sSign[12].fHeading = 0.0000 sSign[13].vCoords = << 160.29, 486.71, 142.96 >> sSign[13].fHeading = 95.0000 sSign[14].vCoords = <<-1163.8590, 319.1900, 67.9600>> sSign[14].fHeading = 40.0000 // Updated 07/10/11 eStage = STAGE_PROCESS ELSE eStage = STAGE_CLEANUP ENDIF ENDPROC /// PURPOSE: /// Print a message stating how many signs have been destroyed if this is needed... /// Now using the Midsized message UI as per Les request PROC UPDATE_SALE_SIGN_MESSAGE() INT iSplashSoundID IF bDisplayMessage SWITCH iMessageStage CASE 0 IF NOT IS_SCREEN_FADED_OUT() siMessage = REQUEST_SCALEFORM_MOVIE("MIDSIZED_MESSAGE") IF HAS_SCALEFORM_MOVIE_LOADED(siMessage) iSplashSoundID = GET_SOUND_ID() PLAY_SOUND_FRONTEND(iSplashSoundID, "SIGN_DESTROYED", "HUD_AWARDS") iMessageStage++ ENDIF ENDIF BREAK CASE 1 BEGIN_SCALEFORM_MOVIE_METHOD(siMessage, "SHOW_SHARD_MIDSIZED_MESSAGE") BEGIN_TEXT_COMMAND_SCALEFORM_STRING("FS_TITLE") END_TEXT_COMMAND_SCALEFORM_STRING() BEGIN_TEXT_COMMAND_SCALEFORM_STRING("FS_DESTROY") ADD_TEXT_COMPONENT_INTEGER(GET_NUM_SCRAPS_SORTED(SCRAP_SALE_SIGNS)) END_TEXT_COMMAND_SCALEFORM_STRING() END_SCALEFORM_MOVIE_METHOD() SETTIMERB(0) iMessageStage++ BREAK CASE 2 IF TIMERB() > DEFAULT_GOD_TEXT_TIME - 500 BEGIN_SCALEFORM_MOVIE_METHOD(siMessage, "SHARD_ANIM_OUT") SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(ENUM_TO_INT(HUD_COLOUR_WHITE)) SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(0.33) END_SCALEFORM_MOVIE_METHOD() iMessageStage++ ELSE IF NOT IS_RESULT_SCREEN_DISPLAYING() IF HAS_SCALEFORM_MOVIE_LOADED(siMessage) DRAW_SCALEFORM_MOVIE_FULLSCREEN(siMessage, 100, 100, 100, 255) ENDIF ENDIF ENDIF BREAK CASE 3 IF TIMERB() > DEFAULT_GOD_TEXT_TIME iMessageStage++ ELSE IF NOT IS_RESULT_SCREEN_DISPLAYING() IF HAS_SCALEFORM_MOVIE_LOADED(siMessage) DRAW_SCALEFORM_MOVIE_FULLSCREEN(siMessage, 100, 100, 100, 255) ENDIF ENDIF ENDIF BREAK CASE 4 IF HAS_SCALEFORM_MOVIE_LOADED(siMessage) SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(siMessage) ENDIF bMessageOnDisplay = FALSE bDisplayMessage = FALSE iMessageStage = 0 BREAK ENDSWITCH ENDIF ENDPROC /// PURPOSE: /// Checks to see if the sign has been 'knocked over' by checking it X and Y rotation to see if it's not standing up straight anymore /// PARAMS: /// sign - The sign we're checking /// RETURNS: /// True if the X or Y are beyond certain bounds, False otherwise FUNC BOOL HAS_SIGN_TIPPED_OVER(ENTITY_INDEX sign) VECTOR testRot = GET_ENTITY_ROTATION(sign, EULER_XYZ) // If the sign has an X or Y rot more than 30.0 or less than -30.0, consider it knocked over IF (testRot.X > 30.0) OR (testRot.X < -30.0) OR (testRot.Y > 30.0) OR (testRot.Y < -30.0) RETURN TRUE // The sign has tipped over ENDIF RETURN FALSE ENDFUNC PROC SET_SIGN_STAT(int iSign) IF iSign < 16 SET_PACKED_STAT_BOOL( INT_TO_ENUM(STATS_PACKED, ENUM_TO_INT(PACKED_NUM_DESTROYED_SIGNS_START) + iSign) , TRUE) ELSE SCRIPT_ASSERT("For sale signs SET_SIGN_STAT(): Destroyed an unknown sign number?") ENDIF QUICK_INCREMENT_INT_STAT(NUM_DESTROYED_SIGNS_0, 1) ENDPROC /// PURPOSE: /// Creates/Removes the "For Sale" sign prop when necessary and maintains saved globals PROC DO_PROCESS() IF bDoPostJosh1 IF IS_ENTITY_ALIVE(pedJosh) // If the player is <=3m from Josh, play one of his ambient lines, with an 8sec delay between them IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND NOT IS_PED_FLEEING(pedJosh) AND NOT IS_PED_RAGDOLL(pedJosh) AND NOT IS_PED_PRONE(pedJosh) AND NOT IS_PED_INJURED(pedJosh) IF GET_DISTANCE_BETWEEN_ENTITIES(pedJosh, PLAYER_PED_ID()) <= 3.0 IF (GET_GAME_TIMER() - iConvTimer) > 8000 IF CREATE_CONVERSATION(ConvStruct, "JOSH1AU", "JOSH1_AMB2", CONV_PRIORITY_MEDIUM) iConvTimer = GET_GAME_TIMER() ENDIF ENDIF ENDIF ENDIF IF GET_DISTANCE_BETWEEN_ENTITIES(pedJosh, PLAYER_PED_ID()) > 150.0 SAFE_DELETE_PED(pedJosh) // Josh won't be alive after this, it'll set the bool to false the frame after ENDIF ELSE SAFE_RELEASE_PED(pedJosh) // In case he still exists but is dead - no point holding onto the ped index anymore bDoPostJosh1 = FALSE ENDIF ENDIF INT iScrap = 0 REPEAT NUMBER_OF_FOR_SALE_SIGNS iScrap IF DOES_ENTITY_EXIST(sSign[iScrap].obj) // If the sign has been destroyed... IF HAS_OBJECT_BEEN_BROKEN(sSign[iScrap].obj) OR HAS_SIGN_TIPPED_OVER(sSign[iScrap].obj) // Flag the sign as destroyed SET_BIT(g_savedGlobals.sAmbient.iForSaleSignDestroyedFlags, iScrap) SET_SIGN_STAT(iScrap) SET_OBJECT_AS_NO_LONGER_NEEDED(sSign[iScrap].obj) bDisplayMessage = TRUE SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE) MAKE_AUTOSAVE_REQUEST() #IF IS_DEBUG_BUILD PRINT_SCRAP_NUMBER(iScrap) #ENDIF // The sign hasn't been destroyed ELSE REMOVE_OBJECT_WHEN_OUT_OF_RANGE(sSign[iScrap].obj, sSign[iScrap].bActive) ENDIF // The sign has not been created ELSE // If the sign has not been destroyed IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iForSaleSignDestroyedFlags, iScrap) CREATE_OBJECT_WHEN_IN_RANGE(sSign[iScrap], eSignModel, FALSE, 200) ENDIF ENDIF ENDREPEAT UPDATE_SALE_SIGN_MESSAGE() IF NOT bMessageOnDisplay AND NOT bDisplayMessage IF HAVE_ALL_SCRAPS_BEEN_COMPLETED(SCRAP_SALE_SIGNS) eStage = STAGE_CLEANUP ENDIF ENDIF ENDPROC /// PURPOSE: /// Cleans up any assets that were created PROC CLEANUP_SCRIPT() CPRINTLN(DEBUG_AMBIENT, "STAGE_CLEANUP") INT iScrap REPEAT NUMBER_OF_FOR_SALE_SIGNS iScrap SAFE_REMOVE_BLIP(sSign[iScrap].blip) ENDREPEAT REPEAT NUMBER_OF_FOR_SALE_SIGNS iScrap SAFE_RELEASE_OBJECT(sSign[iScrap].obj) ENDREPEAT SET_MODEL_AS_NO_LONGER_NEEDED(eSignModel) // Register completion stats when completing normally or via debug IF HAVE_ALL_SCRAPS_BEEN_COMPLETED(SCRAP_SALE_SIGNS) OR GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FOR_SALE_SIGNS_DESTROYED) = TRUE // Set Josh 1 completion percentage REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL ( CP_RAND_C_JOS1 ) // No longer require the script to be relaunched when loading from a savegame. Remove_Script_From_Relaunch_List(LAUNCH_BIT_RC_AMB_FOR_SALE_SIGNS) UNLOCK_TEXT_MESSAGE_BY_LABEL("JOSH1_TXT") DELETE_TEXT_MESSAGE_BY_LABEL_FROM_CURRENT_PLAYER("JOSH1_TXT") IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FOR_SALE_SIGNS_DESTROYED) = FALSE // Send a delayed text from Josh that unlocks RC Josh 2 // only send text if flow flag isn't set // if the flow flag is set, we've debug skipped past Josh 2 // Don't use CT_END_OF_MISSION for this communication as that blocks // switching and a number of other things until it is sent. -BenR REGISTER_TEXT_MESSAGE_FROM_CHARACTER_TO_PLAYER( TEXT_FORSALESIGNS_DONE, CT_FLOW, BIT_TREVOR, CHAR_JOSH, 30000, 10000, VID_BLANK, CID_JOSH1_SIGNS_DESTROYED) ENDIF ENDIF #IF IS_DEBUG_BUILD IF DOES_WIDGET_GROUP_EXIST(widgetGroup) DELETE_WIDGET_GROUP(widgetGroup) ENDIF #ENDIF TERMINATE_THIS_THREAD() ENDPROC SCRIPT IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_REPEAT_PLAY|FORCE_CLEANUP_FLAG_DIRECTOR) CLEANUP_SCRIPT() ENDIF IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH (HASH("forSaleSigns")) > 1 CPRINTLN(DEBUG_AMBIENT, "For Sale Signs: Attempting to launch with an instance already active.") TERMINATE_THIS_THREAD() ENDIF // Register the script so that it can be relaunched when loading from a savegame. Register_Script_To_Relaunch_List(LAUNCH_BIT_RC_AMB_FOR_SALE_SIGNS) #IF IS_DEBUG_BUILD SETUP_FOR_SALE_WIDGETS() #ENDIF // Main loop WHILE TRUE WAIT(0) // Immediately cleanup if this script has been completed via debug IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FOR_SALE_SIGNS_DESTROYED) = TRUE CLEANUP_SCRIPT() ENDIF SWITCH eStage CASE STAGE_INITIALISE DO_INITIALISE() BREAK CASE STAGE_PROCESS DO_PROCESS() BREAK CASE STAGE_CLEANUP CLEANUP_SCRIPT() BREAK ENDSWITCH #IF IS_DEBUG_BUILD MAINTAIN_FOR_SALE_WIDGETS() #ENDIF ENDWHILE ENDSCRIPT