]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/waypointsprites.qc
build bar: center it
[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 = '256 32 0';
26 vector SPRITE_HOTSPOT = '128 32 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(self.hideflags & 1)
116                 if(cvar("cl_hidewaypoints"))
117                         return; // fixed waypoint
118
119         InterpolateOrigin_Do();
120
121         t = GetPlayerColor(player_localentnum - 1) + 1;
122
123         spriteimage = "";
124
125         // choose the sprite
126         switch(self.rule)
127         {
128                 case SPRITERULE_DEFAULT:
129                         if(self.team)
130                         {
131                                 if(self.team == t)
132                                         spriteimage = self.netname;
133                                 else
134                                         spriteimage = "";
135                         }
136                         else
137                                 spriteimage = self.netname;
138                         break;
139                 case SPRITERULE_TEAMPLAY:
140                         if(t == COLOR_SPECTATOR + 1)
141                                 spriteimage = self.netname3;
142                         else if(self.team == t)
143                                 spriteimage = self.netname2;
144                         else
145                                 spriteimage = self.netname;
146                         break;
147                 default:
148                         error("Invalid waypointsprite rule!");
149                         break;
150         }
151
152         if(spriteimage == "")
153                 return;
154         
155         float dist;
156         dist = vlen(self.origin - view_origin);
157         
158         float a;
159         a = self.alpha;
160
161         if(self.maxdistance > waypointsprite_normdistance)
162                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
163         else if(self.maxdistance > 0)
164                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
165
166         if(a <= 0)
167                 return;
168         
169         // draw the sprite image
170         vector o;
171         float rot;
172         o = project_3d_to_2d(self.origin);
173         rot = 0;
174
175         if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight)
176         {
177                 // scale it to be just in view
178                 vector d;
179                 float f1, f2;
180
181                 // get the waypoint angle vector
182                 /*
183                 d_x = view_right * (self.origin - view_origin) * vid_conwidth / vid_width;
184                 d_y = -view_up * (self.origin - view_origin) * vid_conheight / (vid_height * vid_pixelheight);
185                 d_z = 0;
186                 */
187                 
188                 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
189
190                 if(cvar("v_flipped"))
191                         d_x = -d_x;
192
193                 f1 = d_x / vid_conwidth;
194                 f2 = d_y / vid_conheight;
195
196                 if(max(f1, -f1) > max(f2, -f2))
197                 {
198                         if(f1 > 0)
199                         {
200                                 // RIGHT edge
201                                 d = d * (0.5 / f1);
202                                 rot = 3;
203                         }
204                         else
205                         {
206                                 // LEFT edge
207                                 d = d * (-0.5 / f1);
208                                 rot = 1;
209                         }
210                 }
211                 else
212                 {
213                         if(f2 > 0)
214                         {
215                                 // BOTTOM edge
216                                 d = d * (0.5 / f2);
217                                 rot = 0;
218                         }
219                         else
220                         {
221                                 // TOP edge
222                                 d = d * (-0.5 / f2);
223                                 rot = 2;
224                         }
225                 }
226
227                 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
228         }
229         o_z = 0;
230
231         float vidscale;
232         vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
233
234         t = stof(db_get(tempdb, strcat("/spriteframes/", spriteimage)));
235         if(t == 0)
236                 spriteimage = strcat("models/sprites/", spriteimage);
237         else
238                 spriteimage = strcat("models/sprites/", spriteimage, "_frame", ftos(mod(floor((max(0, time - self.spawntime)) * 2), t)));
239
240         drawrotpic(o, rot * 90 * DEG2RAD, spriteimage, SPRITE_SIZE * waypointsprite_scale * vidscale, SPRITE_HOTSPOT * waypointsprite_scale * vidscale, '1 1 1', a, DRAWFLAG_MIPMAP);
241
242         if(self.build_finished)
243         {
244                 if(time < self.build_finished + 0.25)
245                 {
246                         if(time < self.build_started)
247                                 self.health = self.build_starthealth;
248                         else if(time < self.build_finished)
249                                 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
250                         else
251                                 self.health = 1;
252                 }
253                 else
254                         self.health = -1;
255         }
256
257         if(self.health >= 0)
258         {
259                 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, (self.build_finished ? 0.5 : 0), self.teamradar_color, a * SPRITE_HEALTHBAR_BORDERALPHA, self.teamradar_color, a * SPRITE_HEALTHBAR_HEALTHALPHA, DRAWFLAG_NORMAL);
260         }
261 }
262
263 void Ent_RemoveWaypointSprite()
264 {
265         if(self.netname)
266                 strunzone(self.netname);
267         if(self.netname2)
268                 strunzone(self.netname2);
269         if(self.netname3)
270                 strunzone(self.netname3);
271 }
272
273 void Ent_WaypointSprite()
274 {
275         float sendflags, f, t;
276         sendflags = ReadByte();
277
278         if(!self.spawntime)
279                 self.spawntime = time;
280
281         self.draw2d = Draw_WaypointSprite;
282
283         InterpolateOrigin_Undo();
284
285         if(sendflags & 0x80)
286         {
287                 t = ReadByte();
288                 if(t < 192)
289                 {
290                         self.health = t / 191.0;
291                         self.build_finished = 0;
292                 }
293                 else
294                 {
295                         t = (t - 192) * 256 + ReadByte();
296                         self.build_started = servertime;
297                         if(self.build_finished)
298                                 self.build_starthealth = bound(0, self.health, 1);
299                         else
300                                 self.build_starthealth = 0;
301                         self.build_finished = servertime + t / 32;
302                         //print("build: ", ftos(self.build_finished - self.build_started), "\n");
303                 }
304         }
305         else
306                 self.health = -1;
307
308         if(sendflags & 64)
309         {
310                 // unfortunately, this needs to be exact (for the 3D display)
311                 self.origin_x = ReadCoord();
312                 self.origin_y = ReadCoord();
313                 self.origin_z = ReadCoord();
314         }
315
316         if(sendflags & 1)
317         {
318                 self.team = ReadByte();
319                 self.rule = ReadByte();
320         }
321
322         if(sendflags & 2)
323         {
324                 if(self.netname)
325                         strunzone(self.netname);
326                 self.netname = strzone(ReadString());
327         }
328
329         if(sendflags & 4)
330         {
331                 if(self.netname2)
332                         strunzone(self.netname2);
333                 self.netname2 = strzone(ReadString());
334         }
335
336         if(sendflags & 8)
337         {
338                 if(self.netname3)
339                         strunzone(self.netname3);
340                 self.netname3 = strzone(ReadString());
341         }
342
343         if(sendflags & 16)
344         {
345                 self.lifetime = ReadCoord();
346                 self.fadetime = ReadCoord();
347                 self.maxdistance = ReadShort();
348                 self.hideflags = ReadByte();
349         }
350
351         if(sendflags & 32)
352         {
353                 f = ReadByte();
354                 self.teamradar_icon = (f & 0x7F);
355                 if(f & 0x80)
356                 {
357                         self.(teamradar_times[self.teamradar_time_index]) = time;
358                         self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
359                 }
360                 self.teamradar_color_x = ReadByte() / 255.0;
361                 self.teamradar_color_y = ReadByte() / 255.0;
362                 self.teamradar_color_z = ReadByte() / 255.0;
363         }
364
365         InterpolateOrigin_Note();
366
367         self.entremove = Ent_RemoveWaypointSprite;
368 }
369
370 void WaypointSprite_Load()
371 {
372         waypointsprite_fadedistance = vlen(world.maxs - world.mins);
373         waypointsprite_normdistance = cvar("g_waypointsprite_normdistance");
374         waypointsprite_minscale = cvar("g_waypointsprite_minscale");
375         waypointsprite_minalpha = cvar("g_waypointsprite_minalpha");
376         waypointsprite_distancealphaexponent = cvar("g_waypointsprite_distancealphaexponent");
377         waypointsprite_timealphaexponent = cvar("g_waypointsprite_timealphaexponent");
378         waypointsprite_scale = cvar("g_waypointsprite_scale");
379         if(!waypointsprite_scale)
380                 waypointsprite_scale = 1.0;
381
382         if(!waypointsprite_initialized)
383         {
384                 float dh, n, i, o, f;
385                 string s, sname, sframes;
386                 dh = search_begin("models/sprites/*_frame*.tga", FALSE, FALSE);
387                 n = search_getsize(dh);
388                 for(i = 0; i < n; ++i)
389                 {
390                         s = search_getfilename(dh, i);
391                         if(substring(s, 0, 15) != "models/sprites/")
392                                 continue;
393                         if(substring(s, strlen(s) - 4, 4) != ".tga")
394                                 continue;
395                         s = substring(s, 15, strlen(s) - 19);
396
397                         o = strstrofs(s, "_frame", 0);
398                         sname = strcat("/spriteframes/", substring(s, 0, o));
399                         sframes = substring(s, o + 6, strlen(s) - o - 6);
400                         f = stof(sframes) + 1;
401                         db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
402                 }
403                 search_end(dh);
404         }
405         waypointsprite_initialized = 1;
406 }