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;
216 case "tagged-target": return 2;
220 vector spritelookupcolor(string s, vector def)
224 case "keycarrier-friend": return '0 1 0';
228 string spritelookuptext(string s)
232 case "as-push": return _("Push");
233 case "as-destroy": return _("Destroy");
234 case "as-defend": return _("Defend");
235 case "bluebase": return _("Blue base");
236 case "danger": return _("DANGER");
237 case "flagcarrier": return _("Flag carrier");
238 case "flagdropped": return _("Dropped flag");
239 case "helpme": return _("Help me!");
240 case "here": return _("Here");
241 case "key-dropped": return _("Dropped key");
242 case "keycarrier-blue": return _("Key carrier");
243 case "keycarrier-finish": return _("Run here");
244 case "keycarrier-friend": return _("Key carrier");
245 case "keycarrier-pink": return _("Key carrier");
246 case "keycarrier-red": return _("Key carrier");
247 case "keycarrier-yellow": return _("Key carrier");
248 case "redbase": return _("Red base");
249 case "waypoint": return _("Waypoint");
250 case "ons-gen-red": return _("Generator");
251 case "ons-gen-blue": return _("Generator");
252 case "ons-gen-shielded": return _("Generator");
253 case "ons-cp-neut": return _("Control point");
254 case "ons-cp-red": return _("Control point");
255 case "ons-cp-blue": return _("Control point");
256 case "ons-cp-atck-neut": return _("Control point");
257 case "ons-cp-atck-red": return _("Control point");
258 case "ons-cp-atck-blue": return _("Control point");
259 case "ons-cp-dfnd-red": return _("Control point");
260 case "ons-cp-dfnd-blue": return _("Control point");
261 case "race-checkpoint": return _("Checkpoint");
262 case "race-finish": return _("Finish");
263 case "race-start": return _("Start");
264 case "nb-ball": return _("Ball");
265 case "ka-ball": return _("Ball");
266 case "ka-ballcarrier": return _("Ball carrier");
267 case "wpn-laser": return _("Laser");
268 case "wpn-shotgun": return _("Shotgun");
269 case "wpn-uzi": return _("Machine Gun");
270 case "wpn-gl": return _("Mortar");
271 case "wpn-electro": return _("Electro");
272 case "wpn-crylink": return _("Crylink");
273 case "wpn-nex": return _("Nex");
274 case "wpn-hagar": return _("Hagar");
275 case "wpn-rl": return _("Rocket Launcher");
276 case "wpn-porto": return _("Port-O-Launch");
277 case "wpn-minstanex": return _("Minstanex");
278 case "wpn-hookgun": return _("Hook");
279 case "wpn-fireball": return _("Fireball");
280 case "wpn-hlac": return _("HLAC");
281 case "wpn-campingrifle": return _("Rifle");
282 case "wpn-minelayer": return _("Mine Layer");
283 case "dom-neut": return _("Control point");
284 case "dom-red": return _("Control point");
285 case "dom-blue": return _("Control point");
286 case "dom-yellow": return _("Control point");
287 case "dom-pink": return _("Control point");
288 case "item-invis": return _("Invisibility");
289 case "item-extralife": return _("Extra life");
290 case "item-speed": return _("Speed");
291 case "item-strength": return _("Strength");
292 case "item-shield": return _("Shield");
293 case "item-fuelregen": return _("Fuel regen");
294 case "item-jetpack": return _("Jet Pack");
295 case "freezetag_frozen": return _("Frozen!");
296 case "tagged-target": return _("Tagged");
297 case "vehicle": return _("Vehicle");
302 vector fixrgbexcess_move(vector rgb, vector src, vector dst)
304 vector yvec = '0.299 0.587 0.114';
305 return rgb + dst * ((src * yvec) / (dst * yvec)) * ((rgb - '1 1 1') * src);
307 vector fixrgbexcess(vector rgb)
311 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 1');
314 rgb = fixrgbexcess_move(rgb, '0 1 0', '0 0 1');
320 rgb = fixrgbexcess_move(rgb, '0 0 1', '0 1 0');
327 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 1');
330 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 0 1');
336 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 0 0');
343 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 1 0');
346 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 0');
352 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 0');
360 void Draw_WaypointSprite()
366 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
370 if(self.hideflags & 2)
371 return; // radar only
373 if(autocvar_cl_hidewaypoints >= 2)
376 if(self.hideflags & 1)
377 if(autocvar_cl_hidewaypoints)
378 return; // fixed waypoint
380 InterpolateOrigin_Do();
382 t = GetPlayerColor(player_localentnum - 1) + 1;
389 case SPRITERULE_DEFAULT:
393 spriteimage = self.netname;
398 spriteimage = self.netname;
400 case SPRITERULE_TEAMPLAY:
401 if(t == COLOR_SPECTATOR + 1)
402 spriteimage = self.netname3;
403 else if(self.team == t)
404 spriteimage = self.netname2;
406 spriteimage = self.netname;
409 error("Invalid waypointsprite rule!");
413 if(spriteimage == "")
417 dist = vlen(self.origin - view_origin);
420 a = self.alpha * autocvar_hud_panel_fg_alpha;
422 if(self.maxdistance > waypointsprite_normdistance)
423 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
424 else if(self.maxdistance > 0)
425 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
428 rgb = self.teamradar_color;
429 rgb = spritelookupcolor(spriteimage, rgb);
432 self.teamradar_color = '1 0 1';
433 print(sprintf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage));
436 if(time - floor(time) > 0.5)
437 a *= spritelookupblinkvalue(spriteimage);
448 rgb = fixrgbexcess(rgb);
453 o = project_3d_to_2d(self.origin);
454 if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight)
456 // scale it to be just in view
460 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
461 ang = atan2(-d_x, -d_y);
465 f1 = d_x / vid_conwidth;
466 f2 = d_y / vid_conheight;
468 if(max(f1, -f1) > max(f2, -f2))
495 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
503 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
504 ang = atan2(-d_x, -d_y);
509 float edgedistance_min, crosshairdistance;
510 edgedistance_min = min4(o_y, o_x,vid_conwidth - o_x, vid_conheight - o_y);
513 vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
515 crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
517 t = waypointsprite_scale * vidscale;
518 a *= waypointsprite_alpha;
521 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
522 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
524 if (edgedistance_min < waypointsprite_edgefadedistance) {
525 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
526 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
528 if(crosshairdistance < waypointsprite_crosshairfadedistance) {
529 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
530 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
533 if(self.build_finished)
535 if(time < self.build_finished + 0.25)
537 if(time < self.build_started)
538 self.health = self.build_starthealth;
539 else if(time < self.build_finished)
540 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
548 o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
551 txt = spritelookuptext(spriteimage);
552 if(autocvar_g_waypointsprite_uppercase)
553 txt = strtoupper(txt);
557 o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
560 if(self.build_finished)
565 marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize;
567 marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize;
574 SPRITE_HEALTHBAR_WIDTH * t,
575 SPRITE_HEALTHBAR_HEIGHT * t,
577 SPRITE_HEALTHBAR_BORDER * t,
580 a * SPRITE_HEALTHBAR_BORDERALPHA,
582 a * SPRITE_HEALTHBAR_HEALTHALPHA,
588 o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
592 void Ent_RemoveWaypointSprite()
595 strunzone(self.netname);
597 strunzone(self.netname2);
599 strunzone(self.netname3);
602 void Ent_WaypointSprite()
604 float sendflags, f, t;
605 sendflags = ReadByte();
608 self.spawntime = time;
610 self.draw2d = Draw_WaypointSprite;
612 InterpolateOrigin_Undo();
619 self.health = t / 191.0;
620 self.build_finished = 0;
624 t = (t - 192) * 256 + ReadByte();
625 self.build_started = servertime;
626 if(self.build_finished)
627 self.build_starthealth = bound(0, self.health, 1);
629 self.build_starthealth = 0;
630 self.build_finished = servertime + t / 32;
636 self.build_finished = 0;
641 // unfortunately, this needs to be exact (for the 3D display)
642 self.origin_x = ReadCoord();
643 self.origin_y = ReadCoord();
644 self.origin_z = ReadCoord();
649 self.team = ReadByte();
650 self.rule = ReadByte();
656 strunzone(self.netname);
657 self.netname = strzone(ReadString());
663 strunzone(self.netname2);
664 self.netname2 = strzone(ReadString());
670 strunzone(self.netname3);
671 self.netname3 = strzone(ReadString());
676 self.lifetime = ReadCoord();
677 self.fadetime = ReadCoord();
678 self.maxdistance = ReadShort();
679 self.hideflags = ReadByte();
685 self.teamradar_icon = (f & 0x7F);
688 self.(teamradar_times[self.teamradar_time_index]) = time;
689 self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
691 self.teamradar_color_x = ReadByte() / 255.0;
692 self.teamradar_color_y = ReadByte() / 255.0;
693 self.teamradar_color_z = ReadByte() / 255.0;
696 InterpolateOrigin_Note();
698 self.entremove = Ent_RemoveWaypointSprite;
701 void WaypointSprite_Load_Frames(string ext)
703 float dh, n, i, o, f;
704 string s, sname, sframes;
705 dh = search_begin(strcat("models/sprites/*_frame*", ext), FALSE, FALSE);
708 float ext_len = strlen(ext);
709 n = search_getsize(dh);
710 for(i = 0; i < n; ++i)
712 s = search_getfilename(dh, i);
713 s = substring(s, 15, strlen(s) - 15 - ext_len); // strip models/sprites/ and extension
715 o = strstrofs(s, "_frame", 0);
716 sname = strcat("/spriteframes/", substring(s, 0, o));
717 sframes = substring(s, o + 6, strlen(s) - o - 6);
718 f = stof(sframes) + 1;
719 db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
724 void WaypointSprite_Load()
726 waypointsprite_fadedistance = vlen(mi_scale);
727 waypointsprite_normdistance = autocvar_g_waypointsprite_normdistance;
728 waypointsprite_minscale = autocvar_g_waypointsprite_minscale;
729 waypointsprite_minalpha = autocvar_g_waypointsprite_minalpha;
730 waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent;
731 waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent;
732 waypointsprite_scale = autocvar_g_waypointsprite_scale;
733 waypointsprite_fontsize = autocvar_g_waypointsprite_fontsize;
734 waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha;
735 waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale;
736 waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;
737 waypointsprite_crosshairfadealpha = autocvar_g_waypointsprite_crosshairfadealpha;
738 waypointsprite_crosshairfadescale = autocvar_g_waypointsprite_crosshairfadescale;
739 waypointsprite_crosshairfadedistance = autocvar_g_waypointsprite_crosshairfadedistance;
740 waypointsprite_distancefadealpha = autocvar_g_waypointsprite_distancefadealpha;
741 waypointsprite_distancefadescale = autocvar_g_waypointsprite_distancefadescale;
742 waypointsprite_distancefadedistance = waypointsprite_fadedistance * autocvar_g_waypointsprite_distancefadedistancemultiplier;
743 waypointsprite_alpha = autocvar_g_waypointsprite_alpha * (1 - autocvar__menu_alpha);
745 if(!waypointsprite_initialized)
747 WaypointSprite_Load_Frames(".tga");
748 WaypointSprite_Load_Frames(".jpg");
749 waypointsprite_initialized = true;