Merge branch 'terencehill/spectate_player' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / powerups.qc
1 #include "powerups.qh"
2
3 #include <client/autocvars.qh>
4 #include <client/defs.qh>
5 #include <client/miscfunctions.qh>
6 #include <common/items/_mod.qh>
7
8 // Powerups (#2)
9
10 // Powerup item fields (reusing existing fields)
11 .string message;  // Human readable name
12 .string netname;  // Icon name
13 .vector colormod; // Color
14 .float count;     // Time left
15 .float lifetime;  // Maximum time
16
17 entity powerupItems;
18 int powerupItemsCount;
19
20 void resetPowerupItems()
21 {
22         entity item;
23         for(item = powerupItems; item; item = item.chain)
24                 item.count = 0;
25
26         powerupItemsCount = 0;
27 }
28
29 void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime)
30 {
31         if(!powerupItems)
32                 powerupItems = spawn();
33
34         entity item;
35         for(item = powerupItems; item.count; item = item.chain)
36                 if(!item.chain)
37                         item.chain = spawn();
38
39         item.message  = name;
40         item.netname  = icon;
41         item.colormod = color;
42         item.count    = currentTime;
43         item.lifetime = lifeTime;
44
45         ++powerupItemsCount;
46 }
47
48 int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
49 {
50         TC(int, align); TC(int, column); TC(int, row); TC(int, columns); TC(int, rows); TC(bool, isVertical);
51         if(align < 2)
52                 return align;
53
54         bool isTop    =  isVertical && rows > 1 && row == 0;
55         bool isBottom =  isVertical && rows > 1 && row == rows-1;
56         bool isLeft   = !isVertical && columns > 1 && column == 0;
57         bool isRight  = !isVertical && columns > 1 && column == columns-1;
58
59         if(isTop    || isLeft)  return (align == 2) ? 1 : 0;
60         if(isBottom || isRight) return (align == 2) ? 0 : 1;
61
62         return 2;
63 }
64
65 void HUD_Powerups()
66 {
67         int allItems = STAT(ITEMS);
68         int allBuffs = STAT(BUFFS);
69         float strengthTime, shieldTime, superTime;
70
71         // Initialize items
72         if(!autocvar__hud_configure)
73         {
74                 if((!autocvar_hud_panel_powerups) || (spectatee_status == -1))
75                         return;
76                 if(STAT(HEALTH) <= 0 && autocvar_hud_panel_powerups_hide_ondeath)
77                         return;
78                 //if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
79
80                 strengthTime = bound(0, STAT(STRENGTH_FINISHED) - time, 99);
81                 shieldTime = bound(0, STAT(INVINCIBLE_FINISHED) - time, 99);
82                 superTime = bound(0, STAT(SUPERWEAPONS_FINISHED) - time, 99);
83
84                 if(allItems & IT_UNLIMITED_SUPERWEAPONS)
85                         superTime = 99;
86
87                 // Prevent stuff to show up on mismatch that will be fixed next frame
88                 if(!(allItems & IT_SUPERWEAPON))
89                         superTime = 0;
90         }
91         else
92         {
93                 strengthTime = 15;
94                 shieldTime = 27;
95                 superTime = 13;
96                 allBuffs = 0;
97         }
98
99         // Add items to linked list
100         resetPowerupItems();
101
102         if(strengthTime)
103                 addPowerupItem("Strength", "strength", autocvar_hud_progressbar_strength_color, strengthTime, 30);
104         if(shieldTime)
105                 addPowerupItem("Shield", "shield", autocvar_hud_progressbar_shield_color, shieldTime, 30);
106         if(superTime && !(allItems & IT_UNLIMITED_SUPERWEAPONS))
107                 addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
108
109         MUTATOR_CALLHOOK(HUD_Powerups_add);
110
111         if(!powerupItemsCount)
112                 return;
113
114         // Draw panel background
115         HUD_Panel_LoadCvars();
116
117         if (autocvar_hud_panel_powerups_dynamichud)
118                 HUD_Scale_Enable();
119         else
120                 HUD_Scale_Disable();
121         HUD_Panel_DrawBg();
122
123         // Set drawing area
124         vector pos = panel_pos;
125         vector size = panel_size;
126         bool isVertical = size.y > size.x;
127
128         if(panel_bg_padding)
129         {
130                 pos += '1 1 0' * panel_bg_padding;
131                 size -= '2 2 0' * panel_bg_padding;
132         }
133
134         // Find best partitioning of the drawing area
135         const float DESIRED_ASPECT = 6;
136         float aspect = 0, a;
137         int columns = 0, c;
138         int rows = 0, r;
139         int i = 1;
140
141         do
142         {
143                 c = floor(powerupItemsCount / i);
144                 r = ceil(powerupItemsCount / c);
145                 a = isVertical ? (size.y/r) / (size.x/c) : (size.x/c) / (size.y/r);
146
147                 if(i == 1 || fabs(DESIRED_ASPECT - a) < fabs(DESIRED_ASPECT - aspect))
148                 {
149                         aspect = a;
150                         columns = c;
151                         rows = r;
152                 }
153         }
154         while(++i <= powerupItemsCount);
155
156         // Prevent single items from getting too wide
157         if(powerupItemsCount == 1 && aspect > DESIRED_ASPECT)
158         {
159                 if(isVertical)
160                 {
161                         size.y *= 0.5;
162                         pos.y += size.y * 0.5;
163                 }
164                 else
165                 {
166                         size.x *= 0.5;
167                         pos.x += size.x * 0.5;
168                 }
169         }
170
171         // Draw items from linked list
172         vector itemPos = pos;
173         vector itemSize = vec2(size.x / columns, size.y / rows);
174         vector textColor = '1 1 1';
175
176         int fullSeconds = 0;
177         int align = 0;
178         int column = 0;
179         int row = 0;
180
181         draw_beginBoldFont();
182         for(entity item = powerupItems; item.count; item = item.chain)
183         {
184                 itemPos = vec2(pos.x + column * itemSize.x, pos.y + row * itemSize.y);
185
186                 // Draw progressbar
187                 if(autocvar_hud_panel_powerups_progressbar)
188                 {
189                         align = getPowerupItemAlign(autocvar_hud_panel_powerups_baralign, column, row, columns, rows, isVertical);
190                         HUD_Panel_DrawProgressBar(itemPos, itemSize, "progressbar", item.count / item.lifetime, isVertical, align, item.colormod, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
191                 }
192
193                 // Draw icon and text
194                 if(autocvar_hud_panel_powerups_text)
195                 {
196                         align = getPowerupItemAlign(autocvar_hud_panel_powerups_iconalign, column, row, columns, rows, isVertical);
197                         fullSeconds = ceil(item.count);
198                         textColor = '0.6 0.6 0.6' + (item.colormod * 0.4);
199
200                         if(item.count > 1)
201                                 DrawNumIcon(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha);
202                         if(item.count <= 5)
203                                 DrawNumIcon_expanding(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha, bound(0, (fullSeconds - item.count) / 0.5, 1));
204                 }
205
206                 // Determine next section
207                 if(isVertical)
208                 {
209                         if(++column >= columns)
210                         {
211                                 column = 0;
212                                 ++row;
213                         }
214                 }
215                 else
216                 {
217                         if(++row >= rows)
218                         {
219                                 row = 0;
220                                 ++column;
221                         }
222                 }
223         }
224         draw_endBoldFont();
225 }