]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/waypointsprites.qc
Merge branch 'morphed/hpitems' of ssh://git.xonotic.org/xonotic-data.pk3dir into...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / waypointsprites.qc
1 float waypointsprite_initialized;
2 float waypointsprite_fadedistance;
3 float waypointsprite_normdistance;
4 float waypointsprite_minscale;
5 float waypointsprite_minalpha;
6 float waypointsprite_distancealphaexponent;
7 float waypointsprite_timealphaexponent;
8 float waypointsprite_scale;
9 float waypointsprite_edgefadealpha;
10 float waypointsprite_edgefadescale;
11 float waypointsprite_edgefadedistance;
12 float waypointsprite_crosshairfadealpha;
13 float waypointsprite_crosshairfadescale;
14 float waypointsprite_crosshairfadedistance;
15 float waypointsprite_distancefadealpha;
16 float waypointsprite_distancefadescale;
17 float waypointsprite_distancefadedistance;
18 float waypointsprite_alpha;
19
20 .float rule;
21 .string netname; // primary picture
22 .string netname2; // secondary picture
23 .string netname3; // tertiary picture
24 .float team; // team that gets netname2
25 .float lifetime;
26 .float fadetime;
27 .float maxdistance;
28 .float hideflags;
29 .float spawntime;
30 .float health;
31 .float build_started;
32 .float build_starthealth;
33 .float build_finished;
34
35 vector SPRITE_SIZE = '288 36 0';
36 vector SPRITE_HOTSPOT = '144 36 0';
37 float SPRITE_HEALTHBAR_WIDTH = 144;
38 float SPRITE_HEALTHBAR_HEIGHT = 9;
39 float SPRITE_HEALTHBAR_MARGIN = 6;
40 float SPRITE_HEALTHBAR_BORDER = 2;
41 float SPRITE_HEALTHBAR_BORDERALPHA = 1;
42 float SPRITE_HEALTHBAR_HEALTHALPHA = 0.5;
43
44 void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
45 {
46         vector v1, v2, v3, v4;
47
48         hotspot = -1 * hotspot;
49
50         // hotspot-relative coordinates of the corners
51         v1 = hotspot;
52         v2 = hotspot + '1 0 0' * sz_x;
53         v3 = hotspot + '1 0 0' * sz_x + '0 1 0' * sz_y;
54         v4 = hotspot                  + '0 1 0' * sz_y;
55
56         // rotate them, and make them absolute
57         rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
58         v1 = rotate(v1, rot) + org;
59         v2 = rotate(v2, rot) + org;
60         v3 = rotate(v3, rot) + org;
61         v4 = rotate(v4, rot) + org;
62
63         // draw them
64         R_BeginPolygon(pic, f);
65         R_PolygonVertex(v1, '0 0 0', rgb, a);
66         R_PolygonVertex(v2, '1 0 0', rgb, a);
67         R_PolygonVertex(v3, '1 1 0', rgb, a);
68         R_PolygonVertex(v4, '0 1 0', rgb, a);
69         R_EndPolygon();
70 }
71
72 void drawquad(vector o, vector ri, vector up, string pic, vector rgb, float a, float f)
73 {
74         R_BeginPolygon(pic, f);
75         R_PolygonVertex(o, '0 0 0', rgb, a);
76         R_PolygonVertex(o + ri, '1 0 0', rgb, a);
77         R_PolygonVertex(o + up + ri, '1 1 0', rgb, a);
78         R_PolygonVertex(o + up, '0 1 0', rgb, a);
79         R_EndPolygon();
80 }
81
82 void drawhealthbar(vector org, float rot, float h, vector sz, vector hotspot, float width, float height, float margin, float border, float align, vector rgb, float a, vector hrgb, float ha, float f)
83 {
84         vector o, ri, up;
85         float owidth; // outer width
86
87         hotspot = -1 * hotspot;
88
89         // hotspot-relative coordinates of the healthbar corners
90         o = hotspot;
91         ri = '1 0 0';
92         up = '0 1 0';
93         
94         rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
95         o = rotate(o, rot) + org;
96         ri = rotate(ri, rot);
97         up = rotate(up, rot);
98
99         owidth = width + 2 * border;
100         o = o - up * (margin + border + height) + ri * (sz_x - owidth) * 0.5;
101
102         drawquad(o - up * border,                               ri * owidth,    up * border, "", rgb,  a,  f);
103         drawquad(o + up * height,                               ri * owidth,    up * border, "", rgb,  a,  f);
104         drawquad(o,                                             ri * border,    up * height, "", rgb,  a,  f);
105         drawquad(o + ri * (owidth - border),                    ri * border,    up * height, "", rgb,  a,  f);
106         drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * height, "", hrgb, ha, f);
107 }
108
109 void Draw_WaypointSprite()
110 {
111         string spriteimage;
112         float t;
113
114         if(self.lifetime)
115                 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
116         else
117                 self.alpha = 1;
118
119         if(self.hideflags & 2)
120                 return; // radar only
121
122         if(autocvar_cl_hidewaypoints >= 2)
123                 return;
124
125         if(self.hideflags & 1)
126                 if(autocvar_cl_hidewaypoints)
127                         return; // fixed waypoint
128
129         InterpolateOrigin_Do();
130
131         t = GetPlayerColor(player_localentnum - 1) + 1;
132
133         spriteimage = "";
134
135         // choose the sprite
136         switch(self.rule)
137         {
138                 case SPRITERULE_DEFAULT:
139                         if(self.team)
140                         {
141                                 if(self.team == t)
142                                         spriteimage = self.netname;
143                                 else
144                                         spriteimage = "";
145                         }
146                         else
147                                 spriteimage = self.netname;
148                         break;
149                 case SPRITERULE_TEAMPLAY:
150                         if(t == COLOR_SPECTATOR + 1)
151                                 spriteimage = self.netname3;
152                         else if(self.team == t)
153                                 spriteimage = self.netname2;
154                         else
155                                 spriteimage = self.netname;
156                         break;
157                 default:
158                         error("Invalid waypointsprite rule!");
159                         break;
160         }
161
162         if(spriteimage == "")
163                 return;
164         
165         float dist;
166         dist = vlen(self.origin - view_origin);
167         
168         float a;
169         a = self.alpha * autocvar_hud_panel_fg_alpha;
170
171         if(self.maxdistance > waypointsprite_normdistance)
172                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
173         else if(self.maxdistance > 0)
174                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
175
176         if(a <= 0)
177                 return;
178         
179         // draw the sprite image
180         vector o;
181         float rot;
182         o = project_3d_to_2d(self.origin);
183         rot = 0;
184
185         if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight)
186         {
187                 // scale it to be just in view
188                 vector d;
189                 float f1, f2;
190
191                 // get the waypoint angle vector
192                 /*
193                 d_x = view_right * (self.origin - view_origin) * vid_conwidth / vid_width;
194                 d_y = -view_up * (self.origin - view_origin) * vid_conheight / (vid_height * vid_pixelheight);
195                 d_z = 0;
196                 */
197                 
198                 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
199
200                 /*
201                 if(autocvar_v_flipped)
202                         d_x = -d_x;
203                 */
204
205                 f1 = d_x / vid_conwidth;
206                 f2 = d_y / vid_conheight;
207
208                 if(max(f1, -f1) > max(f2, -f2))
209                 {
210                         if(d_z * f1 > 0)
211                         {
212                                 // RIGHT edge
213                                 d = d * (0.5 / f1);
214                                 rot = 3;
215                         }
216                         else
217                         {
218                                 // LEFT edge
219                                 d = d * (-0.5 / f1);
220                                 rot = 1;
221                         }
222                 }
223                 else
224                 {
225                         if(d_z * f2 > 0)
226                         {
227                                 // BOTTOM edge
228                                 d = d * (0.5 / f2);
229                                 rot = 0;
230                         }
231                         else
232                         {
233                                 // TOP edge
234                                 d = d * (-0.5 / f2);
235                                 rot = 2;
236                         }
237                 }
238
239                 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
240         }
241         o_z = 0;
242
243         float vidscale;
244         vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
245
246         t = stof(db_get(tempdb, strcat("/spriteframes/", spriteimage)));
247         if(t == 0)
248                 spriteimage = strcat("models/sprites/", spriteimage);
249         else
250                 spriteimage = strcat("models/sprites/", spriteimage, "_frame", ftos(mod(floor((max(0, time - self.spawntime)) * 2), t)));
251
252         float edgedistance_min, crosshairdistance;
253         edgedistance_min = min4(o_y, o_x,vid_conwidth - o_x, vid_conheight - o_y);
254
255         crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
256
257         t = waypointsprite_scale * vidscale;
258         a *= waypointsprite_alpha;
259
260         {
261                 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
262                 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
263         }
264         if (edgedistance_min < waypointsprite_edgefadedistance) {
265                 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
266                 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
267         }
268         if(crosshairdistance < waypointsprite_crosshairfadedistance) {
269                 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
270                 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
271         }
272         drawrotpic(o, rot * 90 * DEG2RAD, spriteimage, SPRITE_SIZE * t, SPRITE_HOTSPOT * t, '1 1 1', a, DRAWFLAG_MIPMAP);
273
274         if(self.build_finished)
275         {
276                 if(time < self.build_finished + 0.25)
277                 {
278                         if(time < self.build_started)
279                                 self.health = self.build_starthealth;
280                         else if(time < self.build_finished)
281                                 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
282                         else
283                                 self.health = 1;
284                 }
285                 else
286                         self.health = -1;
287         }
288
289         if(self.health >= 0)
290         {
291                 float align;
292                 if(self.build_finished)
293                         align = 0.5;
294                 else
295                         align = 0;
296                 drawhealthbar(o, rot * 90 * DEG2RAD, self.health, SPRITE_SIZE * t, SPRITE_HOTSPOT * t, SPRITE_HEALTHBAR_WIDTH * t, SPRITE_HEALTHBAR_HEIGHT * t, SPRITE_HEALTHBAR_MARGIN * t, SPRITE_HEALTHBAR_BORDER * t, align, self.teamradar_color, a * SPRITE_HEALTHBAR_BORDERALPHA, self.teamradar_color, a * SPRITE_HEALTHBAR_HEALTHALPHA, DRAWFLAG_NORMAL);
297         }
298 }
299
300 void Ent_RemoveWaypointSprite()
301 {
302         if(self.netname)
303                 strunzone(self.netname);
304         if(self.netname2)
305                 strunzone(self.netname2);
306         if(self.netname3)
307                 strunzone(self.netname3);
308 }
309
310 void Ent_WaypointSprite()
311 {
312         float sendflags, f, t;
313         sendflags = ReadByte();
314
315         if(!self.spawntime)
316                 self.spawntime = time;
317
318         self.draw2d = Draw_WaypointSprite;
319
320         InterpolateOrigin_Undo();
321
322         if(sendflags & 0x80)
323         {
324                 t = ReadByte();
325                 if(t < 192)
326                 {
327                         self.health = t / 191.0;
328                         self.build_finished = 0;
329                 }
330                 else
331                 {
332                         t = (t - 192) * 256 + ReadByte();
333                         self.build_started = servertime;
334                         if(self.build_finished)
335                                 self.build_starthealth = bound(0, self.health, 1);
336                         else
337                                 self.build_starthealth = 0;
338                         self.build_finished = servertime + t / 32;
339                 }
340         }
341         else
342         {
343                 self.health = -1;
344                 self.build_finished = 0;
345         }
346
347         if(sendflags & 64)
348         {
349                 // unfortunately, this needs to be exact (for the 3D display)
350                 self.origin_x = ReadCoord();
351                 self.origin_y = ReadCoord();
352                 self.origin_z = ReadCoord();
353         }
354
355         if(sendflags & 1)
356         {
357                 self.team = ReadByte();
358                 self.rule = ReadByte();
359         }
360
361         if(sendflags & 2)
362         {
363                 if(self.netname)
364                         strunzone(self.netname);
365                 self.netname = strzone(ReadString());
366         }
367
368         if(sendflags & 4)
369         {
370                 if(self.netname2)
371                         strunzone(self.netname2);
372                 self.netname2 = strzone(ReadString());
373         }
374
375         if(sendflags & 8)
376         {
377                 if(self.netname3)
378                         strunzone(self.netname3);
379                 self.netname3 = strzone(ReadString());
380         }
381
382         if(sendflags & 16)
383         {
384                 self.lifetime = ReadCoord();
385                 self.fadetime = ReadCoord();
386                 self.maxdistance = ReadShort();
387                 self.hideflags = ReadByte();
388         }
389
390         if(sendflags & 32)
391         {
392                 f = ReadByte();
393                 self.teamradar_icon = (f & 0x7F);
394                 if(f & 0x80)
395                 {
396                         self.(teamradar_times[self.teamradar_time_index]) = time;
397                         self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
398                 }
399                 self.teamradar_color_x = ReadByte() / 255.0;
400                 self.teamradar_color_y = ReadByte() / 255.0;
401                 self.teamradar_color_z = ReadByte() / 255.0;
402         }
403
404         InterpolateOrigin_Note();
405
406         self.entremove = Ent_RemoveWaypointSprite;
407 }
408
409 void WaypointSprite_Load()
410 {
411         waypointsprite_fadedistance = vlen(mi_scale);
412         waypointsprite_normdistance = autocvar_g_waypointsprite_normdistance;
413         waypointsprite_minscale = autocvar_g_waypointsprite_minscale;
414         waypointsprite_minalpha = autocvar_g_waypointsprite_minalpha;
415         waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent;
416         waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent;
417         waypointsprite_scale = autocvar_g_waypointsprite_scale;
418         waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha;
419         waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale;
420         waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;
421         waypointsprite_crosshairfadealpha = autocvar_g_waypointsprite_crosshairfadealpha;
422         waypointsprite_crosshairfadescale = autocvar_g_waypointsprite_crosshairfadescale;
423         waypointsprite_crosshairfadedistance = autocvar_g_waypointsprite_crosshairfadedistance;
424         waypointsprite_distancefadealpha = autocvar_g_waypointsprite_distancefadealpha;
425         waypointsprite_distancefadescale = autocvar_g_waypointsprite_distancefadescale;
426         waypointsprite_distancefadedistance = waypointsprite_fadedistance * autocvar_g_waypointsprite_distancefadedistancemultiplier;
427         waypointsprite_alpha = autocvar_g_waypointsprite_alpha * (1 - autocvar__menu_alpha);
428
429         if(!waypointsprite_initialized)
430         {
431                 float dh, n, i, o, f;
432                 string s, sname, sframes;
433
434                 dh = search_begin("models/sprites/*_frame*.tga", FALSE, FALSE);
435                 n = search_getsize(dh);
436                 for(i = 0; i < n; ++i)
437                 {
438                         s = search_getfilename(dh, i);
439                         s = substring(s, 15, strlen(s) - 15 - 4); // strip models/sprites/ and .tga
440
441                         o = strstrofs(s, "_frame", 0);
442                         sname = strcat("/spriteframes/", substring(s, 0, o));
443                         sframes = substring(s, o + 6, strlen(s) - o - 6);
444                         f = stof(sframes) + 1;
445                         db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
446                 }
447                 search_end(dh);
448
449                 dh = search_begin("models/sprites/*_frame*.jpg", FALSE, FALSE);
450                 n = search_getsize(dh);
451                 for(i = 0; i < n; ++i)
452                 {
453                         s = search_getfilename(dh, i);
454                         s = substring(s, 15, strlen(s) - 15 - 4); // strip models/sprites/ and .jpg
455
456                         o = strstrofs(s, "_frame", 0);
457                         sname = strcat("/spriteframes/", substring(s, 0, o));
458                         sframes = substring(s, o + 6, strlen(s) - o - 6);
459                         f = stof(sframes) + 1;
460                         db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
461                 }
462                 search_end(dh);
463                 waypointsprite_initialized = true;
464         }
465 }