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