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