]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/sbar.qc
CSQC scoreboard now knows about fonts
[divverent/nexuiz.git] / data / qcsrc / client / sbar.qc
1
2 float sb_lines; // still don't know what to do with that NOTE: check dp's sbar.c to see what that should be
3
4 vector sbar;
5 vector sbar_fontsize;
6
7 entity sortedPlayers;
8 entity sortedTeams;
9
10 .float sb_frags;
11 .float sb_team;
12 .float sb_player;
13 .float sb_caps;
14
15 void Sbar_FinaleOverlay()
16 {
17         vector pos;
18         pos_x = (vid_conwidth - 1)/2;
19         pos_y = 16;
20         pos_z = 0;
21         drawpic(pos, "gfx/finale", '0 0', '1 1 1', sbar_alpha_fg, DRAWFLAG_NORMAL);
22 }
23
24 void Sbar_DrawWeapon(float nr, float fade, float active)
25 {
26         vector pos, vsize, color;
27         float value;
28         
29         value = (active) ? 1 : 0.6;
30         color_x = color_y = color_z = value;
31         
32         if(sbar_hudselector == 1)
33         {
34                 // width = 300, height = 100
35                 const float w_width = 32, w_height = 12, w_space = 2, font_size = 8;
36                 
37                 pos_x = (vid_conwidth - w_width * 9) * 0.5 + w_width * nr;
38                 pos_y = (vid_conheight - w_height);
39                 pos_z = 0;
40                 vsize_x = w_width;
41                 vsize_y = w_height;
42                 vsize_z = 0;
43                 drawpic(pos, strcat("gfx/inv_weapon", ftos(nr)), vsize, color, value * fade * sbar_alpha_fg, 0);
44                 pos_x += w_space;
45                 pos_y += w_space;
46                 vsize_x = font_size;
47                 vsize_y = font_size;
48                 vsize_z = 0;
49                 drawstring(pos, ftos(nr+1), vsize, '1 1 0', sbar_alpha_fg, 0);
50
51         }
52         else
53         {
54                 // width = 300, height = 100
55                 const float w2_width = 300, w2_height = 100, w2_space = 10;
56                 const float w2_scale = 0.4;
57
58                 pos_x = vid_conwidth - (w2_width + w2_space) * w2_scale;
59                 pos_y = (w2_height + w2_space) * w2_scale * nr + w2_space;
60                 pos_z = 0;
61                 vsize_x = w2_width * w2_scale;
62                 vsize_y = w2_height * w2_scale;
63                 vsize_z = 0;
64                 
65                 drawpic(pos, strcat("gfx/inv_weapon", ftos(nr)), vsize, color, value * fade * sbar_alpha_fg, 0);
66         }
67 }
68 void Sbar_DrawXNum (vector pos, float num, float digits, float lettersize, vector rgb, float a, float dflags)
69 {
70         float l, i;
71         string str, tmp;
72         float minus;
73         vector vsize;
74
75         vsize_x = vsize_y = lettersize;
76         vsize_z = 0;
77
78         if(num < 0)
79         {
80                 minus = true;
81                 num = -num;
82                 pos_x -= lettersize;
83         } else
84                 minus = false;
85         
86         if(digits < 0)
87         {
88                 tmp = ftos(num);
89                 digits = -digits;
90                 str = strcat(substring("0000000000", 0, digits - strlen(tmp)), tmp);
91         } else
92                 str = ftos(num);
93         
94         l = strlen(str);
95
96         if(l > digits)
97         {
98                 str = substring(str, l-digits, 999);
99                 l = strlen(str);
100         } else if(l < digits)
101                 pos_x += (digits-l) * lettersize;
102
103         if(minus)
104         {
105                 drawpic(sbar + pos, "gfx/num_minus", vsize, rgb, a * sbar_alpha_fg, dflags);
106                 pos_x += lettersize;
107         }
108
109         for(i = 0; i < l; ++i)
110         {
111                 drawpic(sbar + pos, strcat("gfx/num_", substring(str, i, 1)), vsize, rgb, a * sbar_alpha_fg, dflags);
112                 pos_x += lettersize;
113         }
114 }
115
116 float Sbar_PlayerCmp(entity l, entity r)
117 {
118         if(teamplay)
119         {
120                 if(l.sb_team > r.sb_team)
121                         return true;
122                 else if(l.sb_team > r.sb_team)
123                         return false;
124                 if(gametype == GAME_CTF)
125                 {
126                         if(l.sb_caps > r.sb_caps)
127                                 return true;
128                         else if(l.sb_caps < r.sb_caps)
129                                 return false;
130                 }
131         }
132         if(l.sb_frags > r.sb_frags)
133                 return true;
134         else if(l.sb_frags < r.sb_frags)
135                 return false;
136         return (l.sb_player > r.sb_player);
137 }
138 float Sbar_TeamCmp(entity l, entity r)
139 {
140         if(gametype == GAME_CTF)
141         {
142                 if(l.sb_caps > r.sb_caps)
143                         return true;
144                 else if(l.sb_caps < r.sb_caps)
145                         return false;
146         }
147         if(l.sb_frags > r.sb_frags)
148                 return true;
149         else if(l.sb_frags < r.sb_frags)
150                 return false;
151         return (l.sb_player > r.sb_player);
152 }
153
154 void Sbar_SortFrags()
155 {
156         float i;
157         entity tmp;
158         entity t1, t2, t3, t4, ts;
159         
160         Sort_Remove(sortedPlayers);
161         sortedPlayers = Sort_New(Sbar_PlayerCmp);
162
163         numteams = 0;
164         if(teamplay)
165         {
166                 Sort_Remove(sortedTeams);
167         
168                 t1 = spawn();
169                 t2 = spawn();
170                 t3 = spawn();
171                 t4 = spawn();
172                 ts = spawn();
173         
174                 t1.sb_team = COLOR_TEAM1;
175                 t2.sb_team = COLOR_TEAM2;
176                 t3.sb_team = COLOR_TEAM3;
177                 t4.sb_team = COLOR_TEAM4;
178                 ts.sb_team = COLOR_SPECTATOR;
179
180                 t1.sb_player = t2.sb_player = t3.sb_player = t4.sb_player = ts.sb_player = 0;
181                 t1.sb_frags = t2.sb_frags = t3.sb_frags = t4.sb_frags = 0;
182                 t1.sb_caps = caps_team1;
183                 t2.sb_caps = caps_team2;
184                 sortedTeams = Sort_New(Sbar_TeamCmp);
185                 
186                 for(i = 0; i < maxclients; ++i)
187                 {
188                         if(strlen(getplayerkey(i, "name")) <= 0)
189                                 continue;
190                 
191                         tmp = spawn();
192                         tmp.sb_player = i;
193                         tmp.sb_frags = stof(getplayerkey(i, "frags"));
194                         tmp.sb_caps = stof(bufstr_get(databuf, DATABUF_CAPTURES + tmp.sb_player));
195                         
196                         if(tmp.sb_frags == -666)
197                                 tmp.sb_team = COLOR_SPECTATOR;
198                         else
199                                 tmp.sb_team = GetPlayerColor(i);
200
201                         switch(tmp.sb_team)
202                         {
203                         case COLOR_TEAM1: t1.sb_frags += tmp.sb_frags; t1.sb_player++; break;
204                         case COLOR_TEAM2: t2.sb_frags += tmp.sb_frags; t2.sb_player++; break;
205                         case COLOR_TEAM3: t3.sb_frags += tmp.sb_frags; t3.sb_player++; break;
206                         case COLOR_TEAM4: t4.sb_frags += tmp.sb_frags; t4.sb_player++; break;
207                         case COLOR_SPECTATOR: ts.sb_frags += tmp.sb_frags; ts.sb_player++; break;
208                         }
209
210                         if(i == player_localentnum-1)
211                                 myteam = tmp.sb_team;
212
213                         Sort_Add(sortedPlayers, tmp);
214                 }
215                 if(t1.sb_player) ++numteams;
216                 if(t2.sb_player) ++numteams;
217                 if(t3.sb_player) ++numteams;
218                 if(t4.sb_player) ++numteams;
219
220                 Sort_Add(sortedTeams, t1);
221                 Sort_Add(sortedTeams, t2);
222                 Sort_Add(sortedTeams, t3);
223                 Sort_Add(sortedTeams, t4);
224                 Sort_Add(sortedTeams, ts);
225
226         } else {
227                 for(i = 0; i < maxclients; ++i)
228                 {
229                         if(strlen(getplayerkey(i, "name")) <= 0)
230                                 continue;
231                 
232                         tmp = spawn();
233                         tmp.sb_player = i;
234                         tmp.sb_frags = stof(getplayerkey(i, "frags"));
235                         if(tmp.sb_frags == -666)
236                                 tmp.sb_team = COLOR_SPECTATOR;
237                         else
238                                 tmp.sb_team = COLOR_TEAM1;
239                         Sort_Add(sortedPlayers, tmp);
240                 }
241         }
242 }
243
244 void Cmd_Sbar_Help(float argc)
245 {
246         print("You can modify the scoreboard using the\n");
247         print("^3|---------------------------------------------------------------|\n");
248         print("^2sbar_columns^7 cvar and the ^2sbar_columns_set command.\n");
249         print("^2sbar_columns^7             specifies the default layout and\n");
250         print("^2sbar_columns_set^7         actually changes the layout.\n");
251         print("You can call ^2sbar_columns_set^7 with the new layout\n");
252         print("as parameters, or eithout parameters it will read the cvar.\n\n");
253         print("Usage:\n");
254         print("^2sbar_columns_set ^7filed1 field2 ...\n");
255         print("Fields which are not relevant to the current gametype\n");
256         print("won't be displayed\n\n");
257         print("The following field names are recognized (case INsensitive):\n");
258         print("^3name^7 or ^3nick^7             Name of a player\n");
259         print("^3caps^7 or ^3captures^7         Number of flags captured\n");
260         print("^3rets^7 or ^3returns^7          Number of flags returned\n");
261         print("^3frags^7 or ^3kills^7           Frags\n");
262         print("^3deaths^7 or ^3dths^7           Number of deaths\n");
263         print("^3kd^7 or ^3kdr^7 or ^3kdratio^7 or ^3k/d\n");
264         print("                         The kill-death ratio\n");
265         print("^3ping^7                     Ping time\n\n");
266         print("You can use a ^3|^7 to start the right-aligned fields.\n");
267         print("Example: ping name | caps rets frags k/d\n");
268         print("This will put the ping and the name on the left side.\n");
269         print("The captures, returns, frags and kill-death ratio will be\n");
270         print("rendered beginning on the right side.\n");
271
272 }
273
274 #define MIN_NAMELEN 24
275 #define MAX_NAMELEN 24
276
277 void Cmd_Sbar_SetFields(float argc)
278 {
279         float i;
280         string str;
281         float digit;
282
283         if(argc < 2)
284                 argc = tokenize(strcat("x ", cvar_string("sbar_columns")));
285         
286         argc = min(MAX_SBAR_FIELDS, argc);
287         sbar_num_fields = 0;
288         drawfont = FONT_USER+1;
289         digit = stringwidth("0123456789", FALSE) / 10;
290         for(i = 0; i < argc-1; ++i)
291         {
292                 str = argv(i+1);
293                 strunzone(sbar_title[i]);
294                 sbar_title[i] = strzone(str);
295                 sbar_size[i] = stringwidth(str, FALSE);
296                 str = strtolower(str);
297                 if(str == "ping") {
298                         sbar_field[i] = SBF_PING;
299                 } else if(str == "name" || str == "nick") {
300                         sbar_field[i] = SBF_NAME;
301                         sbar_size[i] = MIN_NAMELEN; // minimum size? any use?
302                 } else if(str == "caps" || str == "captures") {
303                         if(sbar_size[i] < 3*digit)
304                                 sbar_size[i] = 3*digit;
305                         sbar_field[i] = SBF_CAPS;
306                 } else if(str == "rets" || str == "returns") {
307                         if(sbar_size[i] < 3*digit)
308                                 sbar_size[i] = 3*digit;
309                         sbar_field[i] = SBF_RETS;
310                 } else if(str == "frags" || str == "kills") {
311                         if(sbar_size[i] < 5*digit)
312                                 sbar_size[i] = 5*digit;
313                         sbar_field[i] = SBF_FRAGS;
314                 } else if(str == "deaths" || str == "dths") {
315                         if(sbar_size[i] < 5*digit)
316                                 sbar_size[i] = 5*digit;
317                         sbar_field[i] = SBF_DEATHS;
318                 } else if(str == "kdratio") {
319                         sbar_field[i] = SBF_KDRATIO;
320                 } else if(str == "kdr" || str == "k/d") {
321                         sbar_field[i] = SBF_KDRATIO;
322                 } else if(str == "kd") {
323                         sbar_field[i] = SBF_KDRATIO;
324                 } else if(str == "|") {
325                         sbar_field[i] = SBF_SEPARATOR;
326                 } else {
327                         print(strcat("^1Error:^7 Unknown score field: '", str, "'\n"));
328                         --sbar_num_fields;
329                 }
330                 ++sbar_num_fields;
331         }
332         sbar_field[i] = SBF_END;
333 }
334
335 vector sbar_field_rgb;
336 string Sbar_GetField(entity pl, float field)
337 {
338         float tmp;
339         string str;
340         sbar_field_rgb = '1 1 1';
341         switch(field)
342         {
343         case SBF_PING:
344                 str = bufstr_get(databuf, DATABUF_PING + pl.sb_player);
345                 tmp = max(0, min(220, stof(str)-80)) / 220;
346                 sbar_field_rgb = '1 1 1' - '0 1 1'*tmp;
347                 return str;
348         case SBF_NAME: return getplayerkey(pl.sb_player, "name");
349         case SBF_CAPS: return ftos(pl.sb_caps);
350         case SBF_RETS: return bufstr_get(databuf, DATABUF_RETURNS + pl.sb_player);
351         case SBF_FRAGS: return ftos(pl.sb_frags);
352         case SBF_DEATHS: return bufstr_get(databuf, DATABUF_DEATHS + pl.sb_player);
353         case SBF_KDRATIO:
354                 tmp = stof(bufstr_get(databuf, DATABUF_DEATHS + pl.sb_player));
355                 if(tmp == 0) {
356                         sbar_field_rgb = '0 1 0';
357                         str = ftos(pl.sb_frags);
358                 } else if(pl.sb_frags <= 0) {
359                         sbar_field_rgb = '1 0 0';
360                         str = ftos(pl.sb_frags / tmp);
361                 } else
362                         str = ftos(pl.sb_frags / tmp);
363                 
364                 tmp = strstrofs(str, ".", 0);
365                 if(tmp > 0)
366                         str = substring(str, 0, tmp+2);
367                 return str;
368         }
369 }
370
371 float Sbar_IsFieldMasked(float field, float mask)
372 {
373         if(mask&1) // spectator
374                 return (field != SBF_NAME && field != SBF_PING);
375         if(gametype != GAME_CTF)
376                 return (field == SBF_CAPS || field == SBF_RETS);
377         return false;
378 }
379
380 // shamelessly stolen from menu QC :P
381 float textLengthUpToWidth(string theText, float maxWidth, float handleColors)
382 {
383         // STOP.
384         // The following function is SLOW.
385         // For your safety and for the protection of those around you...
386         // DO NOT CALL THIS AT HOME.
387         // No really, don't.
388         if(stringwidth(theText, handleColors) <= maxWidth)
389                 return strlen(theText); // yeah!
390
391         // binary search for right place to cut string
392         float left, right, middle; // this always works
393         left = 0;
394         right = strlen(theText); // this always fails
395         do
396         {
397                 middle = floor((left + right) / 2);
398                 if(stringwidth(substring(theText, 0, middle), handleColors) <= maxWidth)
399                         left = middle;
400                 else
401                         right = middle;
402         }
403         while(left < right - 1);
404
405         // NOTE: when color codes are involved, this binary search is,
406         // mathematically, BROKEN. However, it is obviously guaranteed to
407         // terminate, as the range still halves each time - but nevertheless, it is
408         // guaranteed that it finds ONE valid cutoff place (where "left" is in
409         // range, and "right" is outside).
410
411         return left;
412 }
413 string textShortenToWidth(string theText, float maxWidth, float handleColors)
414 {
415         if(stringwidth(theText, handleColors) <= maxWidth)
416                 return theText;
417         else
418                 return strcat(substring(theText, 0, textLengthUpToWidth(theText, maxWidth - stringwidth("...", handleColors), handleColors)), "...");
419 }
420
421 float xmin, xmax, ymin, ymax, sbwidth, sbheight;
422 void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self, float mask)
423 {
424         vector tmp;
425         string str, tempstr;
426         float i, field, len;
427
428         // Layout:
429         tmp_z = 0;
430         if(is_self)
431         {
432                 tmp_x = sbwidth;
433                 tmp_y = sbar_fontsize_y;
434                 drawfill(pos - '1 1', tmp + '2 2', '1 1 1', 0.3, DRAWFLAG_NORMAL);
435         }       
436         tmp_y = 0;
437         
438         for(i = 0; i < sbar_num_fields; ++i)
439         {
440                 field = sbar_field[i];
441                 if(field == SBF_SEPARATOR)
442                         break;
443                 if(Sbar_IsFieldMasked(field, mask))
444                         continue;
445
446                 str = Sbar_GetField(pl, field);
447
448                 if(field == SBF_NAME)
449                 {
450                         float realsize;
451                         float j;
452                         realsize = sbar_size[i];
453                         if(i+1 < sbar_num_fields)
454                                 if(sbar_field[i+1] == SBF_SEPARATOR)
455                                 {
456                                         realsize = (xmax - xmin) / sbar_fontsize_x;
457                                         print("remaining size: ", ftos(realsize), "\n");
458                                         for(j = 0; j < sbar_num_fields; ++j) if(j != i) if(sbar_field[j] != SBF_SEPARATOR)
459                                                 realsize -= sbar_size[j] + 1;
460                                         realsize += 1;
461                                         print("remaining size: ", ftos(realsize), "\n");
462                                 }
463                         str = textShortenToWidth(str, realsize, TRUE);
464                 }
465                 len = stringwidth(str, TRUE);
466                 
467                 if(sbar_size[i] < len)
468                         sbar_size[i] = len;
469
470                 pos_x += sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
471                 if(field == SBF_NAME) {
472                         tmp_x = sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
473                         drawcolorcodedstring(pos - tmp, str, sbar_fontsize, 1, DRAWFLAG_NORMAL);
474                 } else {
475                         tmp_x = len*sbar_fontsize_x + sbar_fontsize_x;
476                         drawstring(pos - tmp, str, sbar_fontsize, sbar_field_rgb, 1, DRAWFLAG_NORMAL);
477                 }
478         }
479         
480         if(sbar_field[i] == SBF_SEPARATOR)
481         {
482                 pos_x = xmax;
483                 for(i = sbar_num_fields-1; i > 0; --i)
484                 {
485                         field = sbar_field[i];
486                         if(field == SBF_SEPARATOR)
487                                 break;
488                         if(Sbar_IsFieldMasked(field, mask))
489                                 continue;
490                         
491                         str = Sbar_GetField(pl, field);
492
493                         if(field == SBF_NAME)
494                                 str = textShortenToWidth(str, sbar_size[i], TRUE);
495                         len = stringwidth(str, TRUE);
496
497                         if(sbar_size[i] < len)
498                                 sbar_size[i] = len;
499                         
500                         if(field == SBF_NAME) {
501                                 tmp_x = sbar_fontsize_x*len; // left or right aligned? let's put it right...
502                                 drawcolorcodedstring(pos - tmp, str, sbar_fontsize, 1, DRAWFLAG_NORMAL);
503                         } else {
504                                 tmp_x = sbar_fontsize_x*len; //strlen(str);
505                                 drawstring(pos - tmp, str, sbar_fontsize, sbar_field_rgb, 1, DRAWFLAG_NORMAL);
506                         }
507                         pos_x -= sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
508                 }
509         }
510 }
511
512 void Sbar_DrawScoreboard()
513 {
514         //float xmin, ymin, xmax, ymax;
515         vector rgb, pos, tmp, sbar_save;
516         entity pl, tm;
517         float specs, i;
518         float center_x;
519         string str;
520
521         sbar_fontsize = stov(cvar_string("sbar_fontsize"));
522         if(sbar_fontsize_x == 0)
523                 sbar_fontsize = '8 8 0';
524         if(sbar_fontsize_y == 0)
525                 sbar_fontsize_y = sbar_fontsize_x;
526         
527         xmin = vid_conwidth / 5;
528         ymin = 20;
529
530         xmax = vid_conwidth - xmin;
531         ymax = vid_conheight - 0.2*vid_conheight;
532
533         sbwidth = xmax - xmin;
534         sbheight = ymax - ymin;
535
536         center_x = xmin + 0.5*sbwidth;
537
538         //Sbar_UpdateFields();
539
540         // Initializes position
541         //pos_x = xmin;
542         pos_y = ymin;
543         pos_z = 0;
544
545         // Heading
546         drawfont = FONT_USER+1;
547         pos_x = center_x - stringwidth("Scoreboard", TRUE)*0.5*24;
548         drawstring(pos, "Scoreboard", '24 24', '1 1 1', 1, DRAWFLAG_NORMAL);
549         pos_x = xmin;
550         pos_y += 24 + 4;
551
552         // Titlebar background:
553         tmp_x = sbwidth;
554         tmp_y = sbar_fontsize_y;
555         drawfill(pos - '1 1', tmp + '2 2', '0.5 0.5 0.5', 0.5, DRAWFLAG_NORMAL);
556         
557         for(i = 0; i < sbar_num_fields; ++i)
558         {
559                 if(sbar_field[i] == SBF_SEPARATOR)
560                         break;
561                 drawstring(pos, sbar_title[i], sbar_fontsize, '1 1 1', 1, DRAWFLAG_NORMAL);
562                 pos_x += sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
563         }
564         
565         if(sbar_field[i] == SBF_SEPARATOR)
566         {
567                 pos_x = xmax + sbar_fontsize_x;
568                 tmp_y = tmp_z = 0;
569                 for(i = sbar_num_fields-1; i > 0; --i)
570                 {
571                         if(sbar_field[i] == SBF_SEPARATOR)
572                                 break;
573                         
574                         pos_x -= sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
575                         /**
576                          * FTEQCC BUG!
577                          * Using the following line will fuck it all up:
578                          **
579                          * tmp_x = sbar_size[i] - strlen(sbar_title[i])*8;
580                          */
581                         tmp_x = sbar_fontsize_x*sbar_size[i];
582                         tmp_x -= stringwidth(sbar_title[i], FALSE)*sbar_fontsize_x;
583                         drawstring(pos + tmp, sbar_title[i], sbar_fontsize, '1 1 1', 1, DRAWFLAG_NORMAL);
584                 }
585         }
586                 
587         pos_x = xmin;
588         pos_y += 1.5 * sbar_fontsize_y;
589
590         sbar_save = sbar;
591         sbar = '0 0 0';
592         
593         if(teamplay)
594         {
595                 for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next)
596                 {
597                         if(!tm.sb_player || tm.sb_team == COLOR_SPECTATOR) // no players in it?
598                                 continue;
599
600                         rgb = GetTeamRGB(tm.sb_team);
601
602                         pos_x = xmin - 4*24;
603                         if(gametype == GAME_CTF)
604                         {
605                                 if(tm.sb_team == COLOR_TEAM1)
606                                         Sbar_DrawXNum(pos, caps_team1, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
607                                 else if(tm.sb_team == COLOR_TEAM2)
608                                         Sbar_DrawXNum(pos, caps_team2, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
609                                 pos_x = xmin - 4*10;
610                                 Sbar_DrawXNum(pos + '0 24', tm.sb_frags, 4, 10, rgb, 1, DRAWFLAG_NORMAL);
611                                 pos_x = xmin;
612                         } else
613                                 Sbar_DrawXNum(pos, tm.sb_frags, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
614                         pos_x = xmin;
615
616                         // abuse specs as playerounter
617                         specs = 0;
618                         for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
619                         {
620                                 if(pl.sb_team == tm.sb_team)
621                                         ++specs;
622                         }
623
624                         if(specs < 2)
625                                 specs = 2;
626                         if(gametype == GAME_CTF && specs < 4)
627                                 specs = 4;
628                         
629                         tmp_x = sbwidth;
630                         tmp_y = 1.25 * sbar_fontsize_y * specs;
631                         drawfill(pos - '1 1', tmp + '2 0', rgb, 0.2, DRAWFLAG_NORMAL);
632                         
633                         for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
634                         {
635                                 if(pl.sb_team != tm.sb_team)
636                                         continue;
637                                 Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), 0);
638                                 pos_y += 1.25 * sbar_fontsize_y;
639                                 tmp_y -= 1.25 * sbar_fontsize_y;
640                         }
641                         pos_y += tmp_y + 1.5 * sbar_fontsize_y;
642                 }
643                 // rgb := tempvector :)
644                 rgb = pos + '0 1.5 0' * sbar_fontsize_y;
645                 pos_y += 3 * sbar_fontsize_y;
646                 specs = 0;
647                 for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
648                 {
649                         if(pl.sb_team != COLOR_SPECTATOR)
650                                 continue;
651                         //drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
652                         Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), 1);
653                         pos += '0 1.25 0' * sbar_fontsize_y;
654                         ++specs;
655                 }
656                         
657                 if(specs)
658                         drawstring(rgb, "Spectators", sbar_fontsize, '1 1 1', 1, 0);
659         }
660         sbar = sbar_save;
661 }
662
663 void Sbar_Score(float margin)
664 {
665         float timelimit, timeleft, minutes, seconds, distribution, myplace;
666         vector sbar_save, place;
667         entity tm, pl, me;
668         sbar_save = sbar;
669
670         sbar_y = vid_conheight - (32+12);
671         sbar_x -= margin;
672         
673         place = '-48 -12 0';
674         if(teamplay)
675         {
676                 // Layout:
677                 //
678                 //   team1 team3 team4
679                 //
680                 //         TEAM2
681                 //for(i = 0; i < 4; ++i)
682                 for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next)
683                 {
684                         if(tm.sb_team == COLOR_SPECTATOR || !tm.sb_player) // no players? don't display
685                                 continue;
686                         // -32*4 = -128
687                         if(tm.sb_team == myteam)
688                                 Sbar_DrawXNum('-128 0', tm.sb_frags, 4, 32, GetTeamRGB(tm.sb_team), 1, DRAWFLAG_NORMAL);
689                         else
690                         {
691                                 Sbar_DrawXNum(place, tm.sb_frags, 4, 12, GetTeamRGB(tm.sb_team), 1, DRAWFLAG_NORMAL);
692                                 place_x -= 4*12;
693                         }
694                 }
695         } else {
696                 // me vector := [team/connected frags id]
697                 myplace = 0;
698                 for(me = sortedPlayers.sort_next; me; me = me.sort_next)
699                 {
700                         if(me.sb_team != COLOR_SPECTATOR)
701                                 ++myplace;
702                         if(me.sb_player == player_localentnum - 1)
703                                 break;
704                 }
705                 pl = sortedPlayers.sort_next;
706                 if(pl == me)
707                         pl = pl.sort_next;
708                 
709                 if(pl && myplace != 1)
710                 {
711                         distribution = me.sb_frags - pl.sb_frags;
712                 } else if(pl) {
713                         distribution = me.sb_frags - pl.sb_frags;
714                 } else
715                         distribution = 0;
716                 
717                 if(myplace == 1)
718                         Sbar_DrawXNum('-36 -12', myplace, 3, 12, '1 1 1', 1, DRAWFLAG_NORMAL);
719                 else if(myplace == 2)
720                         Sbar_DrawXNum('-36 -12', myplace, 3, 12, '1 1 0', 1, DRAWFLAG_NORMAL);
721                 else
722                         Sbar_DrawXNum('-36 -12', myplace, 3, 12, '1 0 0', 1, DRAWFLAG_NORMAL);
723
724                 if(distribution >= 0)
725                 {
726                         Sbar_DrawXNum('-84 -12', distribution, 4, 12, ' 1 1 1', 1, DRAWFLAG_NORMAL);
727                         Sbar_DrawXNum('-128 0', me.sb_frags, 4, 32, '1 1 1', 1, DRAWFLAG_NORMAL);
728                 } else if(distribution >= -5)
729                 {
730                         Sbar_DrawXNum('-84 -12', distribution, 4, 12, ' 1 1 0', 1, DRAWFLAG_NORMAL);
731                         Sbar_DrawXNum('-128 0', me.sb_frags, 4, 32, '1 1 0', 1, DRAWFLAG_NORMAL);
732                 } else {
733                         Sbar_DrawXNum('-84 -12', distribution, 4, 12, ' 1 0 0', 1, DRAWFLAG_NORMAL);
734                         Sbar_DrawXNum('-128 0', me.sb_frags, 4, 32, '1 0 0', 1, DRAWFLAG_NORMAL);
735                 }
736         }
737         timelimit = getstatf(STAT_TIMELIMIT);
738         if(timelimit)
739         {
740                 timeleft = max(0, timelimit * 60 - time);
741                 minutes = floor(timeleft / 60);
742                 seconds = floor(timeleft - minutes*60);
743                 if(minutes >= 5)
744                 {
745                         Sbar_DrawXNum('-72 32', minutes, 3, 12, '1 1 1', 1, DRAWFLAG_NORMAL);
746                         drawpic(sbar + '-36 32', "gfx/num_colon", '12 12', '1 1 1', sbar_alpha_fg, 0);
747                         Sbar_DrawXNum('-24 32', seconds, -2, 12, '1 1 1', 1, DRAWFLAG_NORMAL);
748                 } else if(minutes >= 1)
749                 {
750                         Sbar_DrawXNum('-72 32', minutes, 3, 12, '1 1 0', 1, DRAWFLAG_NORMAL);
751                         drawpic(sbar + '-36 32', "gfx/num_colon", '12 12', '1 1 0', sbar_alpha_fg, 0);
752                         Sbar_DrawXNum('-24 32', seconds, -2, 12, '1 1 0', 1, DRAWFLAG_NORMAL);
753                 } else {
754                         Sbar_DrawXNum('-24 32', seconds, -2, 12, '1 0 0', 1, DRAWFLAG_NORMAL);
755                 }
756         } else {
757                 minutes = floor(time / 60);
758                 seconds = floor(time - minutes*60);
759                 Sbar_DrawXNum('-72 32', minutes, 3, 12, '1 1 1', 1, DRAWFLAG_NORMAL);
760                 drawpic(sbar + '-36 32', "gfx/num_colon", '12 12', '1 1 1', sbar_alpha_fg, 0);
761                 Sbar_DrawXNum('-24 32', seconds, -2, 12, '1 1 1', 1, DRAWFLAG_NORMAL);
762         }
763         sbar = sbar_save;
764 }
765
766 void Sbar_MiniscoreItem(vector pos, entity pl, float is_self)
767 {
768         float x;
769         pos_x += 72;
770         
771         if(teamplay)
772                 drawfill(pos + '0 1 0', '40 6 0', GetTeamRGB(pl.sb_team)*0.5, 1, DRAWFLAG_NORMAL);
773         else
774                 drawfill(pos + '0 1 0', '40 6 0', '0.5 0.5 0.5', 0.5, DRAWFLAG_NORMAL);
775         x = pos_x;
776         pos_x += 5*8;
777         pos_x -= stringwidth(ftos(pl.sb_frags), FALSE)*8;
778         drawstring(pos, ftos(pl.sb_frags), '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
779         pos_x = x;
780         if(is_self)
781         {
782                 pos_x += 48;
783                 drawstring(pos, "\x0D", '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
784                 pos_x += 8;
785         } else
786                 pos_x += 56;
787         drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
788 }
789
790 void Sbar_MiniscoreTeamItem(vector pos, float color, float frags, float is_self)
791 {
792         float x;
793         pos_x += 72;
794         
795         if(teamplay)
796                 drawfill(pos + '0 1 0', '40 6 0', GetTeamRGB(color)*0.5, 1, DRAWFLAG_NORMAL);
797         else
798                 drawfill(pos + '0 1 0', '40 6 0', '0.5 0.5 0.5', 0.5, DRAWFLAG_NORMAL);
799         x = pos_x;
800         pos_x += 5*8;
801         pos_x -= stringwidth(ftos(frags), FALSE)*8;
802         drawstring(pos, ftos(frags), '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
803         pos_x = x;
804         if(is_self)
805         {
806                 pos_x += 48;
807                 drawstring(pos, "\x0D", '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
808                 pos_x += 8;
809         } else
810                 pos_x += 56;
811         drawstring(pos, GetTeamName(color), '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
812 }
813
814 void Sbar_MiniDeathmatchOverlay(vector pos)
815 {
816         float numlines, up, down;
817         entity me, tm, pl;
818         float miniscoreboard_size;
819         miniscoreboard_size = cvar("sbar_miniscoreboard_size");
820         
821         if(miniscoreboard_size == 0)
822                 return;
823         pos_y = vid_conheight - 8;
824         
825         if(miniscoreboard_size < 0)
826                 numlines = (vid_conheight - sbar_y + 7) / 8;
827         else
828                 numlines = miniscoreboard_size;
829
830         // give up if there isn't enough room
831         if(pos_x >= vid_conwidth || pos_y >= vid_conheight || numlines < 1)
832                 return;
833
834         // me vector := [team/connected frags id]
835         for(me = sortedPlayers.sort_next; me; me = me.sort_next)
836         {
837                 if(me.sb_player == player_localentnum - 1)
838                         break;
839         }
840
841         if(teamplay)
842                 numlines -= numteams;
843
844         // figure out how many players above and below we can show
845         up = floor(numlines/2);
846         down = up;
847         if((up + down) > numlines)
848                 down = numlines - up;
849
850         // render bottom-up
851         for(pl = me.sort_next; pl && down > 0; pl = pl.sort_next)
852         {
853                 if(pl.sb_team == COLOR_SPECTATOR)
854                         continue;
855                 Sbar_MiniscoreItem(pos, pl, false);
856                 pos_y -= 9;
857                 --down;
858         }
859         Sbar_MiniscoreItem(pos, me, true);
860         pos_y -= 9;
861         up += down; // if there weren't enough lines below... add them
862         for(pl = me.sort_prev; pl != sortedPlayers && up > 0; pl = pl.sort_prev)
863         {
864                 if(pl.sb_team == COLOR_SPECTATOR)
865                         continue;
866                 Sbar_MiniscoreItem(pos, pl, false);
867                 pos_y -= 9;
868                 --up;
869         }
870
871         if(teamplay)
872         {
873                 for(tm = sortedTeams.sort_next; tm.sort_next; tm = tm.sort_next);
874                 for(; tm != sortedTeams; tm = tm.sort_prev)
875                 {
876                         if(!tm.sb_player || tm.sb_team == COLOR_SPECTATOR) // no players?
877                                 continue;
878                         Sbar_MiniscoreTeamItem(pos, tm.sb_team, tm.sb_frags, (tm.sb_team == me.sb_team));
879                         pos_y -= 9;
880                 }
881         }
882 }
883
884 void Sbar_Draw (void)
885 {
886         float i;
887         float x, fade;
888         float stat_items;
889
890         Sbar_SortFrags();
891
892         sb_lines = 24;
893         
894         if (sb_showscores)
895                 Sbar_DrawScoreboard();
896         else if (intermission == 1)
897         {
898                 Sbar_DrawScoreboard();
899                 return;
900         }
901         else if (intermission == 2)
902                 Sbar_FinaleOverlay();
903         else
904         {
905                 if (sb_showscores || (getstati(STAT_HEALTH) <= 0 && cvar("cl_deathscoreboard")))
906                 {
907                         sbar_x = (vid_conwidth - 640.0)*0.5;
908                         sbar_y = vid_conheight - 47;
909                         //Sbar_DrawAlphaPic (sbar_x, sbar_y, sb_scorebar, sbar_alpha_bg.value);
910                         //drawpic('0 0', "gfx/scorebar", '0 0 0', '1 1 1', cvar("sbar_alpha_bg"), 0);
911                         Sbar_DrawScoreboard ();
912                 }
913                 else
914                 {
915                         if (sb_lines && sbar_hudselector == 1)
916                         {
917                                 stat_items = getstati(STAT_ITEMS);
918
919                                 sbar_x = (vid_conwidth - 320.0)*0.5;
920                                 sbar_y = vid_conheight - 24.0 - 16.0;
921                                 sbar_z = 0;
922                         
923                                 fade = 3.2 - 2 * (time - weapontime);
924                                 fade = bound(0.7, fade, 1);
925
926                                 x = 1.0;
927                                 for(i = 0; i < 8; ++i)
928                                 {
929                                         if(stat_items & x)
930                                         {
931                                                 Sbar_DrawWeapon(i+1, fade, (i + 2 == activeweapon));
932                                         }
933                                         x *= 2;
934                                 }
935                                 x *= 2*2*2*2;
936                                 if(stat_items & x)
937                                 {
938                                         Sbar_DrawWeapon(0, fade, (activeweapon == 1));
939                                 }
940
941                                 // armor
942                                 x = getstati(STAT_ARMOR);
943                                 if (x > 0)
944                                 {
945                                         // "gfx/sb_armor"
946                                         //Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
947                                         drawpic(sbar + '72 0', "gfx/sb_armor", '24 24 0', '1 1 1', sbar_alpha_fg, 0);
948                                         if(x > 200)
949                                                 Sbar_DrawXNum('0 0', x, 3, 24, '0 1 0', 1, 0);
950                                         else if(x > 100)
951                                                 Sbar_DrawXNum('0 0', x, 3, 24, '0.2 1 0', 1, 0);
952                                         else if(x > 50)
953                                                 Sbar_DrawXNum('0 0', x, 3, 24, '0.6 0.7 0.8', 1, 0);
954                                         else if(x > 25)
955                                                 Sbar_DrawXNum('0 0', x, 3, 24, '1 1 0.2', 1, 0);
956                                         else
957                                                 Sbar_DrawXNum('0 0', x, 3, 24, '0.7 0 0', 1, 0);
958                                 }
959
960                                 // health
961                                 x = getstati(STAT_HEALTH);
962                                 if (x != 0)
963                                 {
964                                         // "gfx/sb_health"
965                                         //Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
966                                         drawpic(sbar + '184 0', "gfx/sb_health", '24 24 0', '1 1 1', sbar_alpha_fg, 0);
967                                         if(x > 200)
968                                                 Sbar_DrawXNum('112 0', x, 3, 24, '0 1 0', 1, 0);
969                                         else if(x > 100)
970                                                 Sbar_DrawXNum('112 0', x, 3, 24, '0.2 1 0', 1, 0);
971                                         else if(x > 50)
972                                                 Sbar_DrawXNum('112 0', x, 3, 24, '0.6 0.7 0.8', 1, 0);
973                                         else if(x > 25)
974                                                 Sbar_DrawXNum('112 0', x, 3, 24, '1 1 0.2', 1, 0);
975                                         else
976                                                 Sbar_DrawXNum('112 0', x, 3, 24, '0.7 0 0', 1, 0);
977                                 }
978
979                                 // ammo
980                                 x = getstati(STAT_AMMO);
981                                 if ((stat_items & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || x != 0)
982                                 {
983                                         if (stat_items & NEX_IT_SHELLS)
984                                                 drawpic(sbar + '296 0', "gfx/sb_shells", '24 24 0', '1 1 1', sbar_alpha_fg, 0);
985                                         else if (stat_items & NEX_IT_BULLETS)
986                                                 drawpic(sbar + '296 0', "gfx/sb_bullets", '24 24 0', '1 1 1', sbar_alpha_fg, 0);
987                                         else if (stat_items & NEX_IT_ROCKETS)
988                                                 drawpic(sbar + '296 0', "gfx/sb_rocket", '24 24 0', '1 1 1', sbar_alpha_fg, 0);
989                                         else if (stat_items & NEX_IT_CELLS)
990                                                 drawpic(sbar + '296 0', "gfx/sb_cells", '24 24 0', '1 1 1', sbar_alpha_fg, 0);
991                                         if(x > 10)
992                                                 Sbar_DrawXNum('224 0', x, 3, 24, '0.6 0.7 0.8', 1, 0);
993                                         else
994                                                 Sbar_DrawXNum('224 0', x, 3, 24, '0.7 0 0', 1, 0);
995                                 }
996
997                                 if (sbar_x + 320 + 160 <= vid_conwidth)
998                                         Sbar_MiniDeathmatchOverlay(sbar + '320 0');
999                                 if (sbar_x > 0)
1000                                         Sbar_Score(16);
1001                                 // The margin can be at most 8 to support 640x480 console size:
1002                                 //   320 + 2 * (144 + 16) = 640
1003                         }
1004                         else if (sb_lines)
1005                         {
1006                         
1007                                 stat_items = getstati(STAT_ITEMS);
1008                         
1009                                 sbar_x = (vid_conwidth - 640.0)*0.5;
1010                                 sbar_y = vid_conheight - 47;
1011                                 sbar_z = 0;
1012
1013                                 fade = 3 - 2 * (time - weapontime);
1014
1015                                 x = 1.0;
1016                                 for(i = 0; i < 8; ++i)
1017                                 {
1018                                         if(stat_items & x)
1019                                         {
1020                                                 Sbar_DrawWeapon(i+1, fade, (i + 2 == activeweapon));
1021                                         }
1022                                         x *= 2;
1023                                 }
1024                                 x *= 2*2*2*2;
1025                                 if(stat_items & x)
1026                                 {
1027                                         Sbar_DrawWeapon(0, fade, (activeweapon == 1));
1028                                 }
1029
1030                                 if (sb_lines > 24)
1031                                         drawpic(sbar, "gfx/sbar", '0 0 0', '1 1 1', sbar_alpha_fg, 0);
1032                                 else
1033                                         drawpic(sbar, "gfx/sbar_minimal", '0 0 0', '1 1 1', sbar_alpha_fg, 0);
1034
1035                                 // armor
1036                                 // (340-3*24) = 268
1037                                 Sbar_DrawXNum('268 12', getstati(STAT_ARMOR), 3, 24, '0.6 0.7 0.8', 1, 0);
1038
1039                                 // health
1040                                 // (154-3*24) = 82
1041                                 x = getstati(STAT_HEALTH);
1042                                 if(x > 100)
1043                                         Sbar_DrawXNum('82 12', x, 3, 24, '1 1 1', 1, 0);
1044                                 else if(x <= 25 && time - floor(time) > 0.5)
1045                                         Sbar_DrawXNum('82 12', x, 3, 24, '0.7 0 0', 1, 0);
1046                                 else
1047                                         Sbar_DrawXNum('81 12', x, 3, 24, '0.6 0.7 0.8', 1, 0);
1048
1049                                 // AK dont draw ammo for the laser
1050                                 x = getstati(STAT_AMMO);
1051                                 if(activeweapon != 12)
1052                                 {
1053                                         // (519-3*24) = 447
1054                                         if (stat_items & NEX_IT_SHELLS)
1055                                                 drawpic(sbar + '519 0', "gfx/sb_shells", '0 0 0', '1 1 1', sbar_alpha_fg, 0);
1056                                         else if (stat_items & NEX_IT_BULLETS)
1057                                                 drawpic(sbar + '519 0', "gfx/sb_bullets", '0 0 0', '1 1 1', sbar_alpha_fg, 0);
1058                                         else if (stat_items & NEX_IT_ROCKETS)
1059                                                 drawpic(sbar + '519 0', "gfx/sb_rocket", '0 0 0', '1 1 1', sbar_alpha_fg, 0);
1060                                         else if (stat_items & NEX_IT_CELLS)
1061                                                 drawpic(sbar + '519 0', "gfx/sb_cells", '0 0 0', '1 1 1', sbar_alpha_fg, 0);
1062                                         if(x > 10)
1063                                                 Sbar_DrawXNum('447 12', x, 3, 24, '0.6 0.7 0.8', 1, 0);
1064                                         else
1065                                                 Sbar_DrawXNum('447 12', x, 3, 24, '0.7 0 0', 1, 0);
1066                                 }
1067
1068                                 if (sb_lines > 24)
1069                                         drawpic(sbar, "gfx/sbar_overlay", '0 0 0', '1 1 1', 1, DRAWFLAG_MODULATE);
1070
1071                                 if (sbar_x + 600 + 160 <= vid_conwidth)
1072                                         Sbar_MiniDeathmatchOverlay (sbar + '600 0');
1073
1074                                 if (sbar_x > 0)
1075                                         Sbar_Score(-16);
1076                                 // Because:
1077                                 //   Mini scoreboard uses 12*4 per other team, that is, 144
1078                                 //   pixels when there are four teams...
1079                                 //   Nexuiz by default sets vid_conwidth to 800... makes
1080                                 //   sbar_x == 80...
1081                                 //   so we need to shift it by 64 pixels to the right to fit
1082                                 //   BUT: then it overlaps with the image that gets drawn
1083                                 //   for viewsize 100! Therefore, just account for 3 teams,
1084                                 //   that is, 96 pixels mini scoreboard size, needing 16 pixels
1085                                 //   to the right!
1086                         }
1087                 
1088                 
1089                         if(gametype == GAME_KEYHUNT)
1090                         {
1091                                 CSQC_kh_hud();
1092                         } else if(gametype == GAME_CTF)
1093                         {
1094                                 CSQC_ctf_hud();
1095                         }
1096                 }
1097         }
1098 }
1099
1100 void CSQC_ctf_hud(void)
1101 {
1102         // cvar("sbar_flagstatus_right") move the flag icons right
1103         // cvar("sbar_flagstatus_pos") pixel position of the nexuiz flagstatus icons
1104         float redflag, blueflag;
1105         float stat_items;
1106         vector pos;
1107         
1108         stat_items = getstati(STAT_ITEMS);
1109         redflag = (stat_items/32768) & 3;
1110         blueflag = (stat_items/131072) & 3;
1111
1112         /**
1113          * FTEQCC BUG!
1114          * For some reason now not even THAT works there...
1115          * Maybe the minus' precedence screws it up? The last one there, maybe I should use brackets
1116          **
1117          * pos_x = (cvar("sbar_flagstatus_right")) ? vid_conwidth - 10 - sbar_x - 64 : 10 - sbar_x;
1118          ** Should try those later:
1119          * pos_x = (cvar("sbar_flagstatus_right")) ? (vid_conwidth - 10 - sbar_x - 64) : (10 - sbar_x);
1120          * pos_x = ( (cvar("sbar_flagstatus_right")) ? vid_conwidth - 10 - 64 : 10 ) - sbar_x;
1121          */
1122         
1123         if(cvar("sbar_flagstatus_right"))
1124                 pos_x = vid_conwidth - 10 - sbar_x - 64;
1125         else
1126                 pos_x = 10 - sbar_x;
1127         
1128         pos_z = 0;
1129
1130         if(sbar_hudselector == 1)
1131                 pos_y = (vid_conheight - sbar_y) - cvar("sbar_flagstatus_pos") - 64;
1132         else
1133                 pos_y = -117;
1134
1135         pos += sbar;
1136
1137         switch(redflag)
1138         {
1139         case 1: drawpic(pos, "gfx/sb_flag_red_taken", '0 0 0', '1 1 1', 1, DRAWFLAG_NORMAL); break;
1140         case 2: drawpic(pos, "gfx/sb_flag_red_lost", '0 0 0', '1 1 1', 1, DRAWFLAG_NORMAL); break;
1141         case 3: drawpic(pos, "gfx/sb_flag_red_carrying", '0 0 0', '1 1 1', 1, DRAWFLAG_NORMAL); break;
1142         }
1143
1144         pos_y -= 64;
1145         
1146         switch(blueflag)
1147         {
1148         case 1: drawpic(pos, "gfx/sb_flag_blue_taken", '0 0 0', '1 1 1', 1, 0); break;
1149         case 2: drawpic(pos, "gfx/sb_flag_blue_lost", '0 0 0', '1 1 1', 1, 0); break;
1150         case 3: drawpic(pos, "gfx/sb_flag_blue_carrying", '0 0 0', '1 1 1', 1, 0); break;
1151         }
1152 }