mirror of
https://github.com/Q3Rally-Team/q3rally.git
synced 2024-11-26 13:51:42 +00:00
9b86138351
Fix IQM quat normalize fail case Remove erroneous newlines from Com_Error in sdl_glimp.c Restore OpenGL 1.1 support (GL_CLAMP) q3rcc: Allow to override build date Fix lightning gun handling for corpses and single player podiums Fix for macOS Catalina screen resolution issue Fix team orders menu not listing clients with lower clientnums Fix duplicate team join center print for bots and g_teamAutoJoin E2K: fixed build by MCST lcc compiler when using USE_CURL=1 option
450 lines
11 KiB
C
450 lines
11 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
Copyright (C) 2002-2015 Q3Rally Team (Per Thormann - q3rally@gmail.com)
|
|
|
|
This file is part of q3rally source code.
|
|
|
|
q3rally source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
q3rally source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with q3rally; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
//
|
|
/*
|
|
=======================================================================
|
|
|
|
TEAM ORDERS MENU
|
|
|
|
=======================================================================
|
|
*/
|
|
|
|
|
|
#include "ui_local.h"
|
|
|
|
|
|
#define ART_FRAME "menu/art/addbotframe"
|
|
#define ART_BACK0 "menu/art/back_0"
|
|
#define ART_BACK1 "menu/art/back_1"
|
|
|
|
#define ID_LIST_BOTS 10
|
|
#define ID_LIST_CTF_ORDERS 11
|
|
#define ID_LIST_TEAM_ORDERS 12
|
|
|
|
|
|
typedef struct {
|
|
menuframework_s menu;
|
|
|
|
menutext_s banner;
|
|
menubitmap_s frame;
|
|
|
|
menulist_s list;
|
|
|
|
menubitmap_s back;
|
|
|
|
int gametype;
|
|
int numBots;
|
|
int selectedBot;
|
|
char *bots[9];
|
|
char botNames[9][16];
|
|
} teamOrdersMenuInfo_t;
|
|
|
|
static teamOrdersMenuInfo_t teamOrdersMenuInfo;
|
|
|
|
#define NUM_CTF_ORDERS 7
|
|
static const char *ctfOrders[] = {
|
|
"I Am the Leader",
|
|
"Defend the Base",
|
|
"Follow Me",
|
|
"Get Enemy Flag",
|
|
"Camp Here",
|
|
"Report",
|
|
"I Relinquish Command",
|
|
NULL
|
|
};
|
|
static const char *ctfMessages[] = {
|
|
"i am the leader",
|
|
"%s defend the base",
|
|
"%s follow me",
|
|
"%s get enemy flag",
|
|
"%s camp here",
|
|
"%s report",
|
|
"i stop being the leader",
|
|
NULL
|
|
};
|
|
|
|
#define NUM_TEAM_ORDERS 6
|
|
static const char *teamOrders[] = {
|
|
"I Am the Leader",
|
|
"Follow Me",
|
|
"Roam",
|
|
"Camp Here",
|
|
"Report",
|
|
"I Relinquish Command",
|
|
NULL
|
|
};
|
|
static const char *teamMessages[] = {
|
|
"i am the leader",
|
|
"%s follow me",
|
|
"%s roam",
|
|
"%s camp here",
|
|
"%s report",
|
|
"i stop being the leader",
|
|
NULL
|
|
};
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu_BackEvent
|
|
===============
|
|
*/
|
|
static void UI_TeamOrdersMenu_BackEvent( void *ptr, int event ) {
|
|
if( event != QM_ACTIVATED ) {
|
|
return;
|
|
}
|
|
UI_PopMenu();
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu_SetList
|
|
===============
|
|
*/
|
|
static void UI_TeamOrdersMenu_SetList( int id ) {
|
|
switch( id ) {
|
|
default:
|
|
case ID_LIST_BOTS:
|
|
teamOrdersMenuInfo.list.generic.id = id;
|
|
teamOrdersMenuInfo.list.numitems = teamOrdersMenuInfo.numBots;
|
|
teamOrdersMenuInfo.list.itemnames = (const char **)teamOrdersMenuInfo.bots;
|
|
break;
|
|
|
|
case ID_LIST_CTF_ORDERS:
|
|
teamOrdersMenuInfo.list.generic.id = id;
|
|
teamOrdersMenuInfo.list.numitems = NUM_CTF_ORDERS;
|
|
teamOrdersMenuInfo.list.itemnames = ctfOrders;
|
|
break;
|
|
|
|
case ID_LIST_TEAM_ORDERS:
|
|
teamOrdersMenuInfo.list.generic.id = id;
|
|
teamOrdersMenuInfo.list.numitems = NUM_TEAM_ORDERS;
|
|
teamOrdersMenuInfo.list.itemnames = teamOrders;
|
|
break;
|
|
}
|
|
|
|
teamOrdersMenuInfo.list.generic.bottom = teamOrdersMenuInfo.list.generic.top + teamOrdersMenuInfo.list.numitems * PROP_HEIGHT;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_TeamOrdersMenu_Key
|
|
=================
|
|
*/
|
|
sfxHandle_t UI_TeamOrdersMenu_Key( int key ) {
|
|
menulist_s *l;
|
|
int x;
|
|
int y;
|
|
int index;
|
|
|
|
l = (menulist_s *)Menu_ItemAtCursor( &teamOrdersMenuInfo.menu );
|
|
if( l != &teamOrdersMenuInfo.list ) {
|
|
return Menu_DefaultKey( &teamOrdersMenuInfo.menu, key );
|
|
}
|
|
|
|
switch( key ) {
|
|
case K_MOUSE1:
|
|
x = l->generic.left;
|
|
y = l->generic.top;
|
|
if( UI_CursorInRect( x, y, l->generic.right - x, l->generic.bottom - y ) ) {
|
|
index = (uis.cursory - y) / PROP_HEIGHT;
|
|
l->oldvalue = l->curvalue;
|
|
l->curvalue = index;
|
|
|
|
if( l->generic.callback ) {
|
|
l->generic.callback( l, QM_ACTIVATED );
|
|
return menu_move_sound;
|
|
}
|
|
}
|
|
return menu_null_sound;
|
|
|
|
case K_KP_UPARROW:
|
|
case K_UPARROW:
|
|
l->oldvalue = l->curvalue;
|
|
|
|
if( l->curvalue == 0 ) {
|
|
l->curvalue = l->numitems - 1;
|
|
}
|
|
else {
|
|
l->curvalue--;
|
|
}
|
|
return menu_move_sound;
|
|
|
|
case K_KP_DOWNARROW:
|
|
case K_DOWNARROW:
|
|
l->oldvalue = l->curvalue;
|
|
|
|
if( l->curvalue == l->numitems - 1 ) {
|
|
l->curvalue = 0;;
|
|
}
|
|
else {
|
|
l->curvalue++;
|
|
}
|
|
return menu_move_sound;
|
|
}
|
|
|
|
return Menu_DefaultKey( &teamOrdersMenuInfo.menu, key );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_TeamOrdersMenu_ListDraw
|
|
=================
|
|
*/
|
|
static void UI_TeamOrdersMenu_ListDraw( void *self ) {
|
|
menulist_s *l;
|
|
int x;
|
|
int y;
|
|
int i;
|
|
float *color;
|
|
qboolean hasfocus;
|
|
int style;
|
|
|
|
l = (menulist_s *)self;
|
|
|
|
hasfocus = (l->generic.parent->cursor == l->generic.menuPosition);
|
|
|
|
x = 320;//l->generic.x;
|
|
y = l->generic.y;
|
|
for( i = 0; i < l->numitems; i++ ) {
|
|
style = UI_LEFT|UI_SMALLFONT|UI_CENTER;
|
|
if( i == l->curvalue ) {
|
|
color = color_yellow;
|
|
if( hasfocus ) {
|
|
style |= UI_PULSE;
|
|
}
|
|
}
|
|
else {
|
|
color = color_orange;
|
|
}
|
|
|
|
UI_DrawProportionalString( x, y, l->itemnames[i], style, color );
|
|
y += PROP_HEIGHT;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu_ListEvent
|
|
===============
|
|
*/
|
|
static void UI_TeamOrdersMenu_ListEvent( void *ptr, int event ) {
|
|
int id;
|
|
int selection;
|
|
char message[256];
|
|
|
|
if (event != QM_ACTIVATED)
|
|
return;
|
|
|
|
id = ((menulist_s *)ptr)->generic.id;
|
|
selection = ((menulist_s *)ptr)->curvalue;
|
|
|
|
if( id == ID_LIST_BOTS ) {
|
|
teamOrdersMenuInfo.selectedBot = selection;
|
|
if( teamOrdersMenuInfo.gametype == GT_CTF ) {
|
|
UI_TeamOrdersMenu_SetList( ID_LIST_CTF_ORDERS );
|
|
}
|
|
else {
|
|
UI_TeamOrdersMenu_SetList( ID_LIST_TEAM_ORDERS );
|
|
}
|
|
return;
|
|
}
|
|
|
|
if( id == ID_LIST_CTF_ORDERS ) {
|
|
Com_sprintf( message, sizeof(message), ctfMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] );
|
|
}
|
|
else {
|
|
Com_sprintf( message, sizeof(message), teamMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] );
|
|
}
|
|
|
|
trap_Cmd_ExecuteText( EXEC_APPEND, va( "say_team \"%s\"\n", message ) );
|
|
UI_PopMenu();
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu_BuildBotList
|
|
===============
|
|
*/
|
|
static void UI_TeamOrdersMenu_BuildBotList( void ) {
|
|
uiClientState_t cs;
|
|
int numPlayers;
|
|
int isBot;
|
|
int n;
|
|
char playerTeam;
|
|
char botTeam;
|
|
char info[MAX_INFO_STRING];
|
|
|
|
for( n = 0; n < 9; n++ ) {
|
|
teamOrdersMenuInfo.bots[n] = teamOrdersMenuInfo.botNames[n];
|
|
}
|
|
|
|
trap_GetClientState( &cs );
|
|
|
|
Q_strncpyz( teamOrdersMenuInfo.botNames[0], "Everyone", 16 );
|
|
teamOrdersMenuInfo.numBots = 1;
|
|
|
|
trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
|
|
numPlayers = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
|
|
teamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
|
|
|
|
trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
|
|
playerTeam = *Info_ValueForKey( info, "t" );
|
|
|
|
for( n = 0; n < numPlayers && teamOrdersMenuInfo.numBots < 9; n++ ) {
|
|
if( n == cs.clientNum ) {
|
|
continue;
|
|
}
|
|
|
|
trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
|
|
|
|
isBot = atoi( Info_ValueForKey( info, "skill" ) );
|
|
if( !isBot ) {
|
|
continue;
|
|
}
|
|
|
|
botTeam = *Info_ValueForKey( info, "t" );
|
|
if( botTeam != playerTeam ) {
|
|
continue;
|
|
}
|
|
|
|
Q_strncpyz( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots], Info_ValueForKey( info, "n" ), 16 );
|
|
Q_CleanStr( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots] );
|
|
teamOrdersMenuInfo.numBots++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu_Init
|
|
===============
|
|
*/
|
|
static void UI_TeamOrdersMenu_Init( void ) {
|
|
UI_TeamOrdersMenu_Cache();
|
|
|
|
memset( &teamOrdersMenuInfo, 0, sizeof(teamOrdersMenuInfo) );
|
|
teamOrdersMenuInfo.menu.fullscreen = qfalse;
|
|
teamOrdersMenuInfo.menu.key = UI_TeamOrdersMenu_Key;
|
|
|
|
UI_TeamOrdersMenu_BuildBotList();
|
|
|
|
teamOrdersMenuInfo.banner.generic.type = MTYPE_BTEXT;
|
|
teamOrdersMenuInfo.banner.generic.x = 320;
|
|
teamOrdersMenuInfo.banner.generic.y = 16;
|
|
teamOrdersMenuInfo.banner.string = "TEAM ORDERS";
|
|
teamOrdersMenuInfo.banner.color = color_white;
|
|
teamOrdersMenuInfo.banner.style = UI_CENTER;
|
|
|
|
teamOrdersMenuInfo.frame.generic.type = MTYPE_BITMAP;
|
|
teamOrdersMenuInfo.frame.generic.flags = QMF_INACTIVE;
|
|
teamOrdersMenuInfo.frame.generic.name = ART_FRAME;
|
|
teamOrdersMenuInfo.frame.generic.x = 320-233;
|
|
teamOrdersMenuInfo.frame.generic.y = 240-166;
|
|
teamOrdersMenuInfo.frame.width = 466;
|
|
teamOrdersMenuInfo.frame.height = 332;
|
|
|
|
teamOrdersMenuInfo.list.generic.type = MTYPE_SCROLLLIST;
|
|
teamOrdersMenuInfo.list.generic.flags = QMF_PULSEIFFOCUS;
|
|
teamOrdersMenuInfo.list.generic.ownerdraw = UI_TeamOrdersMenu_ListDraw;
|
|
teamOrdersMenuInfo.list.generic.callback = UI_TeamOrdersMenu_ListEvent;
|
|
teamOrdersMenuInfo.list.generic.x = 320-64;
|
|
teamOrdersMenuInfo.list.generic.y = 120;
|
|
|
|
teamOrdersMenuInfo.back.generic.type = MTYPE_BITMAP;
|
|
teamOrdersMenuInfo.back.generic.name = ART_BACK0;
|
|
teamOrdersMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
|
|
teamOrdersMenuInfo.back.generic.callback = UI_TeamOrdersMenu_BackEvent;
|
|
teamOrdersMenuInfo.back.generic.x = 0;
|
|
teamOrdersMenuInfo.back.generic.y = 480-64;
|
|
teamOrdersMenuInfo.back.width = 128;
|
|
teamOrdersMenuInfo.back.height = 64;
|
|
teamOrdersMenuInfo.back.focuspic = ART_BACK1;
|
|
|
|
Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.banner );
|
|
Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.frame );
|
|
Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.list );
|
|
Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.back );
|
|
|
|
teamOrdersMenuInfo.list.generic.left = 220;
|
|
teamOrdersMenuInfo.list.generic.top = teamOrdersMenuInfo.list.generic.y;
|
|
teamOrdersMenuInfo.list.generic.right = 420;
|
|
UI_TeamOrdersMenu_SetList( ID_LIST_BOTS );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_TeamOrdersMenu_Cache
|
|
=================
|
|
*/
|
|
void UI_TeamOrdersMenu_Cache( void ) {
|
|
trap_R_RegisterShaderNoMip( ART_FRAME );
|
|
trap_R_RegisterShaderNoMip( ART_BACK0 );
|
|
trap_R_RegisterShaderNoMip( ART_BACK1 );
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu
|
|
===============
|
|
*/
|
|
void UI_TeamOrdersMenu( void ) {
|
|
UI_TeamOrdersMenu_Init();
|
|
UI_PushMenu( &teamOrdersMenuInfo.menu );
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_TeamOrdersMenu_f
|
|
===============
|
|
*/
|
|
void UI_TeamOrdersMenu_f( void ) {
|
|
uiClientState_t cs;
|
|
char info[MAX_INFO_STRING];
|
|
int team;
|
|
|
|
// make sure it's a team game
|
|
trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
|
|
teamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
|
|
if( teamOrdersMenuInfo.gametype < GT_TEAM ) {
|
|
return;
|
|
}
|
|
|
|
// not available to spectators
|
|
trap_GetClientState( &cs );
|
|
trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
|
|
team = atoi( Info_ValueForKey( info, "t" ) );
|
|
if( team == TEAM_SPECTATOR ) {
|
|
return;
|
|
}
|
|
|
|
UI_TeamOrdersMenu();
|
|
}
|