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