]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/itemstime.qc
3fd47c61ade0c220886b3480646b82b72c2969a8
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / itemstime.qc
1 REGISTER_MUTATOR(itemstime, true);
2
3 #ifdef SVQC
4 void IT_Write(entity e, int i, float f) {
5     if (!IS_REAL_CLIENT(e)) return;
6     msg_entity = e;
7     WriteByte(MSG_ONE, SVC_TEMPENTITY);
8     WriteMutator(MSG_ONE, itemstime);
9     WriteByte(MSG_ONE, i);
10     WriteFloat(MSG_ONE, f);
11 }
12 #endif
13
14 #ifdef CSQC
15 const float ITEMSTIME_MAXITEMS = 10;
16 float ItemsTime_time[ITEMSTIME_MAXITEMS];
17 float ItemsTime_availableTime[ITEMSTIME_MAXITEMS];
18 MUTATOR_HOOKFUNCTION(itemstime, CSQC_Parse_TempEntity) {
19     if (MUTATOR_RETURNVALUE) return false;
20     if (!ReadMutatorEquals(mutator_argv_int_0, itemstime)) return false;
21     int i = ReadByte();
22     float f = ReadFloat();
23     ItemsTime_time[i] = f;
24     return true;
25 }
26 #endif
27
28 #ifdef SVQC
29 float it_armor_large_time;
30 float it_health_mega_time;
31 float it_invisible_time;
32 float it_speed_time;
33 float it_extralife_time;
34 float it_strength_time;
35 float it_shield_time;
36 float it_fuelregen_time;
37 float it_jetpack_time;
38 float it_superweapons_time;
39
40 void Item_ItemsTime_Init()
41 {
42     it_armor_large_time = -1;
43     it_health_mega_time = -1;
44     it_invisible_time = -1;
45     it_speed_time = -1;
46     it_extralife_time = -1;
47     it_strength_time = -1;
48     it_shield_time = -1;
49     it_fuelregen_time = -1;
50     it_jetpack_time = -1;
51     it_superweapons_time = -1;
52 }
53
54 STATIC_INIT(ItemsTime_Init) {
55     // items time
56     Item_ItemsTime_Init();
57 }
58
59 void Item_ItemsTime_ResetTimes()
60 {
61     it_armor_large_time  = (it_armor_large_time  == -1) ? -1 : 0;
62     it_health_mega_time  = (it_health_mega_time  == -1) ? -1 : 0;
63     it_invisible_time    = (it_invisible_time    == -1) ? -1 : 0;
64     it_speed_time        = (it_speed_time        == -1) ? -1 : 0;
65     it_extralife_time    = (it_extralife_time    == -1) ? -1 : 0;
66     it_strength_time     = (it_strength_time     == -1) ? -1 : 0;
67     it_shield_time       = (it_shield_time       == -1) ? -1 : 0;
68     it_fuelregen_time    = (it_fuelregen_time    == -1) ? -1 : 0;
69     it_jetpack_time      = (it_jetpack_time      == -1) ? -1 : 0;
70     it_superweapons_time = (it_superweapons_time == -1) ? -1 : 0;
71 }
72
73 void Item_ItemsTime_ResetTimesForPlayer(entity e)
74 {
75     IT_Write(e, item_armor_large_time , (it_armor_large_time  == -1) ? -1 : 0);
76     IT_Write(e, item_health_mega_time , (it_health_mega_time  == -1) ? -1 : 0);
77     IT_Write(e, item_invisible_time   , (it_invisible_time    == -1) ? -1 : 0);
78     IT_Write(e, item_speed_time       , (it_speed_time        == -1) ? -1 : 0);
79     IT_Write(e, item_extralife_time   , (it_extralife_time    == -1) ? -1 : 0);
80     IT_Write(e, item_strength_time    , (it_strength_time     == -1) ? -1 : 0);
81     IT_Write(e, item_shield_time      , (it_shield_time       == -1) ? -1 : 0);
82     IT_Write(e, item_fuelregen_time   , (it_fuelregen_time    == -1) ? -1 : 0);
83     IT_Write(e, item_jetpack_time     , (it_jetpack_time      == -1) ? -1 : 0);
84     IT_Write(e, item_superweapons_time, (it_superweapons_time == -1) ? -1 : 0);
85 }
86
87 void Item_ItemsTime_SetTimesForPlayer(entity e)
88 {
89     IT_Write(e, item_armor_large_time , it_armor_large_time );
90     IT_Write(e, item_health_mega_time , it_health_mega_time );
91     IT_Write(e, item_invisible_time   , it_invisible_time   );
92     IT_Write(e, item_speed_time       , it_speed_time       );
93     IT_Write(e, item_extralife_time   , it_extralife_time   );
94     IT_Write(e, item_strength_time    , it_strength_time    );
95     IT_Write(e, item_shield_time      , it_shield_time      );
96     IT_Write(e, item_fuelregen_time   , it_fuelregen_time   );
97     IT_Write(e, item_jetpack_time     , it_jetpack_time     );
98     IT_Write(e, item_superweapons_time, it_superweapons_time);
99 }
100
101 void Item_ItemsTime_SetTime(entity e, float t)
102 {
103     if (!autocvar_sv_itemstime)
104         return;
105
106     if (g_instagib)
107     {
108         switch (e.items)
109         {
110             case IT_STRENGTH://"item-invis"
111                 it_invisible_time = t;
112                 break;
113             case IT_NAILS://"item-extralife"
114                 it_extralife_time = t;
115                 break;
116             case IT_INVINCIBLE://"item-speed"
117                 it_speed_time = t;
118                 break;
119         }
120     }
121     else
122     {
123         switch (e.items)
124         {
125             case ITEM_HealthMega.m_itemid:
126                 // if (e.itemdef == ITEM_HealthMega) // e.items == IT_HEALTH unequivocally identifies it
127                     it_health_mega_time = t;
128                 break;
129             case ITEM_ArmorMega.m_itemid:
130                 if (e.itemdef == ITEM_ArmorMega) // e.items == IT_ARMOR doesn't unequivocally identifies it
131                     it_armor_large_time = t;
132                 break;
133             case IT_STRENGTH://"item-strength"
134                 it_strength_time = t;
135                 break;
136             case IT_INVINCIBLE://"item-shield"
137                 it_shield_time = t;
138                 break;
139             default:
140                 if (e.weapons & WEPSET_SUPERWEAPONS)
141                     it_superweapons_time = t;
142         }
143     }
144     switch (e.items)
145     {
146         case IT_FUEL_REGEN://"item-fuelregen"
147             it_fuelregen_time = t;
148             break;
149         case IT_JETPACK://"item-jetpack"
150             it_jetpack_time = t;
151             break;
152     }
153 }
154
155 void Item_ItemsTime_SetTimesForAllPlayers()
156 {
157     entity e;
158     FOR_EACH_REALCLIENT(e) if (warmup_stage || !IS_PLAYER(e))
159         Item_ItemsTime_SetTimesForPlayer(e);
160 }
161
162 float Item_ItemsTime_UpdateTime(entity e, float t)
163 {
164     bool isavailable = (t == 0);
165     if (e.weapons & WEPSET_SUPERWEAPONS)
166     {
167         for (entity head = world; (head = nextent(head)); )
168         {
169             if (clienttype(head) != CLIENTTYPE_NOTACLIENT || !(head.weapons & WEPSET_SUPERWEAPONS) || head.classname == "weapon_info")
170                 continue;
171             if (e == head)
172                 continue;
173
174             if (head.scheduledrespawntime <= time)
175                 isavailable = true;
176             else if (t == 0 || head.scheduledrespawntime < t)
177                 t = head.scheduledrespawntime;
178         }
179     }
180     else
181     {
182         for (entity head = world; (head = nextent(head)); )
183         {
184             if (head.itemdef != e.itemdef)
185                 continue;
186             if (e == head)
187                 continue;
188
189             if (head.scheduledrespawntime <= time)
190                 isavailable = true;
191             else if (t == 0 || head.scheduledrespawntime < t)
192                 t = head.scheduledrespawntime;
193         }
194     }
195     if (isavailable)
196         t = -t; // let know the client there's another available item
197     return t;
198 }
199
200 MUTATOR_HOOKFUNCTION(itemstime, reset_map_global) {
201     Item_ItemsTime_ResetTimes();
202 }
203
204 MUTATOR_HOOKFUNCTION(itemstime, MakePlayerObserver) {
205     Item_ItemsTime_SetTimesForPlayer(self);
206 }
207
208 MUTATOR_HOOKFUNCTION(itemstime, PlayerSpawn) {
209     if (warmup_stage) return;
210     Item_ItemsTime_ResetTimesForPlayer(self);
211 }
212
213 #endif
214
215 #ifdef CSQC
216
217 string GetItemsTimePicture(float i)
218 {
219     switch(i)
220     {
221         case 0: return "item_large_armor";
222         case 1: return "item_mega_health";
223         case 2: return "strength";
224         case 3: return "shield";
225         case 4: return "item_mega_health";
226         case 5: return "strength";
227         case 6: return "shield";
228         case 7: return "fuelregen";
229         case 8: return "jetpack";
230         case 9: return "superweapons";
231         default: return "";
232     }
233 }
234
235 void DrawItemsTimeItem(vector myPos, vector mySize, float ar, float itemcode, float item_time, bool item_available, float item_availableTime)
236 {
237     float t = 0;
238     vector color = '0 0 0';
239     float picalpha;
240
241     if(autocvar_hud_panel_itemstime_hidespawned == 2)
242         picalpha = 1;
243     else if(item_available)
244     {
245         float BLINK_FACTOR = 0.15;
246         float BLINK_BASE = 0.85;
247         float BLINK_FREQ = 5;
248         picalpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
249     }
250     else
251         picalpha = 0.5;
252     t = floor(item_time - time + 0.999);
253     if(t < 5)
254         color = '0.7 0 0';
255     else if(t < 10)
256         color = '0.7 0.7 0';
257     else
258         color = '1 1 1';
259
260     vector picpos, numpos;
261     if(autocvar_hud_panel_itemstime_iconalign)
262     {
263         numpos = myPos;
264         picpos = myPos + eX * (ar - 1) * mySize_y;
265     }
266     else
267     {
268         numpos = myPos + eX * mySize_y;
269         picpos = myPos;
270     }
271
272     if(t > 0 && autocvar_hud_panel_itemstime_progressbar)
273     {
274         vector p_pos, p_size;
275         if(autocvar_hud_panel_itemstime_progressbar_reduced)
276         {
277             p_pos = numpos;
278             p_size = eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y;
279         }
280         else
281         {
282             p_pos = myPos;
283             p_size = mySize;
284         }
285         HUD_Panel_DrawProgressBar(p_pos, p_size, autocvar_hud_panel_itemstime_progressbar_name, t/autocvar_hud_panel_itemstime_progressbar_maxtime, 0, autocvar_hud_panel_itemstime_iconalign, color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
286     }
287
288     if(t > 0 && autocvar_hud_panel_itemstime_text)
289         drawstring_aspect(numpos, ftos(t), eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
290     else
291         picpos.x = myPos.x + mySize.x / 2 - mySize.y / 2;
292     if(item_availableTime)
293         drawpic_aspect_skin_expanding(picpos, GetItemsTimePicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL, item_availableTime);
294     drawpic_aspect_skin(picpos, GetItemsTimePicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
295 }
296
297 void HUD_ItemsTime()
298 {
299     if(!autocvar__hud_configure)
300     {
301         if(!(
302             (autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
303         ||      (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage))
304             )) { return; }
305     }
306     else
307     {
308         // do not show here mutator-dependent items
309         ItemsTime_time[0] = time + 0;
310         ItemsTime_time[1] = time + 8;
311         ItemsTime_time[2] = -1; // mutator-dependent
312         ItemsTime_time[3] = -1; // mutator-dependent
313         ItemsTime_time[4] = -1; // mutator-dependent
314         ItemsTime_time[5] = time + 0;
315         ItemsTime_time[6] = time + 4;
316         ItemsTime_time[7] = time + 49;
317         ItemsTime_time[8] = -1;
318         ItemsTime_time[9] = time + 28;
319     }
320
321     float i;
322     float count = 0;
323     if(autocvar_hud_panel_itemstime_hidespawned == 1)
324         for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
325             count += (ItemsTime_time[i] > time || -ItemsTime_time[i] > time);
326     else if(autocvar_hud_panel_itemstime_hidespawned == 2)
327         for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
328             count += (ItemsTime_time[i] > time);
329     else
330         for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
331             count += (ItemsTime_time[i] != -1);
332     if (count == 0)
333         return;
334
335     HUD_Panel_UpdateCvars();
336
337     vector pos, mySize;
338     pos = panel_pos;
339     mySize = panel_size;
340
341     if(panel_bg_padding)
342     {
343         pos += '1 1 0' * panel_bg_padding;
344         mySize -= '2 2 0' * panel_bg_padding;
345     }
346
347     float rows, columns;
348     float ar = max(2, autocvar_hud_panel_itemstime_ratio) + 1;
349     rows = HUD_GetRowCount(count, mySize, ar);
350     columns = ceil(count/rows);
351
352     vector itemstime_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
353
354     vector offset = '0 0 0';
355     float newSize;
356     if(autocvar_hud_panel_itemstime_dynamicsize)
357     {
358         if(autocvar__hud_configure)
359         if(menu_enabled != 2)
360             HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
361
362         // reduce panel to avoid spacing items
363         if(itemstime_size.x / itemstime_size.y < ar)
364         {
365             newSize = rows * itemstime_size.x / ar;
366             pos.y += (mySize.y - newSize) / 2;
367             mySize.y = newSize;
368             itemstime_size.y = mySize.y / rows;
369         }
370         else
371         {
372             newSize = columns * itemstime_size.y * ar;
373             pos.x += (mySize.x - newSize) / 2;
374             mySize.x = newSize;
375             itemstime_size.x = mySize.x / columns;
376         }
377         panel_pos = pos - '1 1 0' * panel_bg_padding;
378         panel_size = mySize + '2 2 0' * panel_bg_padding;
379     }
380     else
381     {
382         if(itemstime_size.x/itemstime_size.y > ar)
383         {
384             newSize = ar * itemstime_size.y;
385             offset.x = itemstime_size.x - newSize;
386             pos.x += offset.x/2;
387             itemstime_size.x = newSize;
388         }
389         else
390         {
391             newSize = 1/ar * itemstime_size.x;
392             offset.y = itemstime_size.y - newSize;
393             pos.y += offset.y/2;
394             itemstime_size.y = newSize;
395         }
396     }
397
398     HUD_Panel_DrawBg(1);
399
400     float row = 0, column = 0;
401     bool item_available;
402     for (i = 0; i < ITEMSTIME_MAXITEMS; ++i) {
403         if (ItemsTime_time[i] == -1)
404             continue;
405
406         float item_time = ItemsTime_time[i];
407         if(item_time < -1)
408         {
409             item_available = true;
410             item_time = -item_time;
411         }
412         else
413             item_available = (item_time <= time);
414
415         if(ItemsTime_time[i] >= 0)
416         {
417             if(time <= ItemsTime_time[i])
418                 ItemsTime_availableTime[i] = 0;
419             else if(ItemsTime_availableTime[i] == 0)
420                 ItemsTime_availableTime[i] = time;
421         }
422         else if(ItemsTime_availableTime[i] == 0)
423             ItemsTime_availableTime[i] = time;
424
425         float f = (time - ItemsTime_availableTime[i]) * 2;
426         f = (f > 1) ? 0 : bound(0, f, 1);
427
428         if(autocvar_hud_panel_itemstime_hidespawned == 1)
429             if(!(ItemsTime_time[i] > time || -ItemsTime_time[i] > time))
430                 continue;
431
432         if(autocvar_hud_panel_itemstime_hidespawned == 2)
433             if(!(ItemsTime_time[i] > time))
434                 continue;
435
436         DrawItemsTimeItem(pos + eX * column * (itemstime_size.x + offset.x) + eY * row * (itemstime_size.y + offset.y), itemstime_size, ar, i, item_time, item_available, f);
437         ++row;
438         if(row >= rows)
439         {
440             row = 0;
441             column = column + 1;
442         }
443     }
444 }
445
446 #endif