]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/hud/panel/weapons.qc
Transifex autosync
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / weapons.qc
1 #include "weapons.qh"
2
3 #include <client/autocvars.qh>
4 #include <client/draw.qh>
5 #include <client/view.qh>
6 #include <common/wepent.qh>
7
8 // Weapons (#0)
9
10 void HUD_Weapons_Export(int fh)
11 {
12         HUD_Write_Cvar("hud_panel_weapons_accuracy");
13         HUD_Write_Cvar("hud_panel_weapons_label");
14         HUD_Write_Cvar("hud_panel_weapons_label_scale");
15         HUD_Write_Cvar("hud_panel_weapons_complainbubble");
16         HUD_Write_Cvar("hud_panel_weapons_complainbubble_padding");
17         HUD_Write_Cvar("hud_panel_weapons_complainbubble_time");
18         HUD_Write_Cvar("hud_panel_weapons_complainbubble_fadetime");
19         HUD_Write_Cvar("hud_panel_weapons_complainbubble_color_outofammo");
20         HUD_Write_Cvar("hud_panel_weapons_complainbubble_color_donthave");
21         HUD_Write_Cvar("hud_panel_weapons_complainbubble_color_unavailable");
22         HUD_Write_Cvar("hud_panel_weapons_ammo");
23         HUD_Write_Cvar("hud_panel_weapons_ammo_color");
24         HUD_Write_Cvar("hud_panel_weapons_ammo_alpha");
25         HUD_Write_Cvar("hud_panel_weapons_aspect");
26         HUD_Write_Cvar("hud_panel_weapons_timeout");
27         HUD_Write_Cvar("hud_panel_weapons_timeout_effect");
28         HUD_Write_Cvar("hud_panel_weapons_timeout_fadebgmin");
29         HUD_Write_Cvar("hud_panel_weapons_timeout_fadefgmin");
30         HUD_Write_Cvar("hud_panel_weapons_timeout_speed_in");
31         HUD_Write_Cvar("hud_panel_weapons_timeout_speed_out");
32         HUD_Write_Cvar("hud_panel_weapons_onlyowned");
33         HUD_Write_Cvar("hud_panel_weapons_noncurrent_alpha");
34         HUD_Write_Cvar("hud_panel_weapons_noncurrent_scale");
35         HUD_Write_Cvar("hud_panel_weapons_selection_radius");
36         HUD_Write_Cvar("hud_panel_weapons_selection_speed");
37 }
38
39 void Accuracy_LoadLevels()
40 {
41         if(autocvar_accuracy_color_levels != acc_color_levels)
42         {
43                 strcpy(acc_color_levels, autocvar_accuracy_color_levels);
44                 acc_levels = tokenize_console(acc_color_levels);
45                 if(acc_levels > MAX_ACCURACY_LEVELS)
46                         acc_levels = MAX_ACCURACY_LEVELS;
47                 if(acc_levels < 2)
48                         LOG_INFO("Warning: accuracy_color_levels must contain at least 2 values");
49
50                 int i;
51                 for(i = 0; i < acc_levels; ++i)
52                         acc_lev[i] = stof(argv(i)) / 100.0;
53         }
54 }
55
56 void Accuracy_LoadColors()
57 {
58         if(time > acc_col_loadtime)
59         if(acc_levels >= 2)
60         {
61                 int i;
62                 for(i = 0; i < acc_levels; ++i)
63                         acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
64                 acc_col_loadtime = time + 2;
65         }
66 }
67
68 vector Accuracy_GetColor(float accuracy)
69 {
70         float factor;
71         vector color;
72         if(acc_levels < 2)
73                 return '0 0 0'; // return black, can't determine the right color
74
75         // find the max level lower than acc
76         int j = acc_levels-1;
77         while(j && accuracy < acc_lev[j])
78                 --j;
79
80         // inject color j+1 in color j, how much depending on how much accuracy is higher than level j
81         factor = (accuracy - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]);
82         color = acc_col[j];
83         color = color + factor * (acc_col[j+1] - color);
84         return color;
85 }
86
87 entity weaponorder[REGISTRY_MAX(Weapons)];
88 void weaponorder_swap(int i, int j, entity pass)
89 {
90         TC(int, i); TC(int, j);
91         entity h = weaponorder[i];
92         weaponorder[i] = weaponorder[j];
93         weaponorder[j] = h;
94 }
95
96 string weaponorder_cmp_str;
97 int weaponorder_cmp(int i, int j, entity pass)
98 {
99         TC(int, i); TC(int, j);
100         int ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].m_id), 0);
101         int aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].m_id), 0);
102         return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
103 }
104
105 #define HUD_WEAPONS_GET_FULL_LAYOUT() MACRO_BEGIN \
106         int nHidden = 0; \
107         FOREACH(Weapons, it != WEP_Null, { \
108                 if (weapons_stat & WepSet_FromWeapon(it)) continue; \
109                 if (it.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)) nHidden += 1; \
110         }); \
111         vector table_size = HUD_GetTableSize_BestItemAR((REGISTRY_COUNT(Weapons) - 1) - nHidden, panel_size, aspect); \
112         columns = table_size.x; \
113         rows = table_size.y; \
114         weapon_size.x = panel_size.x / columns; \
115         weapon_size.y = panel_size.y / rows; \
116 MACRO_END
117
118 string cl_weaponpriority_old;
119 bool weapons_orderbyimpulse_old;
120 void HUD_Weapons()
121 {
122         // declarations
123         WepSet weapons_stat = WepSet_GetFromStat();
124         int i;
125         float f, a;
126         float screen_ar;
127         vector center = '0 0 0';
128         int weapon_count, weapon_id;
129         int row, column, rows = 0, columns = 0;
130         bool vertical_order = true;
131         float aspect = autocvar_hud_panel_weapons_aspect;
132
133         float timeout = autocvar_hud_panel_weapons_timeout;
134         float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
135         float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
136
137         vector barsize = '0 0 0', baroffset = '0 0 0';
138         vector ammo_color = '1 0 1';
139         float ammo_alpha = 1;
140
141         float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
142         float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
143
144         bool infinite_ammo = (STAT(ITEMS) & IT_UNLIMITED_AMMO);
145
146         vector weapon_pos, weapon_size = '0 0 0';
147         vector color;
148
149         entity panel_switchweapon = NULL;
150
151         // check to see if we want to continue
152         if(hud != HUD_NORMAL) return;
153
154         if(!autocvar__hud_configure)
155         {
156                 if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
157                         return;
158                 if(STAT(HEALTH) <= 0 && autocvar_hud_panel_weapons_hide_ondeath)
159                         return;
160                 if(timeout && time >= weapontime + timeout + timeout_effect_length)
161                 if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
162                 {
163                         weaponprevtime = time;
164                         return;
165                 }
166         }
167
168         // update generic hud functions
169         HUD_Panel_LoadCvars();
170
171         if(cl_weaponpriority_old != autocvar_cl_weaponpriority || weapons_orderbyimpulse_old != autocvar_hud_panel_weapons_orderbyimpulse || weaponorder[0] == NULL)
172         {
173                 weapons_orderbyimpulse_old = autocvar_hud_panel_weapons_orderbyimpulse;
174                 strcpy(cl_weaponpriority_old, autocvar_cl_weaponpriority);
175                 string weporder = W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(cl_weaponpriority_old));
176                 if(autocvar_hud_panel_weapons_orderbyimpulse)
177                 {
178                         weporder = W_FixWeaponOrder_BuildImpulseList(weporder);
179                 }
180
181                 weaponorder_cmp_str = strcat(" ", weporder, " ");
182
183                 int weapon_cnt = 0;
184                 FOREACH(Weapons, it != WEP_Null && it.impulse >= 0, weaponorder[weapon_cnt++] = it);
185                 for(i = weapon_cnt; i < REGISTRY_MAX(Weapons); ++i)
186                         weaponorder[i] = NULL;
187                 heapsort(weapon_cnt, weaponorder_swap, weaponorder_cmp, NULL);
188
189                 weaponorder_cmp_str = string_null;
190         }
191
192         if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
193                 complain_weapon = NULL;
194
195         entity wepent = viewmodels[0]; // TODO: unhardcode
196
197         if (wepent.switchweapon == WEP_Null)
198                 panel_switchweapon = NULL;
199         else if (!panel_switchweapon)
200                 panel_switchweapon = wepent.switchweapon;
201
202         if(autocvar__hud_configure)
203         {
204                 if(!weapons_stat)
205                 {
206                         int j = 0;
207                         FOREACH(Weapons, it != WEP_Null && it.impulse >= 0 && (it.impulse % 3 != 0) && j < 6, {
208                                 if(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_SPECIALATTACK))
209                                 {
210                                         if(!panel_switchweapon || j < 4)
211                                                 panel_switchweapon = it;
212                                         weapons_stat |= it.m_wepset;
213                                         ++j;
214                                 }
215                         });
216                 }
217
218                 #if 0
219                 /// debug code
220                 if(cvar("wep_add"))
221                 {
222                         int j;
223                         int nHidden = 0;
224                         FOREACH(Weapons, it != WEP_Null, {
225                                 if (it.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1;
226                         });
227                         weapons_stat = '0 0 0';
228                         float countw = 1 + floor((floor(time * cvar("wep_add"))) % ((REGISTRY_COUNT(Weapons) - 1) - nHidden));
229                         for(i = 0, j = 0; i <= (REGISTRY_COUNT(Weapons) - 1) && j < countw; ++i)
230                         {
231                                 if(weaponorder[i].spawnflags & WEP_FLAG_MUTATORBLOCKED)
232                                         continue;
233                                 weapons_stat |= weaponorder[i].m_wepset;
234                                 ++j;
235                         }
236                 }
237                 #endif
238         }
239
240         // determine which weapons are going to be shown
241         if (autocvar_hud_panel_weapons_onlyowned)
242         {
243                 if(autocvar__hud_configure)
244                 {
245                         if(hud_configure_menu_open != 2)
246                                 HUD_Panel_DrawBg(); // also draw the bg of the entire panel
247                 }
248
249                 // do we own this weapon?
250                 weapon_count = 0;
251                 if (autocvar_hud_panel_weapons_onlyowned >= 2) // only current
252                 {
253                         for (i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
254                                 if (weaponorder[i] == panel_switchweapon || weaponorder[i] == complain_weapon)
255                                         ++weapon_count;
256                 }
257                 else
258                 {
259                         for (i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
260                                 if ((weapons_stat & WepSet_FromWeapon(weaponorder[i])) || weaponorder[i] == complain_weapon)
261                                         ++weapon_count;
262                 }
263
264                 // might as well commit suicide now, no reason to live ;)
265                 if (weapon_count == 0)
266                         return;
267
268                 vector old_panel_size = panel_size;
269                 panel_size -= '2 2 0' * panel_bg_padding;
270
271                 HUD_WEAPONS_GET_FULL_LAYOUT();
272
273                 // NOTE: although weapons should aways look the same even if onlyowned is enabled,
274                 // we enlarge them a bit when possible to better match the desired aspect ratio
275                 if(panel_size.x / panel_size.y < aspect)
276                 {
277                         // maximum number of rows that allows to display items with the desired aspect ratio
278                         int max_rows = floor(panel_size.y / (weapon_size.x / aspect));
279                         columns = min(columns, ceil(weapon_count / max_rows));
280                         rows = ceil(weapon_count / columns);
281                         weapon_size.y = min(panel_size.y / rows, weapon_size.x / aspect);
282                         weapon_size.x = min(panel_size.x / columns, aspect * weapon_size.y);
283                         vertical_order = false;
284                 }
285                 else
286                 {
287                         int max_columns = floor(panel_size.x / (weapon_size.y * aspect));
288                         rows = min(rows, ceil(weapon_count / max_columns));
289                         columns = ceil(weapon_count / rows);
290                         weapon_size.x = min(panel_size.x / columns, aspect * weapon_size.y);
291                         weapon_size.y = min(panel_size.y / rows, weapon_size.x / aspect);
292                         vertical_order = true;
293                 }
294
295                 // reduce size of the panel
296                 panel_size.x = columns * weapon_size.x;
297                 panel_size.y = rows * weapon_size.y;
298                 panel_size += '2 2 0' * panel_bg_padding;
299
300                 // center the resized panel, or snap it to the screen edge when close enough
301                 if(panel_pos.x > vid_conwidth * 0.001)
302                 {
303                         if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
304                                 panel_pos.x += old_panel_size.x - panel_size.x;
305                         else
306                                 panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
307                 }
308                 else if(old_panel_size.x > vid_conwidth * 0.999)
309                         panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
310
311                 if(panel_pos.y > vid_conheight * 0.001)
312                 {
313                         if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
314                                 panel_pos.y += old_panel_size.y - panel_size.y;
315                         else
316                                 panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
317                 }
318                 else if(old_panel_size.y > vid_conheight * 0.999)
319                         panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
320         }
321         else
322                 weapon_count = (REGISTRY_COUNT(Weapons) - 1);
323
324         // animation for fading in/out the panel respectively when not in use
325         if(!autocvar__hud_configure)
326         {
327                 if (timeout && time >= weapontime + timeout) // apply timeout effect if needed
328                 {
329                         f = bound(0, (time - (weapontime + timeout)) / timeout_effect_length, 1);
330
331                         // fade the panel alpha
332                         if(autocvar_hud_panel_weapons_timeout_effect == 1)
333                         {
334                                 panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * f + (1 - f));
335                                 panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * f + (1 - f));
336                         }
337                         else if(autocvar_hud_panel_weapons_timeout_effect == 3)
338                         {
339                                 panel_bg_alpha *= (1 - f);
340                                 panel_fg_alpha *= (1 - f);
341                         }
342
343                         // move the panel off the screen
344                         if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
345                         {
346                                 f *= f; // for a cooler movement
347                                 center.x = panel_pos.x + panel_size.x/2;
348                                 center.y = panel_pos.y + panel_size.y/2;
349                                 screen_ar = vid_conwidth/vid_conheight;
350                                 if (center.x/center.y < screen_ar) //bottom left
351                                 {
352                                         if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
353                                                 panel_pos.y += f * (vid_conheight - panel_pos.y);
354                                         else //left
355                                                 panel_pos.x -= f * (panel_pos.x + panel_size.x);
356                                 }
357                                 else //top right
358                                 {
359                                         if ((vid_conwidth - center.x)/center.y < screen_ar) //right
360                                                 panel_pos.x += f * (vid_conwidth - panel_pos.x);
361                                         else //top
362                                                 panel_pos.y -= f * (panel_pos.y + panel_size.y);
363                                 }
364                                 if(f == 1)
365                                         center.x = -1; // mark the panel as off screen
366                         }
367                         weaponprevtime = time - (1 - f) * timein_effect_length;
368                 }
369                 else if (timeout && time < weaponprevtime + timein_effect_length) // apply timein effect if needed
370                 {
371                         f = bound(0, (time - weaponprevtime) / timein_effect_length, 1);
372
373                         // fade the panel alpha
374                         if(autocvar_hud_panel_weapons_timeout_effect == 1)
375                         {
376                                 panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * (1 - f) + f);
377                                 panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * (1 - f) + f);
378                         }
379                         else if(autocvar_hud_panel_weapons_timeout_effect == 3)
380                         {
381                                 panel_bg_alpha *= (f);
382                                 panel_fg_alpha *= (f);
383                         }
384
385                         // move the panel back on screen
386                         if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
387                         {
388                                 f *= f; // for a cooler movement
389                                 f = 1 - f;
390                                 center.x = panel_pos.x + panel_size.x/2;
391                                 center.y = panel_pos.y + panel_size.y/2;
392                                 screen_ar = vid_conwidth/vid_conheight;
393                                 if (center.x/center.y < screen_ar) //bottom left
394                                 {
395                                         if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
396                                                 panel_pos.y += f * (vid_conheight - panel_pos.y);
397                                         else //left
398                                                 panel_pos.x -= f * (panel_pos.x + panel_size.x);
399                                 }
400                                 else //top right
401                                 {
402                                         if ((vid_conwidth - center.x)/center.y < screen_ar) //right
403                                                 panel_pos.x += f * (vid_conwidth - panel_pos.x);
404                                         else //top
405                                                 panel_pos.y -= f * (panel_pos.y + panel_size.y);
406                                 }
407                         }
408                 }
409         }
410
411         // draw the background, then change the virtual size of it to better fit other items inside
412         if (autocvar_hud_panel_weapons_dynamichud)
413                 HUD_Scale_Enable();
414         else
415                 HUD_Scale_Disable();
416         HUD_Panel_DrawBg();
417
418         if(center.x == -1)
419                 return; // panel has gone off screen
420
421         if(panel_bg_padding)
422         {
423                 panel_pos += '1 1 0' * panel_bg_padding;
424                 panel_size -= '2 2 0' * panel_bg_padding;
425         }
426
427         // after the sizing and animations are done, update the other values
428
429         if(!rows) // if rows is > 0 onlyowned code has already updated these vars
430         {
431                 HUD_WEAPONS_GET_FULL_LAYOUT();
432                 vertical_order = (panel_size.x / panel_size.y >= aspect);
433         }
434
435         // calculate position/size for visual bar displaying ammount of ammo status
436         if (!infinite_ammo && autocvar_hud_panel_weapons_ammo)
437         {
438                 ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
439                 ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
440
441                 if(weapon_size.x/weapon_size.y > aspect)
442                 {
443                         barsize.x = aspect * weapon_size.y;
444                         barsize.y = weapon_size.y;
445                         baroffset.x = (weapon_size.x - barsize.x) / 2;
446                 }
447                 else
448                 {
449                         barsize.y = 1/aspect * weapon_size.x;
450                         barsize.x = weapon_size.x;
451                         baroffset.y = (weapon_size.y - barsize.y) / 2;
452                 }
453         }
454         if(autocvar_hud_panel_weapons_accuracy)
455                 Accuracy_LoadColors();
456
457         // draw items
458         row = column = 0;
459         vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
460         vector noncurrent_size = weapon_size * bound(0.01, autocvar_hud_panel_weapons_noncurrent_scale, 1);
461         float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
462         static vector weapon_pos_current = '-1 0 0';
463         if(weapon_pos_current.x == -1)
464                 weapon_pos_current = panel_pos;
465
466         float switch_speed;
467         if(autocvar_hud_panel_weapons_selection_speed <= 0 || autocvar__hud_configure)
468                 switch_speed = 999;
469         else
470                 switch_speed = frametime * autocvar_hud_panel_weapons_selection_speed;
471         vector radius_size = weapon_size * (autocvar_hud_panel_weapons_selection_radius + 1);
472
473         // draw background behind currently selected weapon
474         // do it earlier to make sure bg is drawn behind every weapon icons while it's moving
475         if(panel_switchweapon)
476                 drawpic_aspect_skin(weapon_pos_current, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
477
478         for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
479         {
480                 // retrieve information about the current weapon to be drawn
481                 entity it = weaponorder[i];
482                 weapon_id = it.impulse;
483
484                 // skip if this weapon doesn't exist
485                 if(!it || weapon_id < 0) { continue; }
486
487                 // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
488                 if (autocvar_hud_panel_weapons_onlyowned)
489                 {
490                         if (autocvar_hud_panel_weapons_onlyowned >= 2) // only current
491                         {
492                                 if (!(it == panel_switchweapon || it == complain_weapon))
493                                         continue;
494                         }
495                         else
496                         {
497                                 if (!((weapons_stat & WepSet_FromWeapon(it)) || (it == complain_weapon)))
498                                         continue;
499                         }
500                 }
501                 else
502                 {
503                         if (it.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)
504                                 && !(weapons_stat & WepSet_FromWeapon(it)))
505                         {
506                                 continue;
507                         }
508                 }
509
510                 // figure out the drawing position of weapon
511                 weapon_pos = panel_pos + vec2(column * weapon_size.x, row * weapon_size.y);
512
513                 // update position of the currently selected weapon
514                 if(it == panel_switchweapon)
515                 {
516                         if(weapon_pos_current.y > weapon_pos.y)
517                                 weapon_pos_current.y = max(weapon_pos.y, weapon_pos_current.y - switch_speed * (weapon_pos_current.y - weapon_pos.y));
518                         else if(weapon_pos_current.y < weapon_pos.y)
519                                 weapon_pos_current.y = min(weapon_pos.y, weapon_pos_current.y + switch_speed * (weapon_pos.y - weapon_pos_current.y));
520                         if(weapon_pos_current.x > weapon_pos.x)
521                                 weapon_pos_current.x = max(weapon_pos.x, weapon_pos_current.x - switch_speed * (weapon_pos_current.x - weapon_pos.x));
522                         else if(weapon_pos_current.x < weapon_pos.x)
523                                 weapon_pos_current.x = min(weapon_pos.x, weapon_pos_current.x + switch_speed * (weapon_pos.x - weapon_pos_current.x));
524                 }
525
526                 // draw the weapon accuracy
527                 if(autocvar_hud_panel_weapons_accuracy)
528                 {
529                         float panel_weapon_accuracy = weapon_accuracy[it.m_id-WEP_FIRST];
530                         if(panel_weapon_accuracy >= 0)
531                         {
532                                 color = Accuracy_GetColor(panel_weapon_accuracy);
533                                 drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
534                         }
535                 }
536
537                 vector weapon_size_real = noncurrent_size;
538                 float weapon_alpha_real = noncurrent_alpha;
539                 float radius_factor_x = 1 - bound(0, fabs(weapon_pos.x - weapon_pos_current.x) / radius_size.x, 1);
540                 float radius_factor_y = 1 - bound(0, fabs(weapon_pos.y - weapon_pos_current.y) / radius_size.y, 1);
541                 if(radius_factor_x || radius_factor_y)
542                 {
543                         weapon_size_real.x += (weapon_size.x - noncurrent_size.x) * radius_factor_x;
544                         weapon_size_real.y += (weapon_size.y - noncurrent_size.y) * radius_factor_y;
545                         weapon_alpha_real += (panel_fg_alpha - noncurrent_alpha) * min(radius_factor_x, radius_factor_y);
546                 }
547
548                 vector weapon_pos_real = weapon_pos;
549                 weapon_pos_real.x = weapon_pos.x + (weapon_size.x - weapon_size_real.x) / 2;
550                 weapon_pos_real.y = weapon_pos.y + (weapon_size.y - weapon_size_real.y) / 2;
551
552                 // drawing all the weapon items
553                 if(weapons_stat & WepSet_FromWeapon(it))
554                 {
555                         // draw the weapon image
556                         drawpic_aspect_skin(weapon_pos_real, it.model2, weapon_size_real, '1 1 1', weapon_alpha_real, DRAWFLAG_NORMAL);
557
558                         // draw weapon label string
559                         switch(autocvar_hud_panel_weapons_label)
560                         {
561                                 case 1: // weapon number
562                                         drawstring(weapon_pos, ftos(weapon_id), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
563                                         break;
564
565                                 case 2: // bind
566                                         drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
567                                         break;
568
569                                 case 3: // weapon name
570                                         drawstring(weapon_pos, strtolower(it.m_name), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
571                                         break;
572
573                                 default: // nothing
574                                         break;
575                         }
576
577                         // draw ammo status bar
578                         if(!infinite_ammo && autocvar_hud_panel_weapons_ammo && (it.ammo_type != RES_NONE))
579                         {
580                                 float ammo_full;
581                                 a = getstati(GetAmmoStat(it.ammo_type)); // how much ammo do we have?
582
583                                 if(a > 0)
584                                 {
585                                         switch (it.ammo_type)
586                                         {
587                                                 case RES_SHELLS:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
588                                                 case RES_BULLETS: ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
589                                                 case RES_ROCKETS: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
590                                                 case RES_CELLS:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
591                                                 case RES_PLASMA:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
592                                                 case RES_FUEL:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
593                                                 default: ammo_full = 60;
594                                         }
595
596                                         drawsetcliparea(
597                                                 weapon_pos.x + baroffset.x,
598                                                 weapon_pos.y + baroffset.y,
599                                                 barsize.x * bound(0, a/ammo_full, 1),
600                                                 barsize.y
601                                         );
602
603                                         drawpic_aspect_skin(
604                                                 weapon_pos,
605                                                 "weapon_ammo",
606                                                 weapon_size,
607                                                 ammo_color,
608                                                 ammo_alpha,
609                                                 DRAWFLAG_NORMAL
610                                         );
611
612                                         drawresetcliparea();
613                                 }
614                         }
615                 }
616                 else // draw a "ghost weapon icon" if you don't have the weapon
617                 {
618                         drawpic_aspect_skin(weapon_pos_real, it.model2, weapon_size_real, '0.2 0.2 0.2', weapon_alpha_real * 0.5, DRAWFLAG_NORMAL);
619                 }
620
621                 // draw the complain message
622                 if(it == complain_weapon)
623                 {
624                         if(fadetime)
625                                 a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
626                         else
627                                 a = ((complain_weapon_time + when > time) ? 1 : 0);
628
629                         string s;
630                         if(complain_weapon_type == 0) {
631                                 s = _("Out of ammo");
632                                 color = stov(autocvar_hud_panel_weapons_complainbubble_color_outofammo);
633                         }
634                         else if(complain_weapon_type == 1) {
635                                 s = _("Don't have");
636                                 color = stov(autocvar_hud_panel_weapons_complainbubble_color_donthave);
637                         }
638                         else {
639                                 s = _("Unavailable");
640                                 color = stov(autocvar_hud_panel_weapons_complainbubble_color_unavailable);
641                         }
642                         float padding = autocvar_hud_panel_weapons_complainbubble_padding;
643                         drawpic_aspect_skin(weapon_pos + '1 1 0' * padding, "weapon_complainbubble", weapon_size - '2 2 0' * padding, color, a * panel_fg_alpha, DRAWFLAG_NORMAL);
644                         drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
645                 }
646
647                 #if 0
648                 /// debug code
649                 if(!autocvar_hud_panel_weapons_onlyowned)
650                 {
651                         drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
652                         drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
653                 }
654                 #endif
655
656                 // continue with new position for the next weapon
657                 if(vertical_order)
658                 {
659                         ++column;
660                         if(column >= columns)
661                         {
662                                 column = 0;
663                                 ++row;
664                         }
665                 }
666                 else
667                 {
668                         ++row;
669                         if(row >= rows)
670                         {
671                                 row = 0;
672                                 ++column;
673                         }
674                 }
675         }
676 }