diff --git a/COPYING b/COPYING index 88fea84c1..05baf5e3f 100644 --- a/COPYING +++ b/COPYING @@ -22,3 +22,17 @@ is contained within the files as listed. src/game/bg_lib.c BSD license src/client/snd_adpcm.c Stichting Mathematisch Centrum license src/jpeg-6/* JPEG license + +assets/ui/main_menu_music/Finally_Heartbeat.ogg: + "Finally Heartbeat" by Avarthar licensed CC-BY-SA-3.0 + based on "C'Mon" by Analog by Nature, licensed CC-BY-3.0 + and samples from "Tremulous" game assets, licensed CC-BY-SA-3.0 + +assets/ui/main_menu_music/tremfusion_heartbeat.ogg: + by Vortexx licensed CC-BY-SA-2.5 + +assets/ui/main_menu_music/Black_mistUntiteled_3.ogg: + by AutumnLegends licensed CC-BY-NC-SA-3.0 + +assets/ui/main_menu_music/Granger_Foley_v1.ogg: + by Akane licensed CC-BY-SA-2.5 diff --git a/assets/sound/ui/main_menu_music/Black_mistUntitled_3.ogg b/assets/sound/ui/main_menu_music/Black_mistUntitled_3.ogg new file mode 100644 index 000000000..c6e8a4225 Binary files /dev/null and b/assets/sound/ui/main_menu_music/Black_mistUntitled_3.ogg differ diff --git a/assets/sound/ui/main_menu_music/Finally_Heartbeat.ogg b/assets/sound/ui/main_menu_music/Finally_Heartbeat.ogg new file mode 100644 index 000000000..433b37691 Binary files /dev/null and b/assets/sound/ui/main_menu_music/Finally_Heartbeat.ogg differ diff --git a/assets/sound/ui/main_menu_music/Granger_Foley_v1.ogg b/assets/sound/ui/main_menu_music/Granger_Foley_v1.ogg new file mode 100755 index 000000000..746168c62 Binary files /dev/null and b/assets/sound/ui/main_menu_music/Granger_Foley_v1.ogg differ diff --git a/assets/sound/ui/main_menu_music/heartbeat.wav b/assets/sound/ui/main_menu_music/heartbeat.wav new file mode 100644 index 000000000..fc732debb Binary files /dev/null and b/assets/sound/ui/main_menu_music/heartbeat.wav differ diff --git a/assets/sound/ui/main_menu_music/tremfusion_heartbeat.ogg b/assets/sound/ui/main_menu_music/tremfusion_heartbeat.ogg new file mode 100644 index 000000000..995cfc5cb Binary files /dev/null and b/assets/sound/ui/main_menu_music/tremfusion_heartbeat.ogg differ diff --git a/assets/ui/main.menu b/assets/ui/main.menu index 38e812cdc..8442c2702 100644 --- a/assets/ui/main.menu +++ b/assets/ui/main.menu @@ -34,7 +34,7 @@ focusColor WINDOW_FOCUSCOLOR// vim:ft=menu onOpen { uiScript stopRefresh - playlooped "sound/ui/heartbeat.wav" + bucketPlayLooped "sound/ui/main_menu_music" ui_mainMenuSelectedMusic } onESC diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 6627740a4..9e250401b 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -1860,6 +1860,14 @@ void CG_LoadHudMenu( void ) cgDC.stopCinematic = &CG_StopCinematic; cgDC.drawCinematic = &CG_DrawCinematic; cgDC.runCinematicFrame = &CG_RunCinematicFrame; + cgDC.Bucket_Create_Bucket = BG_Bucket_Create_Bucket; + cgDC.Bucket_Delete_Bucket = BG_Bucket_Delete_Bucket; + cgDC.Bucket_Destroy_All_Buckets = BG_Bucket_Destroy_All_Buckets; + cgDC.Bucket_Add_Item_To_Bucket = BG_Bucket_Add_Item_To_Bucket; + cgDC.Bucket_Remove_Item_From_Bucket = BG_Bucket_Remove_Item_From_Bucket; + cgDC.Bucket_Select_A_Random_Item = BG_Bucket_Select_A_Random_Item; + cgDC.Bucket_Select_A_Specific_Item = BG_Bucket_Select_A_Specific_Item; + cgDC.FS_GetFileList = trap_FS_GetFileList; Init_Display( &cgDC ); @@ -2047,6 +2055,7 @@ Called before every level change or subsystem restart */ void CG_Shutdown( void ) { + BG_Bucket_Destroy_All_Buckets( ); CG_UnregisterCommands( ); } diff --git a/src/client/cl_main.cpp b/src/client/cl_main.cpp index 434b68382..ccfcfe5c8 100644 --- a/src/client/cl_main.cpp +++ b/src/client/cl_main.cpp @@ -5057,6 +5057,8 @@ void CL_Shutdown(const char *finalmsg, bool disconnect, bool quit) } recursive = true; + Com_Bucket_Destroy_All_Buckets( ); + noGameRestart = quit; if (disconnect) CL_Disconnect(true); diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index ebd9ed9a1..ae3eb2200 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -3155,7 +3155,7 @@ int BG_SlotsForInventory( int stats[ ] ) { slot = BG_Upgrade( i )->slots; - // this check should never be true + // this check should never be qtrue if( slots & slot ) { Com_Printf( S_COLOR_YELLOW "WARNING: held item %d conflicts with " @@ -3971,3 +3971,42 @@ char *G_CopyString( const char *str ) memcpy( cp, str, size ); return cp; } + +/* +============================================================== + +Bucket Selection System + +============================================================== +*/ + +unsigned int BG_Bucket_Create_Bucket(void) { + Q_Bucket_Create_Bucket(BG_Alloc, BG_Free); +} + +void BG_Bucket_Delete_Bucket(unsigned int bucket_handle) { + Q_Bucket_Delete_Bucket(bucket_handle); +} + +void BG_Bucket_Destroy_All_Buckets(void) { + Q_Bucket_Destroy_All_Buckets(BG_Alloc, BG_Free); +} + +void BG_Bucket_Add_Item_To_Bucket( + unsigned int bucket_handle, void* item) { + Q_Bucket_Add_Item_To_Bucket(bucket_handle, item, BG_Alloc, BG_Free); +} + +void BG_Bucket_Remove_Item_From_Bucket( + unsigned int bucket_handle, void* item) { + Q_Bucket_Remove_Item_From_Bucket( + bucket_handle, item, BG_Alloc, BG_Free); +} + +void* BG_Bucket_Select_A_Random_Item(unsigned int bucket_handle) { + Q_Bucket_Select_A_Random_Item(bucket_handle); +} + +void BG_Bucket_Select_A_Specific_Item(unsigned int bucket_handle, void* item) { + Q_Bucket_Select_A_Specific_Item(bucket_handle, item); +} diff --git a/src/game/bg_public.h b/src/game/bg_public.h index ba96b4cae..102a6e406 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -1260,6 +1260,27 @@ void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t * qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ); +/* +============================================================== + +Bucket Selection System + +============================================================== +*/ + +unsigned int BG_Bucket_Create_Bucket(void); +void BG_Bucket_Delete_Bucket(unsigned int bucket_handle); +void BG_Bucket_Destroy_All_Buckets(void); +void BG_Bucket_Add_Item_To_Bucket( + unsigned int bucket_handle, void* item); +void BG_Bucket_Remove_Item_From_Bucket( + unsigned int bucket_handle, void* item); +void* BG_Bucket_Select_A_Random_Item(unsigned int bucket_handle); +void BG_Bucket_Select_A_Specific_Item( + unsigned int bucket_handle, void* item); +//============================================================== + + #define ARENAS_PER_TIER 4 #define MAX_ARENAS 1024 #define MAX_ARENAS_TEXT 8192 diff --git a/src/game/g_main.c b/src/game/g_main.c index 1a0ab1bde..9d9a4d543 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -746,6 +746,8 @@ void G_ShutdownGame( int restart ) G_FreePlayerModel( ); G_ShutdownMapRotations( ); + BG_Bucket_Destroy_All_Buckets( ); + level.restarted = qfalse; level.surrenderTeam = TEAM_NONE; trap_SetConfigstring( CS_WINNER, "" ); diff --git a/src/qcommon/common.cpp b/src/qcommon/common.cpp index 051f475cf..764b146fa 100644 --- a/src/qcommon/common.cpp +++ b/src/qcommon/common.cpp @@ -3660,3 +3660,46 @@ int QDECL Com_strCompare( const void *a, const void *b ) const char **pb = (const char **)b; return strcmp( *pa, *pb ); } + +/* +============================================================== + +Bucket Selection System + +============================================================== +*/ + +static void *Z_PlaceHolderAlloc(int size) { + Z_Malloc(size); +} + +unsigned int Com_Bucket_Create_Bucket(void) { + Q_Bucket_Create_Bucket(Z_PlaceHolderAlloc, Z_Free); +} + +void Com_Bucket_Delete_Bucket(unsigned int bucket_handle) { + Q_Bucket_Delete_Bucket(bucket_handle); +} + +void Com_Bucket_Destroy_All_Buckets(void) { + Q_Bucket_Destroy_All_Buckets(Z_PlaceHolderAlloc, Z_Free); +} + +void Com_Bucket_Add_Item_To_Bucket( + unsigned int bucket_handle, void* item) { + Q_Bucket_Add_Item_To_Bucket(bucket_handle, item, Z_PlaceHolderAlloc, Z_Free); +} + +void Com_Bucket_Remove_Item_From_Bucket( + unsigned int bucket_handle, void* item) { + Q_Bucket_Remove_Item_From_Bucket( + bucket_handle, item, Z_PlaceHolderAlloc, Z_Free); +} + +void* Com_Bucket_Select_A_Random_Item(unsigned int bucket_handle) { + Q_Bucket_Select_A_Random_Item(bucket_handle); +} + +void Com_Bucket_Select_A_Specific_Item(unsigned int bucket_handle, void* item) { + Q_Bucket_Select_A_Specific_Item(bucket_handle, item); +} diff --git a/src/qcommon/q_math.c b/src/qcommon/q_math.c index 99448506d..90a6d22d6 100644 --- a/src/qcommon/q_math.c +++ b/src/qcommon/q_math.c @@ -1298,6 +1298,348 @@ int Q_isnan( float x ) return (int)( (unsigned int)fi.ui >> 31 ); } + +/* +============================================================== + +Bucket Selection System + +============================================================== +*/ + +typedef enum bucket_lists_s +{ + BUCKET_LIST_A = 0, + BUCKET_LIST_B, + + NUM_BUCKET_LISTS +} bucket_lists_t; + +typedef struct bucket_s +{ + void** list[NUM_BUCKET_LISTS]; + unsigned int list_length[NUM_BUCKET_LISTS]; + bucket_lists_t selection_list; + unsigned int bucket_size; + qboolean bucket_slot_used; +} bucket_t; + +static bucket_t* buckets = NULL; +static unsigned int num_buckets = 0; + +static void Q_Bucket_Resize_Array_Of_Buckets( + unsigned int new_num_buckets, void* (*qalloc)(int size), + void (*qfree)(void *ptr)) { + bucket_t* old_buckets = buckets; + unsigned int num_buckets_to_copy; + const unsigned int num_deleted_buckets = + (num_buckets > new_num_buckets) ? (num_buckets - new_num_buckets) : 0; + + //free bucket lists for any buckets that will be deleted + if(num_deleted_buckets > 0) { + int i; + + for(i = num_buckets - num_deleted_buckets - 1; i < num_buckets ; i++) { + int j; + + for(j = 0; j < NUM_BUCKET_LISTS; j++) { + if(buckets[i].list[i]) { + qfree(buckets[i].list[i]); + } + } + } + } + + if(new_num_buckets > 0) { + buckets = (bucket_t *)qalloc(new_num_buckets * sizeof(bucket_t)); + + if(new_num_buckets > num_buckets) { + num_buckets_to_copy = num_buckets; + } else { + num_buckets_to_copy = new_num_buckets; + } + + if(old_buckets) { + memcpy(buckets, old_buckets, num_buckets_to_copy * sizeof(bucket_t)); + } + } else { + buckets = NULL; + } + + num_buckets = new_num_buckets; + + if(old_buckets) { + qfree(old_buckets); + } +} + +unsigned int Q_Bucket_Create_Bucket( + void* (*qalloc)(int size), void (*qfree)(void *ptr)) { + + //check if there are currently any free slots for a new bucket + if(num_buckets > 0) { + int i; + + for(i = 0; i < num_buckets; i++) { + if(!buckets[i].bucket_slot_used) { + return i; + } + } + } + + //create a new bucket slot, and return it + Q_Bucket_Resize_Array_Of_Buckets((num_buckets + 1), qalloc, qfree); + memset(&buckets[num_buckets - 1], 0, sizeof(bucket_t)); + buckets[num_buckets - 1].bucket_slot_used = qtrue; + return num_buckets - 1; +} + +void Q_Bucket_Delete_Bucket(unsigned int bucket_handle) { + assert( + (bucket_handle < num_buckets) && + buckets[bucket_handle].bucket_slot_used && + "Q_Bucket_Destroy_Bucket: bucket handle not found"); + + buckets[bucket_handle].bucket_slot_used = qfalse; +} + +void Q_Bucket_Destroy_All_Buckets( + void* (*qalloc)(int size), void (*qfree)(void *ptr)) { + Q_Bucket_Resize_Array_Of_Buckets(0, qalloc, qfree); +} + +static void Q_Bucket_Resize_Bucket( + unsigned int bucket_handle, unsigned int new_bucket_size, + void* (*qalloc)(int size), void (*qfree)(void *ptr)) { + void** old_list[NUM_BUCKET_LISTS]; + unsigned int num_items_to_copy; + int i; + + assert( + (bucket_handle < num_buckets) && + buckets[bucket_handle].bucket_slot_used && + "Q_Bucket_Resize_Bucket: bucket handle not found"); + + for(i = 0; i < NUM_BUCKET_LISTS; i++) { + old_list[i] = buckets[bucket_handle].list[i]; + } + + for(i = 0; i < NUM_BUCKET_LISTS; i++) { + buckets[bucket_handle].list[i] = + (void **)qalloc(new_bucket_size * sizeof(void*)); + memset(buckets[bucket_handle].list[i], 0, new_bucket_size * sizeof(void*)); + } + + if(new_bucket_size > buckets[bucket_handle].bucket_size) { + num_items_to_copy = buckets[bucket_handle].bucket_size; + } else { + num_items_to_copy = new_bucket_size; + } + + if(buckets[bucket_handle].bucket_size > 0) { + for(i = 0; i < NUM_BUCKET_LISTS; i++) { + if(old_list[i]) { + memcpy( + buckets[bucket_handle].list[i], + old_list[i], num_items_to_copy * sizeof(void*)); + } + } + } + + buckets[bucket_handle].bucket_size = new_bucket_size; + + for(i = 0; i < NUM_BUCKET_LISTS; i++) { + if(old_list[i]) { + qfree(old_list[i]); + } + } +} + +static void Q_Bucket_Add_Item_To_List( + bucket_t *bucket, void* item, bucket_lists_t bucket_list) { + int list_length; + + assert(bucket && "Q_Bucket_Add_Item_To_List: bucket is NULL"); + + list_length = bucket->list_length[bucket_list]; + + assert( + list_length < bucket->bucket_size && + "Q_Bucket_Add_Item_To_List: adding this item would exceed the bucket_size"); + + //add the item to the end of the list + bucket->list[bucket_list][list_length] = item; + bucket->list_length[bucket_list]++; +} + +static void Q_Bucket_Remove_Item_By_Index_From_List( + bucket_t *bucket, unsigned int item_index, bucket_lists_t bucket_list) { + int list_length; + + assert(bucket && "Q_Bucket_Add_Item_To_List: bucket is NULL"); + + list_length = bucket->list_length[bucket_list]; + + assert( + list_length > 0 && + "Q_Bucket_Add_Item_To_List: bucket list is empty"); + assert( + item_index < list_length && + "Q_Bucket_Add_Item_To_List: item index exceeds bucket list length"); + + //move the last item to the removed item slot + bucket->list[bucket_list][item_index] = + bucket->list[bucket_list][list_length - 1]; + //reduce the length of the list by 1 + bucket->list_length[bucket_list]--; +} + +void Q_Bucket_Add_Item_To_Bucket( + unsigned int bucket_handle, void* item, + void* (*qalloc)(int size), void (*qfree)(void *ptr)) { + + assert( + (bucket_handle < num_buckets) && + buckets[bucket_handle].bucket_slot_used && + "Q_Bucket_Add_Item_To_Bucket: bucket handle not found"); + + Q_Bucket_Resize_Bucket( + bucket_handle, buckets[bucket_handle].bucket_size + 1, + qalloc, qfree); + + Q_Bucket_Add_Item_To_List( + &buckets[bucket_handle], item, + buckets[bucket_handle].selection_list); +} + +void Q_Bucket_Remove_Item_From_Bucket( + unsigned int bucket_handle, void* item, + void* (*qalloc)(int size), void (*qfree)(void *ptr)) { + bucket_t* bucket; + qboolean item_found = qfalse; + int i; + + assert( + (bucket_handle < num_buckets) && + buckets[bucket_handle].bucket_slot_used && + "Q_Bucket_Remove_Item_From_Bucket: bucket handle not found"); + assert( + buckets[bucket_handle].bucket_size > 0 && + "Q_Bucket_Remove_Item_From_Bucket: bucket is empty"); + + bucket = &buckets[bucket_handle]; + + for(i = 0; i < NUM_BUCKET_LISTS; i++) { + int j; + + for(j = 0; j < bucket->list_length[i]; j++) { + if(bucket->list[i][j] == item) { + bucket->list[i][j] = + bucket->list[i][bucket->list_length[i] - 1]; + bucket->list_length[i]--; + Q_Bucket_Resize_Bucket( + bucket_handle, (buckets[bucket_handle].bucket_size - 1), + qalloc, qfree); + item_found = qtrue; + } + } + } + + assert( + item_found && + "Q_Bucket_Remove_Item_From_Bucket: item not found"); +} + +void* Q_Bucket_Select_A_Random_Item(unsigned int bucket_handle) { + bucket_t *bucket; + unsigned int selected_item_index; + void *selected_item; + + assert( + (bucket_handle < num_buckets) && + buckets[bucket_handle].bucket_slot_used && + "Q_Bucket_Select_A_Random_Item: bucket handle not found"); + assert( + buckets[bucket_handle].bucket_size > 0 && + "Q_Bucket_Select_A_Random_Item: bucket is empty"); + + bucket = &buckets[bucket_handle]; + + //check if the selection list is empty + if(bucket->list_length[bucket->selection_list] == 0) { + if(bucket->selection_list == BUCKET_LIST_A) { + bucket->selection_list = BUCKET_LIST_B; + } else { + bucket->selection_list = BUCKET_LIST_A; + } + } + + //select an item from the selection list + selected_item_index = rand() % bucket->list_length[bucket->selection_list]; + selected_item = bucket->list[bucket->selection_list][selected_item_index]; + + //move the item to the other list + Q_Bucket_Remove_Item_By_Index_From_List( + bucket, selected_item_index, bucket->selection_list); + if(bucket->selection_list == BUCKET_LIST_A) { + Q_Bucket_Add_Item_To_List( + bucket, selected_item, BUCKET_LIST_B); + } else { + Q_Bucket_Add_Item_To_List( + bucket, selected_item, BUCKET_LIST_A); + } + + return selected_item; +} + +void Q_Bucket_Select_A_Specific_Item(unsigned int bucket_handle, void* item) { + bucket_t *bucket; + unsigned int selected_item_index, i; + void *selected_item = NULL; + + assert( + (bucket_handle < num_buckets) && + buckets[bucket_handle].bucket_slot_used && + "Q_Bucket_Select_A_Random_Item: bucket handle not found"); + assert( + buckets[bucket_handle].bucket_size > 0 && + "Q_Bucket_Select_A_Random_Item: bucket is empty"); + + bucket = &buckets[bucket_handle]; + + //check if the selection list is empty + if(bucket->list_length[bucket->selection_list] == 0) { + if(bucket->selection_list == BUCKET_LIST_A) { + bucket->selection_list = BUCKET_LIST_B; + } else { + bucket->selection_list = BUCKET_LIST_A; + } + } + + //search for the specific item + for(i = 0; i < bucket->list_length[bucket->selection_list]; i++) { + if(item == bucket->list[bucket->selection_list][i]) { + selected_item_index = i; + selected_item = item; + break; + } + } + + assert(selected_item && "Q_Bucket_Select_A_Specific_Item: item not found"); + + //move the item to the other list + Q_Bucket_Remove_Item_By_Index_From_List( + bucket, selected_item_index, bucket->selection_list); + if(bucket->selection_list == BUCKET_LIST_A) { + Q_Bucket_Add_Item_To_List( + bucket, selected_item, BUCKET_LIST_B); + } else { + Q_Bucket_Add_Item_To_List( + bucket, selected_item, BUCKET_LIST_A); + } +} + + //------------------------------------------------------------------------ #ifndef Q3_VM diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index a854de8cb..d66b3cf61 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -1005,6 +1005,29 @@ typedef enum { CHAN_ANNOUNCER // announcer voices, etc } soundChannel_t; +/* +============================================================== + +Bucket Selection System + +============================================================== +*/ + +unsigned int Q_Bucket_Create_Bucket( + void* (*qalloc)(int size), void (*qfree)(void *ptr)); +void Q_Bucket_Delete_Bucket(unsigned int bucket_handle); +void Q_Bucket_Destroy_All_Buckets( + void* (*qalloc)(int size), void (*qfree)(void *ptr)); +void Q_Bucket_Add_Item_To_Bucket( + unsigned int bucket_handle, void* item, + void* (*qalloc)(int size), void (*qfree)(void *ptr)); +void Q_Bucket_Remove_Item_From_Bucket( + unsigned int bucket_handle, void* item, + void* (*qalloc)(int size), void (*qfree)(void *ptr)); +void* Q_Bucket_Select_A_Random_Item(unsigned int bucket_handle); +void Q_Bucket_Select_A_Specific_Item( + unsigned int bucket_handle, void* item); + /* ======================================================================== diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index f258ce90b..14505f147 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -410,4 +410,23 @@ bool Parse_SourceFileAndLine(int handle, char *filename, int *line); #define DLF_NO_UDP 4 #define DLF_NO_DISCONNECT 8 +/* +============================================================== + +Bucket Selection System + +============================================================== +*/ + +unsigned int Com_Bucket_Create_Bucket(void); +void Com_Bucket_Delete_Bucket(unsigned int bucket_handle); +void Com_Bucket_Destroy_All_Buckets(void); +void Com_Bucket_Add_Item_To_Bucket( + unsigned int bucket_handle, void* item); +void Com_Bucket_Remove_Item_From_Bucket( + unsigned int bucket_handle, void* item); +void* Com_Bucket_Select_A_Random_Item(unsigned int bucket_handle); +void Com_Bucket_Select_A_Specific_Item( + unsigned int bucket_handle, void* item); + #endif // _QCOMMON_H_ diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index 03bce7cf0..a6c2b183b 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -82,6 +82,7 @@ vmCvar_t ui_lastServerRefresh_0_time; vmCvar_t ui_lastServerRefresh_1_time; vmCvar_t ui_lastServerRefresh_2_time; vmCvar_t ui_lastServerRefresh_3_time; +vmCvar_t ui_mainMenuSelectedMusic; vmCvar_t ui_smallFont; vmCvar_t ui_bigFont; vmCvar_t ui_findPlayer; @@ -106,6 +107,7 @@ static cvarTable_t cvarTable[] = {{&ui_browserShowFull, "ui_browserShowFull", "1 {&ui_lastServerRefresh_1, "ui_lastServerRefresh_1_time", "", CVAR_ARCHIVE}, {&ui_lastServerRefresh_2, "ui_lastServerRefresh_2_time", "", CVAR_ARCHIVE}, {&ui_lastServerRefresh_3, "ui_lastServerRefresh_3_time", "", CVAR_ARCHIVE}, + {&ui_mainMenuSelectedMusic, "ui_mainMenuSelectedMusic", "", CVAR_ARCHIVE}, {&ui_smallFont, "ui_smallFont", "0.2", CVAR_ARCHIVE | CVAR_LATCH}, {&ui_bigFont, "ui_bigFont", "0.5", CVAR_ARCHIVE | CVAR_LATCH}, {&ui_findPlayer, "ui_findPlayer", "", CVAR_ARCHIVE}, {&ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE}, @@ -1419,7 +1421,10 @@ void UI_Refresh(int realtime) UI_Shutdown ================= */ -void UI_Shutdown(void) { trap_LAN_SaveCachedServers(); } +void UI_Shutdown(void) { + BG_Bucket_Destroy_All_Buckets( ); + trap_LAN_SaveCachedServers(); +} qboolean Asset_Parse(int handle) { @@ -5367,6 +5372,14 @@ void UI_Init(qboolean inGameLoad) uiInfo.uiDC.stopCinematic = &UI_StopCinematic; uiInfo.uiDC.drawCinematic = &UI_DrawCinematic; uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame; + uiInfo.uiDC.Bucket_Create_Bucket = BG_Bucket_Create_Bucket; + uiInfo.uiDC.Bucket_Delete_Bucket = BG_Bucket_Delete_Bucket; + uiInfo.uiDC.Bucket_Destroy_All_Buckets = BG_Bucket_Destroy_All_Buckets; + uiInfo.uiDC.Bucket_Add_Item_To_Bucket = BG_Bucket_Add_Item_To_Bucket; + uiInfo.uiDC.Bucket_Remove_Item_From_Bucket = BG_Bucket_Remove_Item_From_Bucket; + uiInfo.uiDC.Bucket_Select_A_Random_Item = BG_Bucket_Select_A_Random_Item; + uiInfo.uiDC.Bucket_Select_A_Specific_Item = BG_Bucket_Select_A_Specific_Item; + uiInfo.uiDC.FS_GetFileList = trap_FS_GetFileList; Init_Display(&uiInfo.uiDC); diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 9a964af70..9676b4bf9 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -1820,6 +1820,131 @@ void Script_playLooped(itemDef_t *item, char **args) } } +#define MAX_BUCKET_MENU_SOUNDS 20 + +void Script_playLoopedBucket(itemDef_t *item, char **args) +{ + char play_looped_sound_path[MAX_QPATH]; + char sound[MAX_BUCKET_MENU_SOUNDS][MAX_QPATH]; + char selected_list_cvar_string[1024]; + char sound_list[MAX_BUCKET_MENU_SOUNDS*MAX_QPATH]; + char *sound_ptr; + char *p; + const char *selected_list_cvar; + const char *val; + const char *sound_bucket_directory; + int selected_sound_index[MAX_BUCKET_MENU_SOUNDS]; + int i, j, file_length; + unsigned int num_sounds = 0; + unsigned int num_wav = 0; + unsigned int num_ogg = 0; + unsigned int num_selected_sound_indecies = 0; + unsigned int *play_looped_bucket_handle = + &((menuDef_t*)item->parent)->play_looped_bucket_handle; + qboolean *play_looped_bucket_allocated = + &((menuDef_t*)item->parent)->play_looped_bucket_allocated; + qboolean new_bucket = qfalse; + + for(i = 0; i < MAX_BUCKET_MENU_SOUNDS; i++) { + sound[i][0] = '\0'; + } + + (void)item; + + if(!String_Parse(args, &sound_bucket_directory)) { + return; + } + + if(!String_Parse(args, &selected_list_cvar)) { + return; + } + + num_wav = DC->FS_GetFileList( sound_bucket_directory, ".wav", + sound_list, 10 * MAX_QPATH ); + sound_ptr = sound_list; + num_sounds = num_wav; + + for( i = 0; i < num_wav; i++, sound_ptr += file_length + 1 ) { + file_length = strlen(sound_ptr); + strcpy(sound[i], va("%s", sound_ptr)); + } + + num_sounds = num_wav; + + num_ogg = DC->FS_GetFileList( sound_bucket_directory, ".ogg", + sound_list, 10 * MAX_QPATH ); + sound_ptr = sound_list; + + for( i = 0; i < num_ogg; i++, sound_ptr += file_length + 1 ) { + file_length = strlen(sound_ptr); + strcpy(sound[num_sounds + i], va("%s", sound_ptr)); + } + + num_sounds += num_ogg; + + if(num_sounds == 0) { + return; + } + + if(!*play_looped_bucket_allocated) { + *play_looped_bucket_handle = DC->Bucket_Create_Bucket( ); + *play_looped_bucket_allocated = qtrue; + new_bucket = qtrue; + for(i = 0; i < num_sounds; i++) { + DC->Bucket_Add_Item_To_Bucket( + *play_looped_bucket_handle, (void*)sound[i]); + } + } + + if(selected_list_cvar) { + DC->getCVarString( + selected_list_cvar, selected_list_cvar_string, + sizeof(selected_list_cvar_string)); + + p = selected_list_cvar_string; + + for(i = 0; i < MAX_BUCKET_MENU_SOUNDS; i++) { + if(String_Parse(&p, &val)) { + for(j = 0; j < num_sounds; j++) { + //ensure that the specified selected sound exists + if(!Q_stricmp(val, sound[j])) { + selected_sound_index[num_selected_sound_indecies] = j; + num_selected_sound_indecies++; + break; + } + } + } + } + + Com_Memset(selected_list_cvar_string, 0, sizeof(selected_list_cvar_string)); + if(num_selected_sound_indecies >= num_sounds) { + num_selected_sound_indecies = 0; + } + + for(i = 0; i < num_selected_sound_indecies; i++) { + Q_strcat(selected_list_cvar_string, 1024, va("%s ",sound[selected_sound_index[i]])); + if(new_bucket) { + DC->Bucket_Select_A_Specific_Item( + *play_looped_bucket_handle, (void*)sound[selected_sound_index[i]]); + } + } + } + + val = + (char*)DC->Bucket_Select_A_Random_Item(*play_looped_bucket_handle); + + if(selected_list_cvar) { + Q_strcat(selected_list_cvar_string, 1024, val); + DC->setCVar(selected_list_cvar, selected_list_cvar_string); + } + + if(val) { + strcpy(play_looped_sound_path, va("%s/%s", sound_bucket_directory, val)); + DC->stopBackgroundTrack(); + DC->startBackgroundTrack(play_looped_sound_path, play_looped_sound_path); + } +} + static ID_INLINE float UI_EmoticonHeight(fontInfo_t *font, float scale) { return font->glyphs[(int)'['].height * scale * font->glyphScale; @@ -2331,6 +2456,7 @@ void UI_Text_PaintWithCursor( } commandDef_t commandList[] = { + {"bucketPlayLooped", &Script_playLoopedBucket}, // group/name {"close", &Script_Close}, // menu {"conditionalopen", &Script_ConditionalOpen}, // menu {"exec", &Script_Exec}, // group/name diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 4da0123ab..d21d38edc 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -309,6 +309,9 @@ typedef struct { const char *onClose; // run when the menu is closed const char *onESC; // run when the menu is closed const char *soundName; // background loop sound for menu + qboolean play_looped_bucket_allocated; + unsigned int play_looped_bucket_handle; // for bucket selection of + // background loop sounds vec4_t focusColor; // focus color for items vec4_t disableColor; // focus color for items @@ -416,6 +419,14 @@ typedef struct { void (*stopCinematic)(int handle); void (*drawCinematic)(int handle, float x, float y, float w, float h); void (*runCinematicFrame)(int handle); + unsigned int (*Bucket_Create_Bucket)(void); + void (*Bucket_Delete_Bucket)(unsigned int bucket_handle); + void (*Bucket_Destroy_All_Buckets)(void); + void (*Bucket_Add_Item_To_Bucket)(unsigned int bucket_handle, void* item); + void (*Bucket_Remove_Item_From_Bucket)(unsigned int bucket_handle, void* item); + void* (*Bucket_Select_A_Random_Item)(unsigned int bucket_handle); + void (*Bucket_Select_A_Specific_Item)(unsigned int bucket_handle, void* item); + int (*FS_GetFileList)(const char *path, const char *extension, char *listbuf, int bufsize); float yscale; float xscale;