///// ob_jukebox.sc ///// Mark Richardson - 13/07/16 ///// Network Jukebox functionailty USING "rage_builtins.sch" USING "globals.sch" USING "cellphone_public.sch" USING "commands_zone.sch" USING "menu_public.sch" USING "net_clubhouse.sch" //***********Script CONSTS*********** CONST_INT ciJukeboxUseCharge 1 //Broadcast data BS consts (Player) CONST_INT ciRequestingUseOfJukebox 0 CONST_INT ciUsingJukebox 1 CONST_INT ciRequestedPlaylistChange 2 CONST_INT ciRequestedVolumeChange 3 //Local BS consts CONST_INT ciDelayTimerActive 0 CONST_INT ciRebuildMenu 1 CONST_INT cinetworkInitDone 2 CONST_INT ciMenuActive 3 CONST_INT ciPlaySelectTrackAnim 4 CONST_INT ciPlayInsertCoinAnim 5 CONST_INT ciJukeboxEnabled 6 ENUM JUKEBOX_MENU_STAGE eSelectPlaylist, eTurnJBOffNoMoney, //Seperate stage for when the player has no cash eConfirm ENDENUM ENUM JUKEBOX_ACTIVITY_STAGE eJAInactive, eJAPlayingEntryAnim, eJAAwaitingAproval, eJAMenuActive, eJAExit ENDENUM ENUM JUKEBOX_SERVER_STAGE JBServerStageOff, JBServerStageOn ENDENUM //***********Script variables*********** OBJECT_INDEX obJukebox PLAYER_INDEX pPropertyOwnerID INT iLocalActivePlaylistID = 0 INT iSelectedPlaylist = -1 INT iCurrentSelection = 0 INT iCurrentProperty = -1 INT iStaggeredPlayerLoop = 0 INT iJukeboxContextIntention = NEW_CONTEXT_INTENTION INT iJukeBoxSyncSceneStage = 0 INT iJukeBoxSyncSceneID = 0 INT iJukeBoxBS = 0 INT iJBSelectedPlistPlayTime = 0 INT iMostPlayedPlayistTime = 0 INT iTelemSelectedPlaylist = 0 INT iMenuOnOffOption STRING sJukeboxAnimDict = "anim@amb@clubhouse@jukebox@" JUKEBOX_MENU_STAGE eMenuStage = eSelectPlaylist JUKEBOX_ACTIVITY_STAGE eActivityStage = eJAInactive SCRIPT_TIMER stAnalogueMenuDelay SCRIPT_TIMER stJBWalkToTimer SCRIPT_TIMER stStatAutosaveTimer VECTOR vJukeboxCoords VECTOR vtrigger VECTOR vSynchSceneOrigin //***********Script Structs*********** // The server broadcast data. STRUCT ServerBroadcastData // Game State JUKEBOX_SERVER_STAGE iJukeboxServerState = JBServerStageOn FLOAT fVolume = 0.5 INT iJukeboxUserID = -1 INT iActivePlaylistID = -1 BOOL bNewPlaylistSelectedByOwner ENDSTRUCT ServerBroadcastData serverBD // The client broadcast data. STRUCT PlayerBroadcastData INT iBitSet INT iNewPlaylistRequestID FLOAT fVolume ENDSTRUCT PlayerBroadcastData playerBD[NUM_NETWORK_PLAYERS] //***********Script functions*********** PROC CLEANUP_ANY_PLAYING_ANIMATIONS() IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "IDLE") OR IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "EXIT") OR IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "INSERT_COINS") OR IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "SELECT_TRACK") CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID()) ENDIF ENDIF ENDPROC PROC INIT_TIME_STAMP_FOR_CURRENT_PLAYLIST() #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE INT iFavouritePList = GET_LOCAL_PLAYERS_FAVOURITE_ARCADE_JUKEBOX_PLAYLIST_ID() iJBSelectedPlistPlayTime = GET_CLOUD_TIME_AS_INT() iMostPlayedPlayistTime = GET_MP_INT_CHARACTER_STAT(GET_FAV_ARCADE_PLAYLIST_STAT_FROM_ID(iFavouritePList)) ELSE #ENDIF INT iFavouritePList = GET_LOCAL_PLAYERS_FAVOURITE_JUKEBOX_PLAYLIST_ID() iJBSelectedPlistPlayTime = GET_CLOUD_TIME_AS_INT() iMostPlayedPlayistTime = GET_MP_INT_CHARACTER_STAT(GET_FAV_PLAYLIST_STAT_FROM_ID(iFavouritePList)) #IF FEATURE_CASINO_HEIST ENDIF #ENDIF ENDPROC /// PURPOSE: /// Adds the total time the given playlist has been played to the relevant stat PROC SAVE_JB_PLAYLIST_PLAY_TIME(INT iOldPlaylist) IF iOldPlaylist = iMenuOnOffOption CDEBUG1LN(DEBUG_SAFEHOUSE, " SAVE_JB_PLAYLIST_PLAY_TIME not setting stat as the JB has been turned off") EXIT ENDIF #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE INT iCurrentSavedTime = GET_MP_INT_CHARACTER_STAT(GET_FAV_ARCADE_PLAYLIST_STAT_FROM_ID(iOldPlaylist)) INT iTimeToAdd = (GET_CLOUD_TIME_AS_INT() - iJBSelectedPlistPlayTime) CDEBUG1LN(DEBUG_SAFEHOUSE, " SAVE_JB_PLAYLIST_PLAY_TIME saving time for playlist: ", iOldPlaylist, " Previous total time: ", iCurrentSavedTime, " seconds. Time to add: ", iTimeToAdd, " seconds.") //Set the stat SET_MP_INT_CHARACTER_STAT(GET_FAV_ARCADE_PLAYLIST_STAT_FROM_ID(iOldPlaylist), (iCurrentSavedTime + iTimeToAdd)) //Set the BD IF iMostPlayedPlayistTime < (iCurrentSavedTime + iTimeToAdd) SET_PLAYERS_FAVOURITE_PLAYLIST(GET_LOCAL_PLAYERS_FAVOURITE_ARCADE_JUKEBOX_PLAYLIST_ID()) ENDIF ELSE #ENDIF INT iCurrentSavedTime = GET_MP_INT_CHARACTER_STAT(GET_FAV_PLAYLIST_STAT_FROM_ID(iOldPlaylist)) INT iTimeToAdd = (GET_CLOUD_TIME_AS_INT() - iJBSelectedPlistPlayTime) CDEBUG1LN(DEBUG_SAFEHOUSE, " SAVE_JB_PLAYLIST_PLAY_TIME saving time for playlist: ", iOldPlaylist, " Previous total time: ", iCurrentSavedTime, " seconds. Time to add: ", iTimeToAdd, " seconds.") //Set the stat SET_MP_INT_CHARACTER_STAT(GET_FAV_PLAYLIST_STAT_FROM_ID(iOldPlaylist), (iCurrentSavedTime + iTimeToAdd)) //Set the BD IF iMostPlayedPlayistTime < (iCurrentSavedTime + iTimeToAdd) SET_PLAYERS_FAVOURITE_PLAYLIST(GET_LOCAL_PLAYERS_FAVOURITE_JUKEBOX_PLAYLIST_ID()) ENDIF #IF FEATURE_CASINO_HEIST ENDIF #ENDIF iJBSelectedPlistPlayTime = GET_CLOUD_TIME_AS_INT() ENDPROC PROC CLEANUP_JUKEBOX(BOOL bCleanupPlayerControl = FALSE) CDEBUG1LN(DEBUG_SAFEHOUSE, " CLEANUP_JUKEBOX") DISABLE_CELLPHONE(FALSE) IF IS_BIT_SET(iJukeBoxBS, ciMenuActive) CLEANUP_MENU_ASSETS() ENDIF SET_BIT(g_JukeboxData.iBitSet, ciJBJustRunCleanup) IF iJukeboxContextIntention != NEW_CONTEXT_INTENTION RELEASE_CONTEXT_INTENTION(iJukeboxContextIntention) ENDIF IF pPropertyOwnerID = PLAYER_ID() SAVE_JB_PLAYLIST_PLAY_TIME(iLocalActivePlaylistID) ENDIF IF IS_HELP_MESSAGE_BEING_DISPLAYED() AND IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("JBOX_NO_MONEY") CLEAR_HELP(TRUE) ENDIF THEFEED_RESUME() CLEANUP_ANY_PLAYING_ANIMATIONS() IF bCleanupPlayerControl NET_SET_PLAYER_CONTROL(PLAYER_ID(), TRUE) ENDIF #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE STOP_AUDIO_SCENE("dlc_ch_arcade_music_volume") ENDIF #ENDIF TERMINATE_THIS_THREAD() ENDPROC FUNC BOOL IS_JUKEBOX_ON() RETURN serverBD.iJukeboxServerState = JBServerStageOn ENDFUNC FUNC BOOL IS_JUKEBOX_IN_USE() IF serverBD.iJukeboxUserID != -1 RETURN TRUE ENDIF RETURN FALSE ENDFUNC PROC CHARGE_PLAYER_FOR_JB(INT iPlaylist) INT iPlaylistHash IF IS_PROPERTY_CLUBHOUSE(iCurrentProperty) iPlaylistHash = GET_HASH_KEY(GET_CLUBHOUSE_PLAYLIST_NAME_FROM_ID(iPlaylist)) #IF FEATURE_CASINO_HEIST ELIF iCurrentProperty = PROPERTY_ARCADE_GARAGE iPlaylistHash = GET_HASH_KEY(GET_ARCADE_PLAYLIST_NAME_FROM_ID(iPlaylist)) #ENDIF ENDIF IF NETWORK_CAN_SPEND_MONEY(ciJukeboxUseCharge, FALSE, FALSE, TRUE) IF USE_SERVER_TRANSACTIONS() INT iTransactionID CDEBUG1LN(DEBUG_SHOPS, " [$$$] Charging MP player for jukebox - PC: $", ciJukeboxUseCharge) TRIGGER_FIRE_AND_FORGET_SERVICE_TRANSACTION(SERVICE_SPEND_JUKEBOX, ciJukeboxUseCharge, iTransactionID, FALSE, FALSE, TRUE) g_cashTransactionData[iTransactionID].cashInfo.iItemHash = iPlaylistHash ELSE CDEBUG1LN(DEBUG_SHOPS, " [$$$] Charging MP player for jukebox - CONSOLE: $", ciJukeboxUseCharge) NETWORK_SPENT_JUKEBOX(ciJukeboxUseCharge, iPlaylistHash, FALSE, FALSE) ENDIF ENDIF ENDPROC #IF IS_DEBUG_BUILD FUNC STRING GET_JUKEBOX_ACTIVITY_STAGE_AS_STRING(JUKEBOX_ACTIVITY_STAGE eStage) SWITCH eStage CASE eJAInactive RETURN "eJAInactive" CASE eJAPlayingEntryAnim RETURN "eJAPlayingEntryAnim" CASE eJAAwaitingAproval RETURN "eJAAwaitingAproval" CASE eJAMenuActive RETURN "eJAMenuActive" CASE eJAExit RETURN "eJAExit" ENDSWITCH RETURN "Jukebox stage unknown" ENDFUNC #ENDIF PROC SET_JUKEBOX_ACTIVITY_STAGE(JUKEBOX_ACTIVITY_STAGE eNewStage) #IF IS_DEBUG_BUILD CDEBUG1LN(DEBUG_SAFEHOUSE, " SET_JUKEBOX_ACTIVITY_STAGE old stage: ", GET_JUKEBOX_ACTIVITY_STAGE_AS_STRING(eActivityStage), " New stage: ", GET_JUKEBOX_ACTIVITY_STAGE_AS_STRING(eNewStage)) DEBUG_PRINTCALLSTACK() #ENDIF eActivityStage = eNewStage ENDPROC PROC REQUEST_VOLUME_CHANGE(FLOAT fNewVolume) playerBD[NATIVE_TO_INT(PLAYER_ID())].fVolume = fNewVolume SET_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedVolumeChange) CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_JUKEBOX_ACTIVITY - Requested volume change to ", fNewVolume) ENDPROC /// PURPOSE: /// Disable all controls necessary whilst the menu is active PROC JUKEBOX_MENU_CONTROL_DISABLE() SET_CLEAR_ON_CALL_HUD_THIS_FRAME() HANG_UP_AND_PUT_AWAY_PHONE(TRUE) IF (NOT IS_SYSTEM_UI_BEING_DISPLAYED()) AND (NOT IS_PAUSE_MENU_ACTIVE()) DISABLE_ALL_CONTROL_ACTIONS(PLAYER_CONTROL) ENABLE_ALL_CONTROL_ACTIONS(CAMERA_CONTROL) DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE_ALTERNATE) ENDIF ENDPROC FUNC INT GET_MAX_AVAILABLE_PLAYLISTS() IF iCurrentProperty = PROPERTY_ARCADE_GARAGE #IF FEATURE_TUNER IF pPropertyOwnerID = PLAYER_ID() AND HAS_LOCAL_PLAYER_COLLECTED_ANY_USB_MIXES() RETURN 10 // url:bugstar:6593351 ENDIF #ENDIF RETURN 9 ENDIF #IF FEATURE_TUNER IF pPropertyOwnerID = PLAYER_ID() AND HAS_LOCAL_PLAYER_COLLECTED_ANY_USB_MIXES() RETURN 5 // url:bugstar:6593351 ENDIF #ENDIF RETURN 4 ENDFUNC FUNC INT GET_MENU_OFF_OPTION() RETURN GET_MAX_AVAILABLE_PLAYLISTS() ENDFUNC FUNC INT GET_JUKEBOX_MENU_LIMIT() INT iNumberOfPlaylists = GET_MAX_AVAILABLE_PLAYLISTS() SWITCH eMenuStage CASE eConfirm RETURN 1 CASE eSelectPlaylist IF IS_JUKEBOX_ON() RETURN iNumberOfPlaylists //Not (ciMaxAvailablePlaylists -1) to allow for the on/off option ELSE RETURN (iNumberOfPlaylists -1) ENDIF BREAK CASE eTurnJBOffNoMoney RETURN 0 ENDSWITCH SCRIPT_ASSERT(" GET_JUKEBOX_MENU_LIMIT: Invalid stage!") RETURN 0 ENDFUNC PROC HANDLE_PC_CONTROL(BOOL &bPrevious, BOOL &bNext, BOOL &bAccept, BOOL &bBack, BOOL &bLeft, BOOL &bRight) // Mouse control support IF IS_PC_VERSION() AND NOT NETWORK_TEXT_CHAT_IS_TYPING() IF IS_USING_CURSOR(FRONTEND_CONTROL) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_LOOK_LR) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_LOOK_UD) DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE_ALTERNATE) ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_CURSOR_ACCEPT) ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_CURSOR_CANCEL) ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_CURSOR_SCROLL_UP) ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_CURSOR_SCROLL_DOWN) IF ((g_iMenuCursorItem = MENU_CURSOR_NO_ITEM) OR (g_iMenuCursorItem = MENU_CURSOR_NO_CAMERA_MOVE) OR (g_iMenuCursorItem = MENU_CURSOR_DRAG_CAM)) ENABLE_CONTROL_ACTION(CAMERA_CONTROL, INPUT_LOOK_LR) ENABLE_CONTROL_ACTION(CAMERA_CONTROL, INPUT_LOOK_UD) ELSE DISABLE_CONTROL_ACTION(CAMERA_CONTROL, INPUT_LOOK_LR) DISABLE_CONTROL_ACTION(CAMERA_CONTROL, INPUT_LOOK_UD) ENDIF HANDLE_CURSOR_HIGHLIGHTED_MENU_ITEMS() HANDLE_MENU_CURSOR(FALSE) ENDIF // Mouse select IF IS_MENU_CURSOR_ACCEPT_PRESSED() IF g_iMenuCursorItem = iCurrentSelection bAccept = TRUE ELSE iCurrentSelection = g_iMenuCursorItem SET_CURRENT_MENU_ITEM(iCurrentSelection) ENDIF ENDIF // Menu cursor back IF IS_MENU_CURSOR_CANCEL_PRESSED() bBack = TRUE ENDIF // Mouse scroll up IF IS_MENU_CURSOR_SCROLL_UP_PRESSED() OR IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_UP) bPrevious = TRUE ENDIF // Mouse scroll down IF IS_MENU_CURSOR_SCROLL_DOWN_PRESSED() OR IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_DOWN) bNext = TRUE ENDIF IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_LEFT) bLeft = TRUE ENDIF IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_RIGHT) bRight = TRUE ENDIF ENDIF ENDPROC /// PURPOSE: /// Control the response to any input whilst the menu is active PROC HANDLE_JUKEBOX_MENU_INPUT() INT iLeftY INT iMenuInputDelay = 150 BOOL bPrevious, bNext, bLeft, bRight IF IS_USING_CURSOR(FRONTEND_CONTROL) iMenuInputDelay = 110 ENDIF JUKEBOX_MENU_CONTROL_DISABLE() // Set the input flag states ENABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_AXIS_X) ENABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_AXIS_Y) ENABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) ENABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_UP) ENABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_DOWN) BOOL bAccept = (IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)) BOOL bBack = (IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) OR IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)) iLeftY = GET_CONTROL_VALUE(FRONTEND_CONTROL, INPUT_FRONTEND_AXIS_Y) IF NOT IS_BIT_SET(iJukeBoxBS, cidelayTimerActive) IF IS_USING_CURSOR(FRONTEND_CONTROL) HANDLE_PC_CONTROL(bPrevious, bNext, bAccept, bBack, bLeft, bRight) ELSE bPrevious = ((iLeftY < 100) OR IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_UP)) bNext = ((iLeftY > 150) OR IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_DOWN)) bLeft = IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_CONTEXT_SECONDARY) bRight = IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_CONTEXT) ENDIF IF bPrevious OR bNext OR bLeft OR bRight START_NET_TIMER(stAnalogueMenuDelay) SET_BIT(iJukeBoxBS, ciDelayTimerActive) ENDIF ELIF HAS_NET_TIMER_EXPIRED(stAnalogueMenuDelay, iMenuInputDelay) RESET_NET_TIMER(stAnalogueMenuDelay) CLEAR_BIT(iJukeBoxBS, ciDelayTimerActive) ENDIF //Menu navigation IF bNext iCurrentSelection ++ IF iCurrentSelection > GET_JUKEBOX_MENU_LIMIT() iCurrentSelection = 0 ENDIF PLAY_SOUND_FRONTEND(-1, "NAV_UP_DOWN", "HUD_FRONTEND_DEFAULT_SOUNDSET") ENDIF IF bPrevious iCurrentSelection -- IF iCurrentSelection < 0 iCurrentSelection = GET_JUKEBOX_MENU_LIMIT() ENDIF PLAY_SOUND_FRONTEND(-1, "NAV_UP_DOWN", "HUD_FRONTEND_DEFAULT_SOUNDSET") ENDIF #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE IF bLeft IF serverBD.fVolume < 1 REQUEST_VOLUME_CHANGE(serverBD.fVolume + 0.5) ENDIF ENDIF IF bRight IF serverBD.fVolume > 0 REQUEST_VOLUME_CHANGE(serverBD.fVolume - 0.5) ENDIF ENDIF ENDIF #ENDIF //Menu - Select an option IF bAccept BOOL bPlayErrorSound = FALSE SWITCH eMenuStage CASE eTurnJBOffNoMoney eMenuStage = eSelectPlaylist iCurrentSelection = 0 //Set the selection to off and exit the activity iSelectedPlaylist = iMenuOnOffOption SET_JUKEBOX_ACTIVITY_STAGE(eJAExit) CLEAR_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) BREAK CASE eSelectPlaylist IF iCurrentSelection != ServerBD.iActivePlaylistID OR NOT IS_JUKEBOX_ON() //Move to the next stage if we've selected a valid playlist iSelectedPlaylist = iCurrentSelection eMenuStage = eConfirm iCurrentSelection = 0 SET_BIT(iJukeBoxBS, ciRebuildMenu) SET_BIT(iJukeBoxBS ,ciPlaySelectTrackAnim) ELSE bPlayErrorSound = TRUE ENDIF BREAK CASE eConfirm IF iCurrentSelection = 0 //This will allow us to interupt the select playlist anim to exit iJukeBoxSyncSceneStage = 0 SET_JUKEBOX_ACTIVITY_STAGE(eJAExit) //If we have not selected the 'Turn off' option charge the player and switch the playlist IF iSelectedPlaylist != iMenuOnOffOption SET_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) CHARGE_PLAYER_FOR_JB(iSelectedPlaylist) ENDIF ELSE //Go back to the select playlist stage as we selected the 'No' option eMenuStage = eSelectPlaylist iCurrentSelection = 0 SET_BIT(iJukeBoxBS, ciRebuildMenu) ENDIF BREAK ENDSWITCH //Play the relevant sound effect IF bPlayErrorSound PLAY_SOUND_FRONTEND(-1, "ERROR", "HUD_FRONTEND_DEFAULT_SOUNDSET") ELSE PLAY_SOUND_FRONTEND(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET") ENDIF ENDIF //Menu - Back button pressed IF bBack PLAY_SOUND_FRONTEND(-1, "BACK", "HUD_FRONTEND_DEFAULT_SOUNDSET") SWITCH eMenuStage CASE eSelectPlaylist eMenuStage = eSelectPlaylist iSelectedPlaylist = -1 SET_JUKEBOX_ACTIVITY_STAGE(eJAExit) CLEAR_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) BREAK CASE eTurnJBOffNoMoney iCurrentSelection = 0 iSelectedPlaylist = -1 SET_JUKEBOX_ACTIVITY_STAGE(eJAExit) CLEAR_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) BREAK CASE eConfirm eMenuStage = eSelectPlaylist iCurrentSelection = 0 iSelectedPlaylist = -1 SET_BIT(iJukeBoxBS, ciRebuildMenu) BREAK ENDSWITCH ENDIF ENDPROC PROC BUILD_JUKEBOX_OFF_MENU() SETUP_MENU_WITH_TITLE("JBOX_MENU_T") ADD_MENU_ITEM_TEXT(0, "JBOX_M_OFF", 0, TRUE) SET_CURRENT_MENU_ITEM(iCurrentSelection) ADD_MENU_HELP_KEY_CLICKABLE(INPUT_FRONTEND_ACCEPT, "ITEM_SELECT") ADD_MENU_HELP_KEY_CLICKABLE(INPUT_FRONTEND_CANCEL, "ITEM_BACK") ENDPROC PROC BUILD_JUKEBOX_MAIN_MENU() SETUP_MENU_WITH_TITLE("JBOX_MENU_T") INT iNumberOfPlaylists = GET_MAX_AVAILABLE_PLAYLISTS() INT iIter //Build a list of available playlists REPEAT iNumberOfPlaylists iIter TEXT_LABEL_15 tlPlaylistName = "JBOX_PLIST_" //if we're playing this playlist now mark it as unavailable BOOL bItemAvailable = iIter != serverBD.iActivePlaylistID IF NOT IS_JUKEBOX_ON() bItemAvailable = TRUE ENDIF tlPlaylistName += iIter // Custom mix #IF FEATURE_TUNER IF iCurrentProperty != PROPERTY_ARCADE_GARAGE AND pPropertyOwnerID = PLAYER_ID() AND HAS_LOCAL_PLAYER_COLLECTED_ANY_USB_MIXES() AND (iIter = (GET_MAX_AVAILABLE_PLAYLISTS() - 1)) tlPlaylistName += "a" ENDIF #ENDIF ADD_MENU_ITEM_TEXT(iIter, tlPlaylistName, 0, bItemAvailable) IF bItemAvailable ADD_MENU_ITEM_TEXT(iIter, "JBOX_CHARGE", 0, bItemAvailable) ENDIF ENDREPEAT IF IS_JUKEBOX_ON() //Add an option to switch off the JB ADD_MENU_ITEM_TEXT(iIter, "JBOX_M_OFF", 0, TRUE) ENDIF SET_CURRENT_MENU_ITEM(iCurrentSelection) ADD_MENU_HELP_KEY_CLICKABLE(INPUT_FRONTEND_ACCEPT, "ITEM_SELECT") ADD_MENU_HELP_KEY_CLICKABLE(INPUT_FRONTEND_CANCEL, "ITEM_BACK") IF iCurrentProperty = PROPERTY_ARCADE_GARAGE AND IS_JUKEBOX_ON() ADD_MENU_HELP_KEY_GROUP(INPUTGROUP_FRONTEND_DPAD_LR, "HUD_INPUT77") ENDIF ENDPROC PROC BUILD_FINAL_MENU() SETUP_MENU_WITH_TITLE("JBOX_CONF_T") ADD_MENU_ITEM_TEXT(0, "JBOX_MENU_0",0, TRUE) ADD_MENU_ITEM_TEXT(1, "JBOX_MENU_1",0, TRUE) SET_CURRENT_MENU_ITEM(iCurrentSelection) ADD_MENU_HELP_KEY_CLICKABLE(INPUT_FRONTEND_ACCEPT, "ITEM_SELECT") ADD_MENU_HELP_KEY_CLICKABLE(INPUT_FRONTEND_CANCEL, "ITEM_BACK") ENDPROC PROC BUILD_JUKEBOX_MENU() SWITCH eMenuStage CASE eTurnJBOffNoMoney BUILD_JUKEBOX_OFF_MENU() BREAK CASE eSelectPlaylist BUILD_JUKEBOX_MAIN_MENU() BREAK CASE eConfirm BUILD_FINAL_MENU() BREAK ENDSWITCH ENDPROC PROC SETUP_JUKEBOX_OFF_DESCRIPTION() SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_TOFF_NM") ENDPROC PROC SETUP_JUKEBOX_MAIN_MENU_DESCRIPTION() IF iCurrentSelection = ServerBD.iActivePlaylistID AND IS_JUKEBOX_ON() SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_PLIST_PLY") ELIF iCurrentSelection = iMenuOnOffOption SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_TOFF") ELSE TEXT_LABEL_15 tlPlaylistDesc = "JBOX_PLIST_D_" tlPlaylistDesc += iCurrentSelection // Custom mix #IF FEATURE_TUNER IF iCurrentProperty != PROPERTY_ARCADE_GARAGE AND pPropertyOwnerID = PLAYER_ID() AND HAS_LOCAL_PLAYER_COLLECTED_ANY_USB_MIXES() AND (iCurrentSelection = (GET_MAX_AVAILABLE_PLAYLISTS() - 1)) tlPlaylistDesc += "a" ENDIF #ENDIF SET_CURRENT_MENU_ITEM_DESCRIPTION(tlPlaylistDesc) ENDIF ENDPROC PROC SETUP_FINAL_MENU_DESCRIPTION() IF NOT IS_JUKEBOX_ON() IF iCurrentSelection = 0 SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_CONF_ON") ELSE SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_CANC_PUR") ENDIF ELIF iSelectedPlaylist = iMenuOnOffOption IF iCurrentSelection = 0 SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_CONF_OFF") ELSE SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_CANC_PUR") ENDIF ELIF iCurrentSelection = 0 SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_CONF_PUR") ELSE SET_CURRENT_MENU_ITEM_DESCRIPTION("JBOX_CANC_PUR") ENDIF ENDPROC PROC RUN_MENU_DESCRIPTION() SWITCH eMenuStage CASE eTurnJBOffNoMoney SETUP_JUKEBOX_OFF_DESCRIPTION() BREAK CASE eSelectPlaylist SETUP_JUKEBOX_MAIN_MENU_DESCRIPTION() BREAK CASE eConfirm SETUP_FINAL_MENU_DESCRIPTION() BREAK ENDSWITCH ENDPROC PROC DEAL_WITH_HUD_ELEMENTS() HIDE_HUD_AND_RADAR_THIS_FRAME() HIDE_SCRIPTED_HUD_COMPONENT_THIS_FRAME(HUD_MP_RANK_BAR) ENDPROC /// PURPOSE: /// Loads them menu assets and builds the current menu PROC RUN_JUKEBOX_MENU() IF NOT IS_PAUSE_MENU_ACTIVE_EX() HANDLE_JUKEBOX_MENU_INPUT() IF LOAD_MENU_ASSETS("SNK_MNU", DEFAULT, TRUE) IF IS_BIT_SET(iJukeBoxBS, ciRebuildMenu) BUILD_JUKEBOX_MENU() CLEAR_BIT(iJukeBoxBS, ciRebuildMenu) ELSE SET_CURRENT_MENU_ITEM(iCurrentSelection) ENDIF RUN_MENU_DESCRIPTION() DRAW_MENU() DEAL_WITH_HUD_ELEMENTS() SET_BIT(iJukeBoxBS, ciMenuActive) ENDIF ENDIF ENDPROC /// PURPOSE: /// Plays a sync scene on the local player /// PARAMS: /// sAnimation - The anim to play /// bInterupt - Interupt the currently playing animation /// bLooped - Determines if the anim should play on a loop /// RETURNS: /// True when the animation has been started FUNC BOOL PLAY_INDIVIDUAL_JUKEBOX_ANIMATION(STRING sAnimation, BOOl bInterupt = FALSE, BOOL bLooped = FALSE) INT iLocaJukeboxSynchSceneID = NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID(iJukeBoxSyncSceneID) REQUEST_ANIM_DICT(sJukeboxAnimDict) IF HAS_ANIM_DICT_LOADED(sJukeboxAnimDict) IF (NOT IS_SYNCHRONIZED_SCENE_RUNNING(iLocaJukeboxSynchSceneID) OR GET_SYNCHRONIZED_SCENE_PHASE(iLocaJukeboxSynchSceneID) >= 0.96) OR bInterupt IF IS_SYNCHRONIZED_SCENE_RUNNING(iJukeBoxSyncSceneID) DETACH_SYNCHRONIZED_SCENE(iJukeBoxSyncSceneID) iJukeBoxSyncSceneID = -1 ENDIF iJukeBoxSyncSceneID = NETWORK_CREATE_SYNCHRONISED_SCENE(vSynchSceneOrigin, GET_ENTITY_ROTATION(obJukebox),DEFAULT,FALSE, bLooped) NETWORK_ADD_PED_TO_SYNCHRONISED_SCENE(PLAYER_PED_ID(), iJukeBoxSyncSceneID, sJukeboxAnimDict, sAnimation, SLOW_BLEND_IN, REALLY_SLOW_BLEND_OUT, SYNCED_SCENE_USE_PHYSICS|SYNCED_SCENE_DONT_INTERRUPT, DEFAULT, REALLY_SLOW_BLEND_IN) NETWORK_START_SYNCHRONISED_SCENE(iJukeBoxSyncSceneID) CDEBUG1LN(DEBUG_SAFEHOUSE, " PLAY_INDIVIDUAL_JUKEBOX_ANIMATION started anim: ", sAnimation) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC //// PURPOSE: /// Runs the enter to idle sync scene animations on the player using the jukebox /// RETURNS: /// True wehn the idle sync scene has started FUNC BOOL RUN_ENTER_TO_IDLE_SYNC_SCENE() JUKEBOX_MENU_CONTROL_DISABLE() CONST_INT ciWalkToPosition 0 CONST_INT ciBeginEnterAnim 1 CONST_INT ciBeginIdleAnim 2 SWITCH iJukeBoxSyncSceneStage CASE ciWalkToPosition DISABLE_CELLPHONE_THIS_FRAME_ONLY() VECTOR vTaregtPos vTaregtPos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(obJukebox, <<0.06, -0.8958, 0.2>>) IF NOT HAS_NET_TIMER_STARTED(stJBWalkToTimer) START_NET_TIMER(stJBWalkToTimer) ELIF HAS_NET_TIMER_EXPIRED(stJBWalkToTimer, 2000) iJukeBoxSyncSceneStage = ciBeginEnterAnim CDEBUG1LN(DEBUG_SAFEHOUSE, " JB in position timer expierd! Moving on") ENDIF IF NOT ARE_VECTORS_ALMOST_EQUAL(GET_ENTITY_COORDS(PLAYER_PED_ID()), vTaregtPos, 0.8) IF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_GO_STRAIGHT_TO_COORD) CDEBUG1LN(DEBUG_SAFEHOUSE, " Tasking player to go to:", vTaregtPos) TASK_GO_STRAIGHT_TO_COORD(PLAYER_PED_ID(), vTaregtPos, PEDMOVEBLENDRATIO_WALK, 4000, GET_ENTITY_HEADING(obJukebox), 0.125) ENDIF ELSE CDEBUG1LN(DEBUG_SAFEHOUSE, " JB in position! Moving on") #IF IS_DEBUG_BUILD VECTOR vPlayerPos vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) CDEBUG1LN(DEBUG_SAFEHOUSE, "[ENTER] player pos: ", vPlayerPos, " Target pos: ", vTaregtPos) #ENDIF iJukeBoxSyncSceneStage = ciBeginEnterAnim ENDIF BREAK CASE ciBeginEnterAnim IF PLAY_INDIVIDUAL_JUKEBOX_ANIMATION("ENTER", TRUE) RESET_NET_TIMER(stJBWalkToTimer) iJukeBoxSyncSceneStage = ciBeginIdleAnim CDEBUG1LN(DEBUG_SAFEHOUSE, " ciBeginEnterAnim starting enter anim. Walk to timer reset") ENDIF BREAK CASE ciBeginIdleAnim IF PLAY_INDIVIDUAL_JUKEBOX_ANIMATION("IDLE", DEFAULT, TRUE) CDEBUG1LN(DEBUG_SAFEHOUSE, ": RUN_ENTER_TO_IDLE_SYNC_SCENE complete. Start menu") //Reset the sync scene stage and return true iJukeBoxSyncSceneStage = 0 RETURN TRUE ENDIF BREAK ENDSWITCH RETURN FALSE ENDFUNC /// PURPOSE: /// Starts the eixt anim on the player currently using the jukebox /// Pass true for bPlayInsertCoins to play the insert coin anim first, folowed by the exit /// RETURNS: /// True when the sync scene has begun FUNC BOOL RUN_EXIT_SYNC_SCENE(BOOL bPlayInsertCoins) CONST_INT ciPlayInsertCoins 0 CONST_INT ciPlayExit 1 IF NOT bPlayInsertCoins iJukeBoxSyncSceneStage = ciPlayExit ENDIF IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) SWITCH iJukeBoxSyncSceneStage CASE ciPlayInsertCoins IF PLAY_INDIVIDUAL_JUKEBOX_ANIMATION("INSERT_COINS", TRUE) CDEBUG1LN(DEBUG_SAFEHOUSE, ": Coins inserted. moving onto exit anim") iJukeBoxSyncSceneStage = ciPlayExit ENDIF BREAK CASE ciPlayExit IF PLAY_INDIVIDUAL_JUKEBOX_ANIMATION("EXIT", NOT bPlayInsertCoins) REMOVE_ANIM_DICT(sJukeboxAnimDict) CDEBUG1LN(DEBUG_SAFEHOUSE, ": Started exit sync scene") //Reset the sync scene stage and return true iJukeBoxSyncSceneStage = 0 RETURN TRUE ENDIF BREAK ENDSWITCH ELSE CDEBUG1LN(DEBUG_SAFEHOUSE, ": player is dead") ENDIF DISABLE_CELLPHONE_THIS_FRAME_ONLY() RETURN FALSE ENDFUNC /// PURPOSE: /// Runs the slect track animation as a sync scene, then returns back to the idle animation /// RETURNS: /// True once the idle animation has started FUNC BOOL PLAY_SELECT_TRACK_SYNC_SCENE() CONST_INT ciPlaySelectTrack 0 CONST_INT ciPlayIdle 1 IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) SWITCH iJukeBoxSyncSceneStage CASE ciPlaySelectTrack IF PLAY_INDIVIDUAL_JUKEBOX_ANIMATION("SELECT_TRACK", TRUE) CDEBUG1LN(DEBUG_SAFEHOUSE, ": Track selected. moving back to idle") iJukeBoxSyncSceneStage = ciPlayIdle ENDIF BREAK CASE ciPlayIdle IF PLAY_INDIVIDUAL_JUKEBOX_ANIMATION("IDLE", DEFAULT, TRUE) CDEBUG1LN(DEBUG_SAFEHOUSE, ": Started idle scene") //Reset the sync scene stage and return true iJukeBoxSyncSceneStage = 0 RETURN TRUE ENDIF BREAK ENDSWITCH ELSE CDEBUG1LN(DEBUG_SAFEHOUSE, ": player is dead") ENDIF DISABLE_CELLPHONE_THIS_FRAME_ONLY() RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the local player is alone in the locate /// RETURNS: /// True if alone in the locate FUNC BOOL IS_PLAYER_ALONE_IN_AREA() PED_INDEX mPed[2] INT iPeds = GET_PED_NEARBY_PEDS(PLAYER_PED_ID(), mPed) IF iPeds > 0 INT i FOR i = 0 TO 1 IF NOT IS_ENTITY_DEAD(mPed[i]) IF IS_ENTITY_AT_COORD(mPed[i], vtrigger, <<0.8, 0.8, 1.5>>, FALSE, TRUE, TM_ON_FOOT) RETURN FALSE ENDIF ENDIF ENDFOR ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Checks if the player can use the jukebox /// RETURNS: /// True if the player is able to use the jukebox FUNC BOOL IS_PLAYER_IN_POSITION_AND_ABLE_TO_USE_JB() BOOL bPropertyAllowsJukebox = TRUE IF IS_PLAYER_IN_ARCADE_PROPERTY(PLAYER_ID()) AND NOT HAS_PLAYER_COMPLETED_FULL_ARCADE_SETUP(pPropertyOwnerID) bPropertyAllowsJukebox = FALSE ENDIF IF NOT IS_BIT_SET(g_JukeboxData.iBitSet, ciJBBlockPlayerUsingJB) AND NOT IS_PLAYER_USING_OFFICE_SEATID_VALID() AND NOT IS_PHONE_ONSCREEN() AND NOT IS_BROWSER_OPEN() AND NOT IS_PED_IN_COVER(PLAYER_PED_ID()) AND (GET_ROOM_KEY_FROM_ENTITY(PLAYER_PED_ID()) = GET_ROOM_KEY_FROM_ENTITY(obJukebox)) AND IS_ENTITY_AT_COORD(PLAYER_PED_ID(), vtrigger, <<0.55, 0.8, 1.5>>, FALSE, TRUE, TM_ON_FOOT) //AND IS_PLAYER_ALONE_IN_AREA() AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "EXIT") AND NOT IS_PLAYER_ENTERING_OR_EXITING_PROPERTY(PLAYER_ID()) AND NOT IS_JUKEBOX_IN_USE() AND bPropertyAllowsJukebox AND NOT IS_BIT_SET(g_simpleInteriorData.iFifthBS, BS5_SIMPLE_INTERIOR_INSTANT_PASS_OUT) AND Get_Peds_Drunk_Alcohol_Hit_Count(PLAYER_PED_ID()) <= 9 AND NOT g_SpawnData.bPassedOutDrunk AND NOT IS_PED_RAGDOLL(PLAYER_PED_ID()) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Runs a check to see if the player can afford to use the JB /// If the JB is on we should still be able to turn it off FUNC BOOL CAN_PLAYER_USE_JB_WITH_NO_MONEY() IF IS_JUKEBOX_ON() OR NETWORK_CAN_SPEND_MONEY(1, FALSE, FALSE, FALSE) RETURN TRUE ENDIF RETURN FALSE ENDFUNC PROC REQUEST_PLAYLIST_CHANGE(INT iNewPlaylistID) playerBD[NATIVE_TO_INT(PLAYER_ID())].iNewPlaylistRequestID = iNewPlaylistID SET_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedPlaylistChange) CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_JUKEBOX_ACTIVITY stage exit. Requested playlist change to ", iNewPlaylistID) ENDPROC PROC CLEAR_NO_MONEY_HELP() IF IS_HELP_MESSAGE_BEING_DISPLAYED() AND IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("JBOX_NO_MONEY") CLEAR_HELP(TRUE) ENDIF ENDPROC /// PURPOSE: /// Runs the jukebox activity stages for the local player /// This will request to use the jukebox when the player triggers the context intention PROC RUN_JUKEBOX_ACTIVITY() SWITCH eActivityStage CASE eJAInactive IF IS_PLAYER_IN_POSITION_AND_ABLE_TO_USE_JB() AND CAN_PLAYER_USE_JB_WITH_NO_MONEY() CLEAR_NO_MONEY_HELP() IF iJukeboxContextIntention = NEW_CONTEXT_INTENTION REGISTER_CONTEXT_INTENTION(iJukeboxContextIntention, CP_HIGH_PRIORITY, "JBOX_INTERACT") ELIF (iJukeboxContextIntention != NEW_CONTEXT_INTENTION AND HAS_CONTEXT_BUTTON_TRIGGERED(iJukeboxContextIntention)) AND NOT IS_PED_RUNNING(PLAYER_PED_ID()) SET_JUKEBOX_ACTIVITY_STAGE(eJAAwaitingAproval) RELEASE_CONTEXT_INTENTION(iJukeboxContextIntention) //Disable player controls NET_SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, NSPC_LEAVE_CAMERA_CONTROL_ON) CDEBUG1LN(DEBUG_SAFEHOUSE, ": RUN_JB_ACTIVITY player is requesting use of JB. Player ID: ", NATIVE_TO_INT(PLAYER_ID())) SET_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestingUseOfJukebox) SET_BIT(g_JukeboxData.iBitSet, ciJBTriggeredContextInt) ENDIF SET_BIT(g_JukeboxData.iBitSet, ciJBInLocate) ELIF iJukeboxContextIntention != NEW_CONTEXT_INTENTION RELEASE_CONTEXT_INTENTION(iJukeboxContextIntention) CLEAR_BIT(g_JukeboxData.iBitSet, ciJBInLocate) ELIF NOT CAN_PLAYER_USE_JB_WITH_NO_MONEY() AND IS_PLAYER_IN_POSITION_AND_ABLE_TO_USE_JB() PRINT_HELP_FOREVER("JBOX_NO_MONEY") CLEAR_BIT(g_JukeboxData.iBitSet, ciJBInLocate) ELSE CLEAR_NO_MONEY_HELP() CLEAR_BIT(g_JukeboxData.iBitSet, ciJBInLocate) ENDIF BREAK CASE eJAAwaitingAproval IF serverBD.iJukeboxUserID = NATIVE_TO_INT(PLAYER_ID()) AND IS_SKYSWOOP_AT_GROUND() //Start the entry sync scene from the begining iJukeBoxSyncSceneStage = 0 //Move onto the next main stage SET_JUKEBOX_ACTIVITY_STAGE(eJAPlayingEntryAnim) //Clear our request CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestingUseOfJukebox) //Inform the server we're using the Jukebox SET_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciUsingJukebox) //Clear the walk to timer RESET_NET_TIMER(stJBWalkToTimer) CDEBUG1LN(DEBUG_SAFEHOUSE, ": RUN_JB_ACTIVITY JB request approved. Player ID: ", NATIVE_TO_INT(PLAYER_ID()), " Calling NET_SET_PLAYER_CONTROL with FALSE & NSPC_LEAVE_CAMERA_CONTROL_ON") ELIF serverBD.iJukeboxUserID != -1 OR NOT IS_SKYSWOOP_AT_GROUND() SET_JUKEBOX_ACTIVITY_STAGE(eJAInactive) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestingUseOfJukebox) CLEAR_BIT(g_JukeboxData.iBitSet, ciJBTriggeredContextInt) NET_SET_PLAYER_CONTROL(PLAYER_ID(), TRUE) CDEBUG1LN(DEBUG_SAFEHOUSE, ": RUN_JB_ACTIVITY JB request denied. Player ID: ", NATIVE_TO_INT(PLAYER_ID()), " Player already using is: ", serverBD.iJukeboxUserID) ENDIF BREAK CASE eJAPlayingEntryAnim IF RUN_ENTER_TO_IDLE_SYNC_SCENE() iCurrentSelection = 0 SET_BIT(iJukeBoxBS, ciRebuildMenu) SET_JUKEBOX_ACTIVITY_STAGE(eJAMenuActive) IF NOT NETWORK_CAN_SPEND_MONEY(1, FALSE, FALSE, FALSE) eMenuStage = eTurnJBOffNoMoney ENDIF ENDIF BREAK CASE eJAMenuActive IF IS_BIT_SET(iJukeBoxBS ,ciPlaySelectTrackAnim) IF PLAY_SELECT_TRACK_SYNC_SCENE() CLEAR_BIT(iJukeBoxBS, ciPlaySelectTrackAnim) ENDIF ENDIF RUN_JUKEBOX_MENU() BREAK CASE eJAExit IF IS_BIT_SET(iJukeBoxBS, ciMenuActive) CLEAR_BIT(iJukeBoxBS, ciMenuActive) CLEANUP_MENU_ASSETS() ENDIF INT iLocaJukeboxSynchSceneID iLocaJukeboxSynchSceneID = NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID(iJukeBoxSyncSceneID) IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "EXIT") RUN_EXIT_SYNC_SCENE(IS_BIT_SET(iJukeBoxBS ,ciPlayInsertCoinAnim)) //Select then new playlist whilst the insert coins anim is playing //Or when the exit anim has begun (For turning the JB off) IF iSelectedPlaylist != -1 IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), sJukeboxAnimDict, "INSERT_COINS") AND GET_SYNCHRONIZED_SCENE_PHASE(iLocaJukeboxSynchSceneID) >= 0.82 OR NOT IS_BIT_SET(iJukeBoxBS ,ciPlayInsertCoinAnim) REQUEST_PLAYLIST_CHANGE(iSelectedPlaylist) ENDIF ENDIF ELSE IF GET_SYNCHRONIZED_SCENE_PHASE(iLocaJukeboxSynchSceneID) >= 0.96 CLEAR_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) CLEAR_BIT(iJukeBoxBS, ciPlaySelectTrackAnim) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciUsingJukebox) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedPlaylistChange) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedVolumeChange) CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_JUKEBOX_ACTIVITY calling NET_SET_PLAYER_CONTROL with TRUE") NET_SET_PLAYER_CONTROL(PLAYER_ID(), TRUE) CLEAR_BIT(g_JukeboxData.iBitSet, ciJBTriggeredContextInt) eMenuStage = eSelectPlaylist #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE iTelemSelectedPlaylist = GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID ELSE #ENDIF iTelemSelectedPlaylist = GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID #IF FEATURE_CASINO_HEIST ENDIF #ENDIF // Send telemetry data on this activity. PLAYSTATS_MC_CLUBHOUSE_ACTIVITY( GB_GET_GANG_BOSS_UUID_INT_A(GB_GET_LOCAL_PLAYER_GANG_BOSS()), GB_GET_GANG_BOSS_UUID_INT_B(GB_GET_LOCAL_PLAYER_GANG_BOSS()), GB_GET_MATCH_ID_1_FOR_TELEMETRY(), GB_GET_MATCH_ID_2_FOR_TELEMETRY(), 4, iTelemSelectedPlaylist, 0) CDEBUG1LN(DEBUG_SAFEHOUSE, " PLAYSTATS_MC_CLUBHOUSE_ACTIVITY: Setting Jukebox station to ", iTelemSelectedPlaylist) SET_JUKEBOX_ACTIVITY_STAGE(eJAInactive) ENDIF ENDIF BREAK ENDSWITCH ENDPROC PROC RUN_NETWORK_SCRIPT_INIT() IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_BIT_SET(iJukeBoxBS, cinetworkInitDone) //Get the interior instance we are in INT iInteriorInstance = mpPropMaintain.iMostRecentPropertyID #IF FEATURE_CASINO_HEIST IF IS_PLAYER_IN_ANY_SIMPLE_INTERIOR(PLAYER_ID()) iInteriorInstance = GET_SIMPLE_INTERIOR_INT_SCRIPT_INSTANCE() + 32 ENDIF #ENDIF CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_NETWORK_SCRIPT_INIT atempting to create a network script with an instance ID of: ", iInteriorInstance) NETWORK_SET_SCRIPT_IS_SAFE_FOR_NETWORK_GAME() NETWORK_SET_THIS_SCRIPT_IS_NETWORK_SCRIPT(NUM_NETWORK_PLAYERS, FALSE, iInteriorInstance) // This makes sure the net script is active, waits until it is. HANDLE_NET_SCRIPT_INITIALISATION() SET_THIS_SCRIPT_CAN_BE_PAUSED(FALSE) NETWORK_REGISTER_HOST_BROADCAST_VARIABLES(serverBD, SIZE_OF(serverBD)) NETWORK_REGISTER_PLAYER_BROADCAST_VARIABLES(playerBD, SIZE_OF(playerBD)) // KGM: Wait for the first network broadcast before moving on // (after Initialisation and Broadcast Variable Registration - Hosts can do this too) IF NOT Wait_For_First_Network_Broadcast() PRINTLN("[MP safehouse] - MISSION END - FAILED TO RECEIVE INITIAL NETWORK BROADCAST - SCRIPT CLEANUP") CLEANUP_JUKEBOX() ENDIF SET_BIT(iJukeBoxBS, cinetworkInitDone) CDEBUG1LN(DEBUG_SAFEHOUSE, "[MP safehouse] JUKEBOX script: Ready for network launch...") ENDIF ENDPROC /// PURPOSE: /// Check for any flags that mean this script should terminate PROC RUN_CLEANUP_CHECKS() #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE IF IS_PLAYER_WALKING_OUT_OF_SIMPLE_INTERIOR(PLAYER_ID()) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! IS_PLAYER_WALKING_OUT_OF_SIMPLE_INTERIOR") CLEANUP_JUKEBOX() ELIF NOT NETWORK_IS_GAME_IN_PROGRESS() CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! No network game is currently active") CLEANUP_JUKEBOX() ELIF IS_ENTITY_DEAD(PLAYER_PED_ID()) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! Player is injured or dead") CLEANUP_JUKEBOX() ELIF IS_BIT_SET(g_JukeboxData.iBitSet, ciJBInteriorGeneralCleanup) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! ciJBInteriorGeneralCleanup is set") CLEAR_BIT(g_JukeboxData.iBitSet, ciJBInteriorGeneralCleanup) CLEANUP_JUKEBOX() ELIF IS_BIT_SET(g_SimpleInteriorData.iSeventhBS, BS7_SIMPLE_INTERIOR_RENOVATION_TRIGGERED) IF eActivityStage != eJAInactive IF IS_BIT_SET(iJukeBoxBS, ciMenuActive) CLEAR_BIT(iJukeBoxBS, ciMenuActive) CLEANUP_MENU_ASSETS() ENDIF CLEAR_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) CLEAR_BIT(iJukeBoxBS, ciPlaySelectTrackAnim) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciUsingJukebox) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedPlaylistChange) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedVolumeChange) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestingUseOfJukebox) CLEAR_BIT(g_JukeboxData.iBitSet, ciJBTriggeredContextInt) eMenuStage = eSelectPlaylist SET_JUKEBOX_ACTIVITY_STAGE(eJAInactive) CDEBUG1LN(DEBUG_SAFEHOUSE, " Cleaning up JB! Player is renovating the arcade whilst using the JB") ENDIF ELIF NOT IS_PLAYER_IN_ARCADE_PROPERTY(PLAYER_ID()) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! Player has left the building") CLEANUP_JUKEBOX() ENDIF ELSE #ENDIF IF IS_BIT_SET(GlobalplayerBD_FM[NATIVE_TO_INT(PLAYER_ID())].propertyDetails.iBS,PROPERTY_BROADCAST_BS_PLAYER_EXITING_PROPERTY) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! PROPERTY_BROADCAST_BS_PLAYER_EXITING_PROPERTY is set") CLEANUP_JUKEBOX() ELIF NOT NETWORK_IS_GAME_IN_PROGRESS() CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! No network game is currently active") CLEANUP_JUKEBOX() ELIF IS_ENTITY_DEAD(PLAYER_PED_ID()) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! Player is injured or dead") CLEANUP_JUKEBOX() ELIF IS_BIT_SET(g_JukeboxData.iBitSet, ciJBInteriorGeneralCleanup) CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! ciJBInteriorGeneralCleanup is set") CLEAR_BIT(g_JukeboxData.iBitSet, ciJBInteriorGeneralCleanup) CLEANUP_JUKEBOX() ELIF GET_UPDATE_CUSTOM_APT() IF eActivityStage != eJAInactive IF IS_BIT_SET(iJukeBoxBS, ciMenuActive) CLEAR_BIT(iJukeBoxBS, ciMenuActive) CLEANUP_MENU_ASSETS() ENDIF CLEAR_BIT(iJukeBoxBS ,ciPlayInsertCoinAnim) CLEAR_BIT(iJukeBoxBS, ciPlaySelectTrackAnim) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciUsingJukebox) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedPlaylistChange) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestedVolumeChange) CLEAR_BIT(playerBD[NATIVE_TO_INT(PLAYER_ID())].iBitSet, ciRequestingUseOfJukebox) CLEAR_BIT(g_JukeboxData.iBitSet, ciJBTriggeredContextInt) eMenuStage = eSelectPlaylist SET_JUKEBOX_ACTIVITY_STAGE(eJAInactive) CDEBUG1LN(DEBUG_SAFEHOUSE, " Cleaning up JB! Player is renovating the clubhouse whilst using the JB") ENDIF ELIF iCurrentProperty != GlobalplayerBD_FM[NATIVE_TO_INT(PLAYER_ID())].propertyDetails.iCurrentlyInsideProperty CDEBUG1LN(DEBUG_SAFEHOUSE, " Shutting down! Player has left the building") CLEANUP_JUKEBOX() ENDIF #IF FEATURE_CASINO_HEIST ENDIF #ENDIF ENDPROC /// PURPOSE: /// Returns the location of the jukebox interior. Used to grab a handle to the object FUNC VECTOR GET_JUKEBOX_COORDS IF IS_PROPERTY_CLUBHOUSE(iCurrentProperty) RETURN GET_CLUBHOUSE_JUKEBOX_COORDS(iCurrentProperty) #IF FEATURE_CASINO_HEIST ELIF iCurrentProperty = PROPERTY_ARCADE_GARAGE RETURN GET_ARCADE_JUKEBOX_COORDS() #ENDIF ENDIF RETURN <<0.0, 0.0, 0.0>> ENDFUNC /// PURPOSE: /// Sets the station for all emitters in the current interior PROC CHANGE_PLAYLIST(INT iPlaylistID) IF IS_PROPERTY_CLUBHOUSE(iCurrentProperty) //We want to save the current playlist but not try to set the static emiters to an invalid playlist IF iPlaylistID != iMenuOnOffOption AND iPlaylistID != -1 IF pPropertyOwnerID = PLAYER_ID() AND iJBSelectedPlistPlayTime != 0 SAVE_JB_PLAYLIST_PLAY_TIME(iLocalActivePlaylistID) ENDIF CHANGE_CLUBHOUSE_JUKEBOX_PLAYLIST(iCurrentProperty, iPlaylistID) ENDIF IF iPlaylistID != -1 iLocalActivePlaylistID = iPlaylistID ENDIF CDEBUG1LN(DEBUG_SAFEHOUSE, " CHANGE_PLAYLIST Server says Playlist changed to ", iPlaylistID) #IF FEATURE_CASINO_HEIST ELIF iCurrentProperty = PROPERTY_ARCADE_GARAGE //We want to save the current playlist but not try to set the static emiters to an invalid playlist IF iPlaylistID != iMenuOnOffOption AND iPlaylistID != -1 IF pPropertyOwnerID = PLAYER_ID() AND iJBSelectedPlistPlayTime != 0 SAVE_JB_PLAYLIST_PLAY_TIME(iLocalActivePlaylistID) ENDIF CHANGE_ARCADE_JUKEBOX_PLAYLIST(iPlaylistID) ENDIF IF iPlaylistID != -1 iLocalActivePlaylistID = iPlaylistID ENDIF CDEBUG1LN(DEBUG_SAFEHOUSE, " CHANGE_PLAYLIST Server says Playlist changed to ", iPlaylistID) #ENDIF ELSE CASSERTLN(DEBUG_SAFEHOUSE, " CHANGE_PLAYLIST invalid property ID: ", iCurrentProperty) ENDIF ENDPROC /// PURPOSE: /// Turn on or off the static emitters PROC SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(BOOL bEnabled) IF bEnabled SET_BIT(iJukeBoxBS, ciJukeboxEnabled) ELSE CLEAR_BIT(iJukeBoxBS, ciJukeboxEnabled) ENDIF IF IS_PROPERTY_CLUBHOUSE(iCurrentProperty) SET_CLUBHOUSE_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(iCurrentProperty, bEnabled) #IF FEATURE_CASINO_HEIST ELIF iCurrentProperty = PROPERTY_ARCADE_GARAGE SET_ARCADE_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(bEnabled) #ENDIF ELSE CASSERTLN(DEBUG_SAFEHOUSE, " SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE invalid property ID: ", iCurrentProperty) ENDIF ENDPROC /// PURPOSE: /// Run checks for any requests to use the jukebox or change the current playlist PROC RUN_SERVER_CHECKS() IF IS_JUKEBOX_IN_USE() //Check for any new playlist requests IF IS_BIT_SET(playerBD[serverBD.iJukeboxUserID].iBitSet, ciRequestedPlaylistChange) IF playerBD[serverBD.iJukeboxUserID].iNewPlaylistRequestID = iMenuOnOffOption IF IS_JUKEBOX_ON() CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_SERVER_CHECKS jukebox no longer in use. Requesting Jukebox turn OFF by player: ", serverBD.iJukeboxUserID) serverBD.iJukeboxServerState = JBServerStageOff serverBD.iActivePlaylistID = iMenuOnOffOption IF NATIVE_TO_INT(pPropertyOwnerID) = serverBD.iJukeboxUserID CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_SERVER_CHECKS jukebox no longer in use. Property Owner requested turn off") serverBD.bNewPlaylistSelectedByOwner = TRUE ENDIF ENDIF ELIF serverBD.iActivePlaylistID != playerBD[serverBD.iJukeboxUserID].iNewPlaylistRequestID serverBD.iActivePlaylistID = playerBD[serverBD.iJukeboxUserID].iNewPlaylistRequestID CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_SERVER_CHECKS jukebox no longer in use. Requesting PList change to ", serverBD.iActivePlaylistID, " by player: ", serverBD.iJukeboxUserID) IF NATIVE_TO_INT(pPropertyOwnerID) = serverBD.iJukeboxUserID CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_SERVER_CHECKS jukebox no longer in use. Property Owner requested state change") serverBD.bNewPlaylistSelectedByOwner = TRUE ENDIF serverBD.iJukeboxServerState = JBServerStageOn ENDIF ENDIF //Check for any new playlist requests IF IS_BIT_SET(playerBD[serverBD.iJukeboxUserID].iBitSet, ciRequestedVolumeChange) IF serverBD.fVolume != playerBD[serverBD.iJukeboxUserID].fVolume serverBD.fVolume = playerBD[serverBD.iJukeboxUserID].fVolume CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_SERVER_CHECKS - Requesting volume change to ", serverBD.fVolume, " by player: ", serverBD.iJukeboxUserID) ENDIF ENDIF //Monitor the player using the jukebox IF NOT IS_BIT_SET(playerBD[serverBD.iJukeboxUserID].iBitSet, ciUsingJukebox) AND NOT IS_BIT_SET(playerBD[serverBD.iJukeboxUserID].iBitSet, ciRequestingUseOfJukebox) serverBD.iJukeboxUserID = -1 ENDIF //Look for any new requests to use the JB ELIF IS_BIT_SET(playerBD[iStaggeredPlayerLoop].iBitSet, ciRequestingUseOfJukebox) IF NOT IS_JUKEBOX_IN_USE() serverBD.iJukeboxUserID = iStaggeredPlayerLoop CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_SERVER_CHECKS jukebox now in use by player ", iStaggeredPlayerLoop) ENDIF ENDIF //Make sure we reset this flag once the oner has saved the new playlist //We do this because the owner of the clubhouse may not be the script host IF NOT IS_JUKEBOX_IN_USE() #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE IF GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID = serverBD.iActivePlaylistID AND (NOT IS_JUKEBOX_ON() AND GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID = iMenuOnOffOption) serverBD.bNewPlaylistSelectedByOwner = FALSE ENDIF ELSE #ENDIF IF GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID = serverBD.iActivePlaylistID AND (NOT IS_JUKEBOX_ON() AND GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID = iMenuOnOffOption) serverBD.bNewPlaylistSelectedByOwner = FALSE ENDIF #IF FEATURE_CASINO_HEIST ENDIF #ENDIF ENDIF //Move to the next player in the loop iStaggeredPlayerLoop ++ IF iStaggeredPlayerLoop = NUM_NETWORK_PLAYERS iStaggeredPlayerLoop = 0 ENDIF ENDPROC /// PURPOSE: /// Run client side checks. Currently only checks for playlist changes PROC RUN_CLIENT_CHECKS() BOOL bServerJBEnabled = IS_JUKEBOX_ON() IF serverBD.iActivePlaylistID != iLocalActivePlaylistID CHANGE_PLAYLIST(serverBD.iActivePlaylistID) //Set our stat and BD if we're the owner //We do this because the owner of the clubhouse may not be the script host IF pPropertyOwnerID = PLAYER_ID() AND serverBD.bNewPlaylistSelectedByOwner #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE SET_PACKED_STAT_INT(PACKED_MP_INT_ARCADE_JB_SAVED_PLAYLIST, iLocalActivePlaylistID) GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID = iLocalActivePlaylistID ELSE #ENDIF SET_PACKED_STAT_INT(PACKED_MP_INT_CLUBHOUSE_JB_SAVED_PLAYLIST, iLocalActivePlaylistID) GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID = iLocalActivePlaylistID #IF FEATURE_CASINO_HEIST ENDIF #ENDIF CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_CLIENT_CHECKS property owner setting PL stats") ENDIF ENDIF IF (IS_BIT_SET(iJukeBoxBS, ciJukeboxEnabled) != bServerJBEnabled) SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(bServerJBEnabled) //Set our stat and BD if we're the owner //We do this because the owner of the clubhouse may not be the script host IF pPropertyOwnerID = PLAYER_ID() AND serverBD.bNewPlaylistSelectedByOwner AND NOT bServerJBEnabled #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE SET_PACKED_STAT_INT(PACKED_MP_INT_ARCADE_JB_SAVED_PLAYLIST, iMenuOnOffOption) GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID = iMenuOnOffOption ELSE #ENDIF SET_PACKED_STAT_INT(PACKED_MP_INT_CLUBHOUSE_JB_SAVED_PLAYLIST, iMenuOnOffOption) GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID = iMenuOnOffOption #IF FEATURE_CASINO_HEIST ENDIF #ENDIF CDEBUG1LN(DEBUG_SAFEHOUSE, " RUN_CLIENT_CHECKS property owner setting PL stat to OFF") ENDIF ENDIF ENDPROC PROC RUN_AUTOSAVE_STAT_TIMER() IF pPropertyOwnerID = PLAYER_ID() AND IS_JUKEBOX_ON() IF NOT HAS_NET_TIMER_STARTED(stStatAutosaveTimer) START_NET_TIMER(stStatAutosaveTimer) ELIF HAS_NET_TIMER_EXPIRED(stStatAutosaveTimer, 180000) SAVE_JB_PLAYLIST_PLAY_TIME(iLocalActivePlaylistID) REINIT_NET_TIMER(stStatAutosaveTimer) ENDIF ENDIF ENDPROC //FEATURE_BIKER //***********SCRIPT functions*********** SCRIPT CDEBUG1LN(DEBUG_SAFEHOUSE, " started \"", GET_THIS_SCRIPT_NAME(), "\"") IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_KEY("ob_jukebox")) > 1 CDEBUG1LN(DEBUG_SAFEHOUSE, " JUKEBOX script already running! cleaning up.") CLEANUP_JUKEBOX() ENDIF iCurrentProperty = GlobalplayerBD_FM[NATIVE_TO_INT(PLAYER_ID())].propertyDetails.iCurrentlyInsideProperty #IF FEATURE_CASINO_HEIST IF IS_PLAYER_IN_ARCADE_PROPERTY(PLAYER_ID()) iCurrentProperty = PROPERTY_ARCADE_GARAGE ENDIF #ENDIF iMenuOnOffOption = GET_MENU_OFF_OPTION() RUN_CLEANUP_CHECKS() RUN_NETWORK_SCRIPT_INIT() // Default cleanup IF HAS_FORCE_CLEANUP_OCCURRED() OR MPGlobalsAmbience.bRunningFmIntroCut IF MPGlobalsAmbience.bRunningFmIntroCut CDEBUG1LN(DEBUG_SAFEHOUSE, " bRunningFmIntroCut is true so cleaning up!") ENDIF CDEBUG1LN(DEBUG_SAFEHOUSE, " DEFAULT CLEANUP") CLEANUP_JUKEBOX() ENDIF //Get the ID of the owner so we can check their BD GAMER_HANDLE sPropertyOwnerGH GET_GAMER_HANDLE_OF_PROPERTY_OWNER(PLAYER_ID(), sPropertyOwnerGH) IF IS_GAMER_HANDLE_VALID(sPropertyOwnerGH) IF NETWORK_IS_GAMER_IN_MY_SESSION(sPropertyOwnerGH) pPropertyOwnerID = NETWORK_GET_PLAYER_FROM_GAMER_HANDLE(sPropertyOwnerGH) ENDIF ENDIF #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE pPropertyOwnerID = GET_OWNER_OF_SIMPLE_INTERIOR_PLAYER_IS_IN(PLAYER_ID()) START_AUDIO_SCENE("dlc_ch_arcade_music_volume") SET_AUDIO_SCENE_VARIABLE("dlc_ch_arcade_music_volume", "ArcadeRadioVolumeDucking", serverBD.fVolume) ENDIF #ENDIF IF pPropertyOwnerID = INVALID_PLAYER_INDEX() CDEBUG1LN(DEBUG_SAFEHOUSE, " CLEANUP pPropertyOwnerID = INVALID_PLAYER_INDEX") CLEANUP_JUKEBOX() ENDIF IF NETWORK_IS_HOST_OF_THIS_SCRIPT() //Select the saved playlist or turn off the jukebox #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE IF GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID != iMenuOnOffOption AND HAS_PLAYER_COMPLETED_FULL_ARCADE_SETUP(pPropertyOwnerID) CHANGE_PLAYLIST(GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iArcadeJBPlaylistID) SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(TRUE) serverBD.fVolume = 0.5 serverBD.iJukeboxServerState = JBServerStageOn serverBD.iActivePlaylistID = iLocalActivePlaylistID INIT_TIME_STAMP_FOR_CURRENT_PLAYLIST() ELSE SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(FALSE) serverBD.fVolume = 0.5 serverBD.iJukeboxServerState = JBServerStageOff ENDIF ELSE #ENDIF IF GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID != iMenuOnOffOption CHANGE_PLAYLIST(GlobalplayerBD_FM[NATIVE_TO_INT(pPropertyOwnerID)].propertyDetails.iClubhouseJBPlaylistID) SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(TRUE) serverBD.iJukeboxServerState = JBServerStageOn serverBD.iActivePlaylistID = iLocalActivePlaylistID INIT_TIME_STAMP_FOR_CURRENT_PLAYLIST() ELSE SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(FALSE) serverBD.iJukeboxServerState = JBServerStageOff ENDIF #IF FEATURE_CASINO_HEIST ENDIF #ENDIF ELSE //Get the current playlist and activate the static emitters CHANGE_PLAYLIST(serverBD.iActivePlaylistID) SET_ALL_JUKEBOX_STATIC_EMITTERS_ON_OFF_STATE(IS_JUKEBOX_ON()) ENDIF /// main update loop WHILE TRUE RUN_CLEANUP_CHECKS() iMenuOnOffOption = GET_MENU_OFF_OPTION() #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE SET_AUDIO_SCENE_VARIABLE("dlc_ch_arcade_music_volume", "ArcadeRadioVolumeDucking", serverBD.fVolume) ENDIF #ENDIF IF obJukebox != NULL AND NOT ARE_VECTORS_EQUAL(vSynchSceneOrigin, <<0.0, 0.0, 0.0>>) IF NETWORK_IS_HOST_OF_THIS_SCRIPT() RUN_SERVER_CHECKS() ENDIF //Runs the sync scene and controls moving through local jukebox stages RUN_JUKEBOX_ACTIVITY() //Responds to changes from the server RUN_CLIENT_CHECKS() //Run auto save timer RUN_AUTOSAVE_STAT_TIMER() ELSE //Find the object for the property we are inside //We don't do this to start with as we need to setup the static emitters before the jukebox model is ready IF iCurrentProperty != -1 AND iCurrentProperty <= MAX_MP_PROPERTIES vJukeboxCoords = GET_JUKEBOX_COORDS() IF GET_FRAME_COUNT() % 4 = 0 CDEBUG1LN(DEBUG_SAFEHOUSE, " Looking for Jukebox at coords: ", vJukeboxCoords, " In property: ", iCurrentProperty) ENDIF #IF FEATURE_CASINO_HEIST IF iCurrentProperty = PROPERTY_ARCADE_GARAGE obJukebox = GET_CLOSEST_OBJECT_OF_TYPE(vJukeboxCoords, 2.0, INT_TO_ENUM(MODEL_NAMES, HASH("ch_prop_arcade_jukebox_01a")), TRUE, FALSE, FALSE) ELSE #ENDIF obJukebox = GET_CLOSEST_OBJECT_OF_TYPE(vJukeboxCoords, 2.0, INT_TO_ENUM(MODEL_NAMES, HASH("bkr_prop_clubhouse_jukebox_01a")), TRUE, FALSE, FALSE) #IF FEATURE_CASINO_HEIST ENDIF #ENDIF //Calculate the trigger vector IF DOES_ENTITY_EXIST(obJukebox) vtrigger = GET_ENTITY_COORDS(obJukebox,TRUE) - (GET_ENTITY_FORWARD_VECTOR(obJukebox)* 0.6) vtrigger.z += 0.5 vSynchSceneOrigin = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(obJukebox, <<0.0, -0.12, -0.0315>>) CDEBUG1LN(DEBUG_SAFEHOUSE, ": Found Jukebox! vSyncSceneOrigin: ", vSynchSceneOrigin) ENDIF ELSE CDEBUG1LN(DEBUG_SAFEHOUSE, " JUKEBOX script not in a property so cleaning up!") CLEANUP_JUKEBOX() ENDIF ENDIF #IF IS_DEBUG_BUILD IF IS_DEBUG_KEY_JUST_PRESSED(KEY_Q, KEYBOARD_MODIFIER_CTRL_SHIFT, "Kill Jukebox Script") CLEANUP_JUKEBOX(TRUE) ENDIF #ENDIF WAIT(0) ENDWHILE // Script should never reach here. Always terminate with cleanup function. CASSERTLN(DEBUG_SAFEHOUSE, " \"", GET_THIS_SCRIPT_NAME(), "\" should never reach here. Always terminate with cleanup function.") ENDSCRIPT