1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 //
23 /*
24 =======================================================================
25 
26 ADD BOTS MENU
27 
28 =======================================================================
29 */
30 
31 
32 #include "ui_local.h"
33 
34 
35 #define ART_BACK0			"menu/art/back_0"
36 #define ART_BACK1			"menu/art/back_1"
37 #define ART_FIGHT0			"menu/art/accept_0"
38 #define ART_FIGHT1			"menu/art/accept_1"
39 #define ART_BACKGROUND		"menu/art/addbotframe"
40 #define ART_ARROWS			"menu/art/arrows_vert_0"
41 #define ART_ARROWUP			"menu/art/arrows_vert_top"
42 #define ART_ARROWDOWN		"menu/art/arrows_vert_bot"
43 
44 #define ID_BACK				10
45 #define ID_GO				11
46 #define ID_LIST				12
47 #define ID_UP				13
48 #define ID_DOWN				14
49 #define ID_SKILL			15
50 #define ID_TEAM				16
51 #define ID_BOTNAME0			20
52 #define ID_BOTNAME1			21
53 #define ID_BOTNAME2			22
54 #define ID_BOTNAME3			23
55 #define ID_BOTNAME4			24
56 #define ID_BOTNAME5			25
57 #define ID_BOTNAME6			26
58 
59 
60 typedef struct {
61 	menuframework_s	menu;
62 	menubitmap_s	arrows;
63 	menubitmap_s	up;
64 	menubitmap_s	down;
65 	menutext_s		bots[7];
66 	menulist_s		skill;
67 	menulist_s		team;
68 	menubitmap_s	go;
69 	menubitmap_s	back;
70 
71 	int				numBots;
72 	int				delay;
73 	int				baseBotNum;
74 	int				selectedBotNum;
75 	int				sortedBotNums[MAX_BOTS];
76 	char			botnames[7][32];
77 } addBotsMenuInfo_t;
78 
79 static addBotsMenuInfo_t	addBotsMenuInfo;
80 
81 
82 /*
83 =================
84 UI_AddBotsMenu_FightEvent
85 =================
86 */
UI_AddBotsMenu_FightEvent(void * ptr,int event)87 static void UI_AddBotsMenu_FightEvent( void* ptr, int event ) {
88 	const char	*team;
89 	int			skill;
90 
91 	if (event != QM_ACTIVATED) {
92 		return;
93 	}
94 
95 	team = addBotsMenuInfo.team.itemnames[addBotsMenuInfo.team.curvalue];
96 	skill = addBotsMenuInfo.skill.curvalue + 1;
97 
98 	trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s %i\n",
99 		addBotsMenuInfo.botnames[addBotsMenuInfo.selectedBotNum], skill, team, addBotsMenuInfo.delay) );
100 
101 	addBotsMenuInfo.delay += 1500;
102 }
103 
104 
105 /*
106 =================
107 UI_AddBotsMenu_BotEvent
108 =================
109 */
UI_AddBotsMenu_BotEvent(void * ptr,int event)110 static void UI_AddBotsMenu_BotEvent( void* ptr, int event ) {
111 	if (event != QM_ACTIVATED) {
112 		return;
113 	}
114 
115 	addBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_orange;
116 	addBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0;
117 	addBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_white;
118 }
119 
120 
121 /*
122 =================
123 UI_AddBotsMenu_BackEvent
124 =================
125 */
UI_AddBotsMenu_BackEvent(void * ptr,int event)126 static void UI_AddBotsMenu_BackEvent( void* ptr, int event ) {
127 	if (event != QM_ACTIVATED) {
128 		return;
129 	}
130 	UI_PopMenu();
131 }
132 
133 
134 /*
135 =================
136 UI_AddBotsMenu_SetBotNames
137 =================
138 */
UI_AddBotsMenu_SetBotNames(void)139 static void UI_AddBotsMenu_SetBotNames( void ) {
140 	int			n;
141 	const char	*info;
142 
143 	for ( n = 0; n < 7; n++ ) {
144 		info = UI_GetBotInfoByNumber( addBotsMenuInfo.sortedBotNums[addBotsMenuInfo.baseBotNum + n] );
145 		Q_strncpyz( addBotsMenuInfo.botnames[n], Info_ValueForKey( info, "name" ), sizeof(addBotsMenuInfo.botnames[n]) );
146 	}
147 
148 }
149 
150 
151 /*
152 =================
153 UI_AddBotsMenu_UpEvent
154 =================
155 */
UI_AddBotsMenu_UpEvent(void * ptr,int event)156 static void UI_AddBotsMenu_UpEvent( void* ptr, int event ) {
157 	if (event != QM_ACTIVATED) {
158 		return;
159 	}
160 
161 	if( addBotsMenuInfo.baseBotNum > 0 ) {
162 		addBotsMenuInfo.baseBotNum--;
163 		UI_AddBotsMenu_SetBotNames();
164 	}
165 }
166 
167 
168 /*
169 =================
170 UI_AddBotsMenu_DownEvent
171 =================
172 */
UI_AddBotsMenu_DownEvent(void * ptr,int event)173 static void UI_AddBotsMenu_DownEvent( void* ptr, int event ) {
174 	if (event != QM_ACTIVATED) {
175 		return;
176 	}
177 
178 	if( addBotsMenuInfo.baseBotNum + 7 < addBotsMenuInfo.numBots ) {
179 		addBotsMenuInfo.baseBotNum++;
180 		UI_AddBotsMenu_SetBotNames();
181 	}
182 }
183 
184 
185 /*
186 =================
187 UI_AddBotsMenu_GetSortedBotNums
188 =================
189 */
UI_AddBotsMenu_SortCompare(const void * arg1,const void * arg2)190 static int QDECL UI_AddBotsMenu_SortCompare( const void *arg1, const void *arg2 ) {
191 	int			num1, num2;
192 	const char	*info1, *info2;
193 	const char	*name1, *name2;
194 
195 	num1 = *(int *)arg1;
196 	num2 = *(int *)arg2;
197 
198 	info1 = UI_GetBotInfoByNumber( num1 );
199 	info2 = UI_GetBotInfoByNumber( num2 );
200 
201 	name1 = Info_ValueForKey( info1, "name" );
202 	name2 = Info_ValueForKey( info2, "name" );
203 
204 	return Q_stricmp( name1, name2 );
205 }
206 
UI_AddBotsMenu_GetSortedBotNums(void)207 static void UI_AddBotsMenu_GetSortedBotNums( void ) {
208 	int		n;
209 
210 	// initialize the array
211 	for( n = 0; n < addBotsMenuInfo.numBots; n++ ) {
212 		addBotsMenuInfo.sortedBotNums[n] = n;
213 	}
214 
215 	qsort( addBotsMenuInfo.sortedBotNums, addBotsMenuInfo.numBots, sizeof(addBotsMenuInfo.sortedBotNums[0]), UI_AddBotsMenu_SortCompare );
216 }
217 
218 
219 /*
220 =================
221 UI_AddBotsMenu_Draw
222 =================
223 */
UI_AddBotsMenu_Draw(void)224 static void UI_AddBotsMenu_Draw( void ) {
225 	UI_DrawBannerString( 320, 16, "ADD BOTS", UI_CENTER, color_white );
226 	UI_DrawNamedPic( 320-233, 240-166, 466, 332, ART_BACKGROUND );
227 
228 	// standard menu drawing
229 	Menu_Draw( &addBotsMenuInfo.menu );
230 }
231 
232 
233 /*
234 =================
235 UI_AddBotsMenu_Init
236 =================
237 */
238 static const char *skillNames[] = {
239 	"I Can Win",
240 	"Bring It On",
241 	"Hurt Me Plenty",
242 	"Hardcore",
243 	"Nightmare!",
244 	NULL
245 };
246 
247 static const char *teamNames1[] = {
248 	"Free",
249 	NULL
250 };
251 
252 static const char *teamNames2[] = {
253 	"Red",
254 	"Blue",
255 	NULL
256 };
257 
UI_AddBotsMenu_Init(void)258 static void UI_AddBotsMenu_Init( void ) {
259 	int		n;
260 	int		y;
261 	int		gametype;
262 	int		count;
263 	char	info[MAX_INFO_STRING];
264 
265 	trap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING);
266 	gametype = atoi( Info_ValueForKey( info,"g_gametype" ) );
267 
268 	memset( &addBotsMenuInfo, 0 ,sizeof(addBotsMenuInfo) );
269 	addBotsMenuInfo.menu.draw = UI_AddBotsMenu_Draw;
270 	addBotsMenuInfo.menu.fullscreen = qfalse;
271 	addBotsMenuInfo.menu.wrapAround = qtrue;
272 	addBotsMenuInfo.delay = 1000;
273 
274 	UI_AddBots_Cache();
275 
276 	addBotsMenuInfo.numBots = UI_GetNumBots();
277 	count = addBotsMenuInfo.numBots < 7 ? addBotsMenuInfo.numBots : 7;
278 
279 	addBotsMenuInfo.arrows.generic.type  = MTYPE_BITMAP;
280 	addBotsMenuInfo.arrows.generic.name  = ART_ARROWS;
281 	addBotsMenuInfo.arrows.generic.flags = QMF_INACTIVE;
282 	addBotsMenuInfo.arrows.generic.x	 = 200;
283 	addBotsMenuInfo.arrows.generic.y	 = 128;
284 	addBotsMenuInfo.arrows.width  	     = 64;
285 	addBotsMenuInfo.arrows.height  	     = 128;
286 
287 	addBotsMenuInfo.up.generic.type	    = MTYPE_BITMAP;
288 	addBotsMenuInfo.up.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
289 	addBotsMenuInfo.up.generic.x		= 200;
290 	addBotsMenuInfo.up.generic.y		= 128;
291 	addBotsMenuInfo.up.generic.id	    = ID_UP;
292 	addBotsMenuInfo.up.generic.callback = UI_AddBotsMenu_UpEvent;
293 	addBotsMenuInfo.up.width  		    = 64;
294 	addBotsMenuInfo.up.height  		    = 64;
295 	addBotsMenuInfo.up.focuspic         = ART_ARROWUP;
296 
297 	addBotsMenuInfo.down.generic.type	  = MTYPE_BITMAP;
298 	addBotsMenuInfo.down.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
299 	addBotsMenuInfo.down.generic.x		  = 200;
300 	addBotsMenuInfo.down.generic.y		  = 128+64;
301 	addBotsMenuInfo.down.generic.id	      = ID_DOWN;
302 	addBotsMenuInfo.down.generic.callback = UI_AddBotsMenu_DownEvent;
303 	addBotsMenuInfo.down.width  		  = 64;
304 	addBotsMenuInfo.down.height  		  = 64;
305 	addBotsMenuInfo.down.focuspic         = ART_ARROWDOWN;
306 
307 	for( n = 0, y = 120; n < count; n++, y += 20 ) {
308 		addBotsMenuInfo.bots[n].generic.type		= MTYPE_PTEXT;
309 		addBotsMenuInfo.bots[n].generic.flags		= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
310 		addBotsMenuInfo.bots[n].generic.id			= ID_BOTNAME0 + n;
311 		addBotsMenuInfo.bots[n].generic.x			= 320 - 56;
312 		addBotsMenuInfo.bots[n].generic.y			= y;
313 		addBotsMenuInfo.bots[n].generic.callback	= UI_AddBotsMenu_BotEvent;
314 		addBotsMenuInfo.bots[n].string				= addBotsMenuInfo.botnames[n];
315 		addBotsMenuInfo.bots[n].color				= color_orange;
316 		addBotsMenuInfo.bots[n].style				= UI_LEFT|UI_SMALLFONT;
317 	}
318 
319 	y += 12;
320 	addBotsMenuInfo.skill.generic.type		= MTYPE_SPINCONTROL;
321 	addBotsMenuInfo.skill.generic.flags		= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
322 	addBotsMenuInfo.skill.generic.x			= 320;
323 	addBotsMenuInfo.skill.generic.y			= y;
324 	addBotsMenuInfo.skill.generic.name		= "Skill:";
325 	addBotsMenuInfo.skill.generic.id		= ID_SKILL;
326 	addBotsMenuInfo.skill.itemnames			= skillNames;
327 	addBotsMenuInfo.skill.curvalue			= Com_Clamp( 0, 4, (int)trap_Cvar_VariableValue( "g_spSkill" ) - 1 );
328 
329 	y += SMALLCHAR_HEIGHT;
330 	addBotsMenuInfo.team.generic.type		= MTYPE_SPINCONTROL;
331 	addBotsMenuInfo.team.generic.flags		= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
332 	addBotsMenuInfo.team.generic.x			= 320;
333 	addBotsMenuInfo.team.generic.y			= y;
334 	addBotsMenuInfo.team.generic.name		= "Team: ";
335 	addBotsMenuInfo.team.generic.id			= ID_TEAM;
336 	if( gametype >= GT_TEAM ) {
337 		addBotsMenuInfo.team.itemnames		= teamNames2;
338 	}
339 	else {
340 		addBotsMenuInfo.team.itemnames		= teamNames1;
341 		addBotsMenuInfo.team.generic.flags	= QMF_GRAYED;
342 	}
343 
344 	addBotsMenuInfo.go.generic.type			= MTYPE_BITMAP;
345 	addBotsMenuInfo.go.generic.name			= ART_FIGHT0;
346 	addBotsMenuInfo.go.generic.flags		= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
347 	addBotsMenuInfo.go.generic.id			= ID_GO;
348 	addBotsMenuInfo.go.generic.callback		= UI_AddBotsMenu_FightEvent;
349 	addBotsMenuInfo.go.generic.x			= 320+128-128;
350 	addBotsMenuInfo.go.generic.y			= 256+128-64;
351 	addBotsMenuInfo.go.width  				= 128;
352 	addBotsMenuInfo.go.height  				= 64;
353 	addBotsMenuInfo.go.focuspic				= ART_FIGHT1;
354 
355 	addBotsMenuInfo.back.generic.type		= MTYPE_BITMAP;
356 	addBotsMenuInfo.back.generic.name		= ART_BACK0;
357 	addBotsMenuInfo.back.generic.flags		= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
358 	addBotsMenuInfo.back.generic.id			= ID_BACK;
359 	addBotsMenuInfo.back.generic.callback	= UI_AddBotsMenu_BackEvent;
360 	addBotsMenuInfo.back.generic.x			= 320-128;
361 	addBotsMenuInfo.back.generic.y			= 256+128-64;
362 	addBotsMenuInfo.back.width				= 128;
363 	addBotsMenuInfo.back.height				= 64;
364 	addBotsMenuInfo.back.focuspic			= ART_BACK1;
365 
366 	addBotsMenuInfo.baseBotNum = 0;
367 	addBotsMenuInfo.selectedBotNum = 0;
368 	addBotsMenuInfo.bots[0].color = color_white;
369 
370 	UI_AddBotsMenu_GetSortedBotNums();
371 	UI_AddBotsMenu_SetBotNames();
372 
373 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.arrows );
374 
375 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.up );
376 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.down );
377 	for( n = 0; n < count; n++ ) {
378 		Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.bots[n] );
379 	}
380 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.skill );
381 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.team );
382 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.go );
383 	Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.back );
384 }
385 
386 
387 /*
388 =================
389 UI_AddBots_Cache
390 =================
391 */
UI_AddBots_Cache(void)392 void UI_AddBots_Cache( void ) {
393 	trap_R_RegisterShaderNoMip( ART_BACK0 );
394 	trap_R_RegisterShaderNoMip( ART_BACK1 );
395 	trap_R_RegisterShaderNoMip( ART_FIGHT0 );
396 	trap_R_RegisterShaderNoMip( ART_FIGHT1 );
397 	trap_R_RegisterShaderNoMip( ART_BACKGROUND );
398 	trap_R_RegisterShaderNoMip( ART_ARROWS );
399 	trap_R_RegisterShaderNoMip( ART_ARROWUP );
400 	trap_R_RegisterShaderNoMip( ART_ARROWDOWN );
401 }
402 
403 
404 /*
405 =================
406 UI_AddBotsMenu
407 =================
408 */
UI_AddBotsMenu(void)409 void UI_AddBotsMenu( void ) {
410 	UI_AddBotsMenu_Init();
411 	UI_PushMenu( &addBotsMenuInfo.menu );
412 }
413