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