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