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_fontsize;
10 float waypointsprite_edgefadealpha;
11 float waypointsprite_edgefadescale;
12 float waypointsprite_edgefadedistance;
13 float waypointsprite_crosshairfadealpha;
14 float waypointsprite_crosshairfadescale;
15 float waypointsprite_crosshairfadedistance;
16 float waypointsprite_distancefadealpha;
17 float waypointsprite_distancefadescale;
18 float waypointsprite_distancefadedistance;
19 float waypointsprite_alpha;
22 .string netname; // primary picture
23 .string netname2; // secondary picture
24 .string netname3; // tertiary picture
25 .float team; // team that gets netname2
33 .float build_starthealth;
34 .float build_finished;
36 float SPRITE_HEALTHBAR_WIDTH = 144;
37 float SPRITE_HEALTHBAR_HEIGHT = 9;
38 float SPRITE_HEALTHBAR_MARGIN = 6;
39 float SPRITE_HEALTHBAR_BORDER = 2;
40 float SPRITE_HEALTHBAR_BORDERALPHA = 1;
41 float SPRITE_HEALTHBAR_HEALTHALPHA = 0.5;
42 float SPRITE_ARROW_SCALE = 1.0;
44 void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
46 vector v1, v2, v3, v4;
48 hotspot = -1 * hotspot;
50 // hotspot-relative coordinates of the corners
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;
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;
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);
72 void drawquad(vector o, vector ri, vector up, string pic, vector rgb, float a, float f)
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);
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)
85 float owidth; // outer width
87 hotspot = -1 * hotspot;
89 // hotspot-relative coordinates of the healthbar corners
94 rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
95 o = rotate(o, rot) + org;
99 owidth = width + 2 * border;
100 o = o - up * (margin + border + height) + ri * (sz_x - owidth) * 0.5;
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);
109 // returns location of sprite text
110 vector drawspritearrow(vector o, float ang, vector rgb, float a, float t)
113 float BORDER; BORDER = 1.5 * t;
114 float TSIZE; TSIZE = 8 * t;
115 float RLENGTH; RLENGTH = 8 * t;
116 float RWIDTH; RWIDTH = 4 * t;
117 float MLENGTH; MLENGTH = 4 * t;
119 R_BeginPolygon("", DRAWFLAG_NORMAL);
120 R_PolygonVertex(o + rotate(eX * -(TSIZE + BORDER * (1 + SQRT2)) + eY * (TSIZE + BORDER), ang), '0 0 0', '0 0 0', a);
121 R_PolygonVertex(o + rotate(eX * (TSIZE + BORDER * (1 + SQRT2)) + eY * (TSIZE + BORDER), ang), '0 0 0', '0 0 0', a);
122 R_PolygonVertex(o + rotate(eY * -( BORDER * SQRT2), ang), '0 0 0', '0 0 0', a);
124 R_BeginPolygon("", DRAWFLAG_NORMAL);
125 R_PolygonVertex(o + rotate(eX * -(RWIDTH + BORDER) + eY * (TSIZE + BORDER), ang), '0 0 0', '0 0 0', a);
126 R_PolygonVertex(o + rotate(eX * -(RWIDTH + BORDER) + eY * (TSIZE + RLENGTH + BORDER), ang), '0 0 0', '0 0 0', a);
127 R_PolygonVertex(o + rotate(eX * (RWIDTH + BORDER) + eY * (TSIZE + RLENGTH + BORDER), ang), '0 0 0', '0 0 0', a);
128 R_PolygonVertex(o + rotate(eX * (RWIDTH + BORDER) + eY * (TSIZE + BORDER), ang), '0 0 0', '0 0 0', a);
131 R_BeginPolygon("", DRAWFLAG_ADDITIVE);
132 R_PolygonVertex(o + rotate(eX * -TSIZE + eY * TSIZE, ang), '0 0 0', rgb, a);
133 R_PolygonVertex(o + rotate(eX * TSIZE + eY * TSIZE, ang), '0 0 0', rgb, a);
134 R_PolygonVertex(o + rotate('0 0 0', ang), '0 0 0', rgb, a);
136 R_BeginPolygon("", DRAWFLAG_ADDITIVE);
137 R_PolygonVertex(o + rotate(eX * -RWIDTH + eY * TSIZE, ang), '0 0 0', rgb, a);
138 R_PolygonVertex(o + rotate(eX * -RWIDTH + eY * (TSIZE + RLENGTH), ang), '0 0 0', rgb, a);
139 R_PolygonVertex(o + rotate(eX * RWIDTH + eY * (TSIZE + RLENGTH), ang), '0 0 0', rgb, a);
140 R_PolygonVertex(o + rotate(eX * RWIDTH + eY * TSIZE, ang), '0 0 0', rgb, a);
144 o + rotate(eY * (TSIZE + RLENGTH + MLENGTH), ang);
147 // returns location of sprite healthbar
148 vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a, vector fontsize, string s)
152 float aspect, sa, ca;
154 sw = stringwidth(s, FALSE, fontsize);
161 // how do corners work?
162 aspect = vid_conwidth / vid_conheight;
164 ca = cos(ang) * aspect;
165 if(fabs(sa) > fabs(ca))
168 algny = 0.5 - 0.5 * ca / fabs(sa);
172 algnx = 0.5 - 0.5 * sa / fabs(ca);
180 // we want to be onscreen
185 if(o_x > vid_conwidth - w)
186 o_x = vid_conwidth - w;
187 if(o_y > vid_conheight - h)
188 o_x = vid_conheight - h;
190 o_x += 0.5 * (w - sw);
192 drawstring(o, s, fontsize, rgb, a, DRAWFLAG_NORMAL);
200 float spritelookupblinkvalue(string s)
204 case "ons-cp-atck-neut": return 2;
205 case "ons-cp-atck-red": return 2;
206 case "ons-cp-atck-blue": return 2;
207 case "ons-cp-dfnd-red": return 0.5;
208 case "ons-cp-dfnd-blue": return 0.5;
209 case "item-invis": return 2;
210 case "item-extralife": return 2;
211 case "item-speed": return 2;
212 case "item-strength": return 2;
213 case "item-shueld": return 2;
214 case "item-fuelregen": return 2;
215 case "item-jetpack": return 2;
219 vector spritelookupcolor(string s, vector def)
223 case "keycarrier-friend": return '0 1 0';
227 string spritelookuptext(string s)
231 case "as-push": return _("Push");
232 case "as-destroy": return _("Destroy");
233 case "as-defend": return _("Defend");
234 case "bluebase": return _("Blue base");
235 case "danger": return _("DANGER");
236 case "flagcarrier": return _("Flag carrier");
237 case "flagdropped": return _("Dropped flag");
238 case "helpme": return _("Help me!");
239 case "here": return _("Here");
240 case "key-dropped": return _("Dropped key");
241 case "keycarrier-blue": return _("Key carrier");
242 case "keycarrier-finish": return _("Run here");
243 case "keycarrier-friend": return _("Key carrier");
244 case "keycarrier-pink": return _("Key carrier");
245 case "keycarrier-red": return _("Key carrier");
246 case "keycarrier-yellow": return _("Key carrier");
247 case "redbase": return _("Red base");
248 case "waypoint": return _("Waypoint");
249 case "ons-gen-red": return _("Generator");
250 case "ons-gen-blue": return _("Generator");
251 case "ons-gen-shielded": return _("Generator");
252 case "ons-cp-neut": return _("Control point");
253 case "ons-cp-red": return _("Control point");
254 case "ons-cp-blue": return _("Control point");
255 case "ons-cp-atck-neut": return _("Control point");
256 case "ons-cp-atck-red": return _("Control point");
257 case "ons-cp-atck-blue": return _("Control point");
258 case "ons-cp-dfnd-red": return _("Control point");
259 case "ons-cp-dfnd-blue": return _("Control point");
260 case "race-checkpoint": return _("Checkpoint");
261 case "race-finish": return _("Finish");
262 case "race-start": return _("Start");
263 case "nb-ball": return _("Ball");
264 case "ka-ball": return _("Ball");
265 case "ka-ballcarrier": return _("Ball carrier");
266 case "wpn-laser": return _("Laser");
267 case "wpn-shotgun": return _("Shotgun");
268 case "wpn-uzi": return _("Machine Gun");
269 case "wpn-gl": return _("Mortar");
270 case "wpn-electro": return _("Electro");
271 case "wpn-crylink": return _("Crylink");
272 case "wpn-nex": return _("Nex");
273 case "wpn-hagar": return _("Hagar");
274 case "wpn-rl": return _("Rocket Launcher");
275 case "wpn-porto": return _("Port-O-Launch");
276 case "wpn-minstanex": return _("Minstanex");
277 case "wpn-hookgun": return _("Hook");
278 case "wpn-fireball": return _("Fireball");
279 case "wpn-hlac": return _("HLAC");
280 case "wpn-campingrifle": return _("Rifle");
281 case "wpn-minelayer": return _("Mine Layer");
282 case "dom-neut": return _("Control point");
283 case "dom-red": return _("Control point");
284 case "dom-blue": return _("Control point");
285 case "dom-yellow": return _("Control point");
286 case "dom-pink": return _("Control point");
287 case "item-invis": return _("Invisibility");
288 case "item-extralife": return _("Extra life");
289 case "item-speed": return _("Speed");
290 case "item-strength": return _("Strength");
291 case "item-shield": return _("Shield");
292 case "item-fuelregen": return _("Fuel regen");
293 case "item-jetpack": return _("Jet Pack");
294 case "freezetag_frozen": return _("Frozen!");
295 case "tagged-target": return _("Tagged");
296 case "vehicle": return _("Vehicle");
301 vector fixrgbexcess_move(vector rgb, vector src, vector dst)
303 vector yvec = '0.299 0.587 0.114';
304 return rgb + dst * ((src * yvec) / (dst * yvec)) * ((rgb - '1 1 1') * src);
306 vector fixrgbexcess(vector rgb)
310 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 1');
313 rgb = fixrgbexcess_move(rgb, '0 1 0', '0 0 1');
319 rgb = fixrgbexcess_move(rgb, '0 0 1', '0 1 0');
326 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 1');
329 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 0 1');
335 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 0 0');
342 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 1 0');
345 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 0');
351 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 0');
359 void Draw_WaypointSprite()
365 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
369 if(self.hideflags & 2)
370 return; // radar only
372 if(autocvar_cl_hidewaypoints >= 2)
375 if(self.hideflags & 1)
376 if(autocvar_cl_hidewaypoints)
377 return; // fixed waypoint
379 InterpolateOrigin_Do();
381 t = GetPlayerColor(player_localentnum - 1) + 1;
388 case SPRITERULE_DEFAULT:
392 spriteimage = self.netname;
397 spriteimage = self.netname;
399 case SPRITERULE_TEAMPLAY:
400 if(t == COLOR_SPECTATOR + 1)
401 spriteimage = self.netname3;
402 else if(self.team == t)
403 spriteimage = self.netname2;
405 spriteimage = self.netname;
408 error("Invalid waypointsprite rule!");
412 if(spriteimage == "")
416 dist = vlen(self.origin - view_origin);
419 a = self.alpha * autocvar_hud_panel_fg_alpha;
421 if(self.maxdistance > waypointsprite_normdistance)
422 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
423 else if(self.maxdistance > 0)
424 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
427 rgb = self.teamradar_color;
428 rgb = spritelookupcolor(spriteimage, rgb);
431 self.teamradar_color = '1 0 1';
432 print(sprintf("WARNING: sprite of name %s has no color, using pink so you notice it\n"));
435 if(time - floor(time) > 0.5)
436 a *= spritelookupblinkvalue(spriteimage);
447 rgb = fixrgbexcess(rgb);
452 o = project_3d_to_2d(self.origin);
453 if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight)
455 // scale it to be just in view
459 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
460 ang = atan2(-d_x, -d_y);
464 f1 = d_x / vid_conwidth;
465 f2 = d_y / vid_conheight;
467 if(max(f1, -f1) > max(f2, -f2))
494 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
502 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
503 ang = atan2(-d_x, -d_y);
508 float edgedistance_min, crosshairdistance;
509 edgedistance_min = min4(o_y, o_x,vid_conwidth - o_x, vid_conheight - o_y);
512 vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
514 crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
516 t = waypointsprite_scale * vidscale;
517 a *= waypointsprite_alpha;
520 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
521 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
523 if (edgedistance_min < waypointsprite_edgefadedistance) {
524 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
525 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
527 if(crosshairdistance < waypointsprite_crosshairfadedistance) {
528 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
529 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
532 if(self.build_finished)
534 if(time < self.build_finished + 0.25)
536 if(time < self.build_started)
537 self.health = self.build_starthealth;
538 else if(time < self.build_finished)
539 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
547 o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
550 txt = spritelookuptext(spriteimage);
551 if(autocvar_g_waypointsprite_uppercase)
552 txt = strtoupper(txt);
556 o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
559 if(self.build_finished)
564 marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize;
566 marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize;
573 SPRITE_HEALTHBAR_WIDTH * t,
574 SPRITE_HEALTHBAR_HEIGHT * t,
576 SPRITE_HEALTHBAR_BORDER * t,
579 a * SPRITE_HEALTHBAR_BORDERALPHA,
581 a * SPRITE_HEALTHBAR_HEALTHALPHA,
587 o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
591 void Ent_RemoveWaypointSprite()
594 strunzone(self.netname);
596 strunzone(self.netname2);
598 strunzone(self.netname3);
601 void Ent_WaypointSprite()
603 float sendflags, f, t;
604 sendflags = ReadByte();
607 self.spawntime = time;
609 self.draw2d = Draw_WaypointSprite;
611 InterpolateOrigin_Undo();
618 self.health = t / 191.0;
619 self.build_finished = 0;
623 t = (t - 192) * 256 + ReadByte();
624 self.build_started = servertime;
625 if(self.build_finished)
626 self.build_starthealth = bound(0, self.health, 1);
628 self.build_starthealth = 0;
629 self.build_finished = servertime + t / 32;
635 self.build_finished = 0;
640 // unfortunately, this needs to be exact (for the 3D display)
641 self.origin_x = ReadCoord();
642 self.origin_y = ReadCoord();
643 self.origin_z = ReadCoord();
648 self.team = ReadByte();
649 self.rule = ReadByte();
655 strunzone(self.netname);
656 self.netname = strzone(ReadString());
662 strunzone(self.netname2);
663 self.netname2 = strzone(ReadString());
669 strunzone(self.netname3);
670 self.netname3 = strzone(ReadString());
675 self.lifetime = ReadCoord();
676 self.fadetime = ReadCoord();
677 self.maxdistance = ReadShort();
678 self.hideflags = ReadByte();
684 self.teamradar_icon = (f & 0x7F);
687 self.(teamradar_times[self.teamradar_time_index]) = time;
688 self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
690 self.teamradar_color_x = ReadByte() / 255.0;
691 self.teamradar_color_y = ReadByte() / 255.0;
692 self.teamradar_color_z = ReadByte() / 255.0;
695 InterpolateOrigin_Note();
697 self.entremove = Ent_RemoveWaypointSprite;
700 void WaypointSprite_Load_Frames(string ext)
702 float dh, n, i, o, f;
703 string s, sname, sframes;
704 dh = search_begin(strcat("models/sprites/*_frame*", ext), FALSE, FALSE);
707 float ext_len = strlen(ext);
708 n = search_getsize(dh);
709 for(i = 0; i < n; ++i)
711 s = search_getfilename(dh, i);
712 s = substring(s, 15, strlen(s) - 15 - ext_len); // strip models/sprites/ and extension
714 o = strstrofs(s, "_frame", 0);
715 sname = strcat("/spriteframes/", substring(s, 0, o));
716 sframes = substring(s, o + 6, strlen(s) - o - 6);
717 f = stof(sframes) + 1;
718 db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
723 void WaypointSprite_Load()
725 waypointsprite_fadedistance = vlen(mi_scale);
726 waypointsprite_normdistance = autocvar_g_waypointsprite_normdistance;
727 waypointsprite_minscale = autocvar_g_waypointsprite_minscale;
728 waypointsprite_minalpha = autocvar_g_waypointsprite_minalpha;
729 waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent;
730 waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent;
731 waypointsprite_scale = autocvar_g_waypointsprite_scale;
732 waypointsprite_fontsize = autocvar_g_waypointsprite_fontsize;
733 waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha;
734 waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale;
735 waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;
736 waypointsprite_crosshairfadealpha = autocvar_g_waypointsprite_crosshairfadealpha;
737 waypointsprite_crosshairfadescale = autocvar_g_waypointsprite_crosshairfadescale;
738 waypointsprite_crosshairfadedistance = autocvar_g_waypointsprite_crosshairfadedistance;
739 waypointsprite_distancefadealpha = autocvar_g_waypointsprite_distancefadealpha;
740 waypointsprite_distancefadescale = autocvar_g_waypointsprite_distancefadescale;
741 waypointsprite_distancefadedistance = waypointsprite_fadedistance * autocvar_g_waypointsprite_distancefadedistancemultiplier;
742 waypointsprite_alpha = autocvar_g_waypointsprite_alpha * (1 - autocvar__menu_alpha);
744 if(!waypointsprite_initialized)
746 WaypointSprite_Load_Frames(".tga");
747 WaypointSprite_Load_Frames(".jpg");
748 waypointsprite_initialized = true;