1 #include "waypointsprites.qh"
3 void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
7 hotspot = -1 * hotspot;
9 // hotspot-relative coordinates of the corners
11 v2 = hotspot + '1 0 0' * sz.x;
12 v3 = hotspot + '1 0 0' * sz.x + '0 1 0' * sz.y;
13 v4 = hotspot + '0 1 0' * sz.y;
15 // rotate them, and make them absolute
16 rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
17 v1 = rotate(v1, rot) + org;
18 v2 = rotate(v2, rot) + org;
19 v3 = rotate(v3, rot) + org;
20 v4 = rotate(v4, rot) + org;
23 R_BeginPolygon(pic, f);
24 R_PolygonVertex(v1, '0 0 0', rgb, a);
25 R_PolygonVertex(v2, '1 0 0', rgb, a);
26 R_PolygonVertex(v3, '1 1 0', rgb, a);
27 R_PolygonVertex(v4, '0 1 0', rgb, a);
31 void drawquad(vector o, vector ri, vector up, string pic, vector rgb, float a, float f)
33 R_BeginPolygon(pic, f);
34 R_PolygonVertex(o, '0 0 0', rgb, a);
35 R_PolygonVertex(o + ri, '1 0 0', rgb, a);
36 R_PolygonVertex(o + up + ri, '1 1 0', rgb, a);
37 R_PolygonVertex(o + up, '0 1 0', rgb, a);
41 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)
44 float owidth; // outer width
46 hotspot = -1 * hotspot;
48 // hotspot-relative coordinates of the healthbar corners
53 rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
54 o = rotate(o, rot) + org;
58 owidth = width + 2 * border;
59 o = o - up * (margin + border + height) + ri * (sz.x - owidth) * 0.5;
61 drawquad(o - up * border, ri * owidth, up * border, "", rgb, a, f);
62 drawquad(o + up * height, ri * owidth, up * border, "", rgb, a, f);
63 drawquad(o, ri * border, up * height, "", rgb, a, f);
64 drawquad(o + ri * (owidth - border), ri * border, up * height, "", rgb, a, f);
65 drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * height, "", hrgb, ha, f);
68 // returns location of sprite text
69 vector drawspritearrow(vector o, float ang, vector rgb, float a, float t)
72 float border = 1.5 * t;
73 float margin = 4.0 * t;
75 float borderDiag = border * 1.414;
76 vector arrowX = eX * size;
77 vector arrowY = eY * (size+borderDiag);
78 vector borderX = eX * (size+borderDiag);
79 vector borderY = eY * (size+borderDiag+border);
81 R_BeginPolygon("", DRAWFLAG_NORMAL);
82 R_PolygonVertex(o, '0 0 0', '0 0 0', a);
83 R_PolygonVertex(o + rotate(arrowY - borderX, ang), '0 0 0', '0 0 0', a);
84 R_PolygonVertex(o + rotate(borderY - borderX, ang), '0 0 0', '0 0 0', a);
85 R_PolygonVertex(o + rotate(borderY + borderX, ang), '0 0 0', '0 0 0', a);
86 R_PolygonVertex(o + rotate(arrowY + borderX, ang), '0 0 0', '0 0 0', a);
89 R_BeginPolygon("", DRAWFLAG_ADDITIVE);
90 R_PolygonVertex(o + rotate(eY * borderDiag, ang), '0 0 0', rgb, a);
91 R_PolygonVertex(o + rotate(arrowY - arrowX, ang), '0 0 0', rgb, a);
92 R_PolygonVertex(o + rotate(arrowY + arrowX, ang), '0 0 0', rgb, a);
95 return o + rotate(eY * (borderDiag+size+margin), ang);
98 // returns location of sprite healthbar
99 vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a, vector fontsize, string s)
103 float aspect, sa, ca;
105 sw = stringwidth(s, false, fontsize);
112 // how do corners work?
113 aspect = vid_conwidth / vid_conheight;
115 ca = cos(ang) * aspect;
116 if(fabs(sa) > fabs(ca))
119 algny = 0.5 - 0.5 * ca / fabs(sa);
123 algnx = 0.5 - 0.5 * sa / fabs(ca);
131 // we want to be onscreen
136 if(o.x > vid_conwidth - w)
137 o.x = vid_conwidth - w;
138 if(o.y > vid_conheight - h)
139 o.x = vid_conheight - h;
141 o.x += 0.5 * (w - sw);
143 drawstring(o, s, fontsize, rgb, a, DRAWFLAG_NORMAL);
151 float spritelookupblinkvalue(string s)
155 case "ons-cp-atck-neut": return 2;
156 case "ons-cp-atck-red": return 2;
157 case "ons-cp-atck-blue": return 2;
158 case "ons-cp-dfnd-red": return 0.5;
159 case "ons-cp-dfnd-blue": return 0.5;
160 case "item-invis": return 2;
161 case "item-extralife": return 2;
162 case "item-speed": return 2;
163 case "item-strength": return 2;
164 case "item-shield": return 2;
165 case "item-fuelregen": return 2;
166 case "item-jetpack": return 2;
167 case "tagged-target": return 2;
171 vector spritelookupcolor(string s, vector def)
173 if(substring(s, 0, 4) == "wpn-")
174 return (get_weaponinfo(stof(substring(s, 4, strlen(s)))).wpcolor);
178 case "keycarrier-friend": return '0 1 0';
182 string spritelookuptext(string s)
184 if(substring(s, 0, 4) == "wpn-") { return (get_weaponinfo(stof(substring(s, 4, strlen(s)))).message); }
185 if(substring(s, 0, 5) == "buff-") { return Buff_PrettyName(Buff_Type_FromSprite(s)); }
189 case "as-push": return _("Push");
190 case "as-destroy": return _("Destroy");
191 case "as-defend": return _("Defend");
192 case "bluebase": return _("Blue base");
193 case "danger": return _("DANGER");
194 case "enemyflagcarrier": return _("Enemy carrier");
195 case "flagcarrier": return _("Flag carrier");
196 case "flagdropped": return _("Dropped flag");
197 case "helpme": return _("Help me!");
198 case "here": return _("Here");
199 case "key-dropped": return _("Dropped key");
200 case "keycarrier-blue": return _("Key carrier");
201 case "keycarrier-finish": return _("Run here");
202 case "keycarrier-friend": return _("Key carrier");
203 case "keycarrier-pink": return _("Key carrier");
204 case "keycarrier-red": return _("Key carrier");
205 case "keycarrier-yellow": return _("Key carrier");
206 case "redbase": return _("Red base");
207 case "yellowbase": return _("Yellow base");
208 case "neutralbase": return _("White base");
209 case "pinkbase": return _("Pink base");
210 case "waypoint": return _("Waypoint");
211 case "ons-gen-red": return _("Generator");
212 case "ons-gen-blue": return _("Generator");
213 case "ons-gen-shielded": return _("Generator");
214 case "ons-cp-neut": return _("Control point");
215 case "ons-cp-red": return _("Control point");
216 case "ons-cp-blue": return _("Control point");
217 case "ons-cp-atck-neut": return _("Control point");
218 case "ons-cp-atck-red": return _("Control point");
219 case "ons-cp-atck-blue": return _("Control point");
220 case "ons-cp-dfnd-red": return _("Control point");
221 case "ons-cp-dfnd-blue": return _("Control point");
222 case "race-checkpoint": return _("Checkpoint");
223 case "race-finish": return _("Finish");
224 case "race-start": return _("Start");
225 case "race-start-finish": return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
226 case "goal": return _("Goal");
227 case "nb-ball": return _("Ball");
228 case "ka-ball": return _("Ball");
229 case "ka-ballcarrier": return _("Ball carrier");
230 case "dom-neut": return _("Control point");
231 case "dom-red": return _("Control point");
232 case "dom-blue": return _("Control point");
233 case "dom-yellow": return _("Control point");
234 case "dom-pink": return _("Control point");
235 case "item-invis": return _("Invisibility");
236 case "item-extralife": return _("Extra life");
237 case "item-speed": return _("Speed");
238 case "item-strength": return _("Strength");
239 case "item-shield": return _("Shield");
240 case "item-fuelregen": return _("Fuel regen");
241 case "item-jetpack": return _("Jet Pack");
242 case "frozen": return _("Frozen!");
243 case "tagged-target": return _("Tagged");
244 case "vehicle": return _("Vehicle");
249 vector fixrgbexcess_move(vector rgb, vector src, vector dst)
251 vector yvec = '0.299 0.587 0.114';
252 return rgb + dst * ((src * yvec) / (dst * yvec)) * ((rgb - '1 1 1') * src);
254 vector fixrgbexcess(vector rgb)
258 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 1');
261 rgb = fixrgbexcess_move(rgb, '0 1 0', '0 0 1');
267 rgb = fixrgbexcess_move(rgb, '0 0 1', '0 1 0');
274 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 1');
277 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 0 1');
283 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 0 0');
290 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 1 0');
293 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 0');
299 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 0');
307 void Draw_WaypointSprite()
313 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
317 if(self.hideflags & 2)
318 return; // radar only
320 if(autocvar_cl_hidewaypoints >= 2)
323 if(self.hideflags & 1)
324 if(autocvar_cl_hidewaypoints)
325 return; // fixed waypoint
327 InterpolateOrigin_Do();
329 t = GetPlayerColor(player_localnum) + 1;
336 case SPRITERULE_DEFAULT:
340 spriteimage = self.netname;
345 spriteimage = self.netname;
347 case SPRITERULE_TEAMPLAY:
348 if(t == NUM_SPECTATOR + 1)
349 spriteimage = self.netname3;
350 else if(self.team == t)
351 spriteimage = self.netname2;
353 spriteimage = self.netname;
356 error("Invalid waypointsprite rule!");
360 if(spriteimage == "")
363 ++waypointsprite_newcount;
366 dist = vlen(self.origin - view_origin);
369 a = self.alpha * autocvar_hud_panel_fg_alpha;
371 if(self.maxdistance > waypointsprite_normdistance)
372 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
373 else if(self.maxdistance > 0)
374 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
377 rgb = self.teamradar_color;
378 rgb = spritelookupcolor(spriteimage, rgb);
381 self.teamradar_color = '1 0 1';
382 printf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage);
385 if(time - floor(time) > 0.5)
387 if(self.helpme && time < self.helpme)
388 a *= SPRITE_HELPME_BLINK;
390 a *= spritelookupblinkvalue(spriteimage);
402 rgb = fixrgbexcess(rgb);
407 o = project_3d_to_2d(self.origin);
409 || o.x < (vid_conwidth * waypointsprite_edgeoffset_left)
410 || o.y < (vid_conheight * waypointsprite_edgeoffset_top)
411 || o.x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
412 || o.y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
414 // scale it to be just in view
418 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
419 ang = atan2(-d.x, -d.y);
423 f1 = d.x / vid_conwidth;
424 f2 = d.y / vid_conheight;
426 if(max(f1, -f1) > max(f2, -f2))
431 d = d * ((0.5 - waypointsprite_edgeoffset_right) / f1);
436 d = d * (-(0.5 - waypointsprite_edgeoffset_left) / f1);
444 d = d * ((0.5 - waypointsprite_edgeoffset_bottom) / f2);
449 d = d * (-(0.5 - waypointsprite_edgeoffset_top) / f2);
453 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
461 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
462 ang = atan2(-d.x, -d.y);
467 float edgedistance_min, crosshairdistance;
468 edgedistance_min = min((o.y - (vid_conheight * waypointsprite_edgeoffset_top)),
469 (o.x - (vid_conwidth * waypointsprite_edgeoffset_left)),
470 (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o.x,
471 (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o.y);
474 vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
476 crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
478 t = waypointsprite_scale * vidscale;
479 a *= waypointsprite_alpha;
482 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
483 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
485 if (edgedistance_min < waypointsprite_edgefadedistance) {
486 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
487 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
489 if(crosshairdistance < waypointsprite_crosshairfadedistance) {
490 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
491 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
494 if(self.build_finished)
496 if(time < self.build_finished + 0.25)
498 if(time < self.build_started)
499 self.health = self.build_starthealth;
500 else if(time < self.build_finished)
501 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
509 o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
512 if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
515 txt = spritelookuptext(spriteimage);
516 if(self.helpme && time < self.helpme)
517 txt = sprintf(_("%s needing help!"), txt);
518 if(autocvar_g_waypointsprite_uppercase)
519 txt = strtoupper(txt);
521 draw_beginBoldFont();
524 o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
527 if(self.build_finished)
532 marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize;
534 marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize;
541 SPRITE_HEALTHBAR_WIDTH * t,
542 SPRITE_HEALTHBAR_HEIGHT * t,
544 SPRITE_HEALTHBAR_BORDER * t,
547 a * SPRITE_HEALTHBAR_BORDERALPHA,
549 a * SPRITE_HEALTHBAR_HEALTHALPHA,
555 o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
560 void Ent_RemoveWaypointSprite()
563 strunzone(self.netname);
565 strunzone(self.netname2);
567 strunzone(self.netname3);
570 void Ent_WaypointSprite()
573 sendflags = ReadByte();
576 self.spawntime = time;
578 self.draw2d = Draw_WaypointSprite;
580 InterpolateOrigin_Undo();
581 self.iflags |= IFLAG_ORIGIN;
588 self.health = t / 191.0;
589 self.build_finished = 0;
593 t = (t - 192) * 256 + ReadByte();
594 self.build_started = servertime;
595 if(self.build_finished)
596 self.build_starthealth = bound(0, self.health, 1);
598 self.build_starthealth = 0;
599 self.build_finished = servertime + t / 32;
605 self.build_finished = 0;
610 // unfortunately, this needs to be exact (for the 3D display)
611 self.origin_x = ReadCoord();
612 self.origin_y = ReadCoord();
613 self.origin_z = ReadCoord();
614 setorigin(self, self.origin);
619 self.team = ReadByte();
620 self.rule = ReadByte();
626 strunzone(self.netname);
627 self.netname = strzone(ReadString());
633 strunzone(self.netname2);
634 self.netname2 = strzone(ReadString());
640 strunzone(self.netname3);
641 self.netname3 = strzone(ReadString());
646 self.lifetime = ReadCoord();
647 self.fadetime = ReadCoord();
648 self.maxdistance = ReadShort();
649 self.hideflags = ReadByte();
655 self.teamradar_icon = (f & 0x7F);
658 self.(teamradar_times[self.teamradar_time_index]) = time;
659 self.teamradar_time_index = (self.teamradar_time_index + 1) % MAX_TEAMRADAR_TIMES;
661 self.teamradar_color_x = ReadByte() / 255.0;
662 self.teamradar_color_y = ReadByte() / 255.0;
663 self.teamradar_color_z = ReadByte() / 255.0;
664 self.helpme = ReadByte() * 0.1;
666 self.helpme += servertime;
669 InterpolateOrigin_Note();
671 self.entremove = Ent_RemoveWaypointSprite;
674 void WaypointSprite_Load_Frames(string ext)
676 float dh, n, i, o, f;
677 string s, sname, sframes;
678 dh = search_begin(strcat("models/sprites/*_frame*", ext), false, false);
681 float ext_len = strlen(ext);
682 n = search_getsize(dh);
683 for(i = 0; i < n; ++i)
685 s = search_getfilename(dh, i);
686 s = substring(s, 15, strlen(s) - 15 - ext_len); // strip models/sprites/ and extension
688 o = strstrofs(s, "_frame", 0);
689 sname = strcat("/spriteframes/", substring(s, 0, o));
690 sframes = substring(s, o + 6, strlen(s) - o - 6);
691 f = stof(sframes) + 1;
692 db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
697 void WaypointSprite_Load()
699 waypointsprite_fadedistance = vlen(mi_scale);
700 waypointsprite_normdistance = autocvar_g_waypointsprite_normdistance;
701 waypointsprite_minscale = autocvar_g_waypointsprite_minscale;
702 waypointsprite_minalpha = autocvar_g_waypointsprite_minalpha;
703 waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent;
704 waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent;
705 waypointsprite_scale = autocvar_g_waypointsprite_scale;
706 waypointsprite_fontsize = autocvar_g_waypointsprite_fontsize;
707 waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha;
708 waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale;
709 waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;
710 waypointsprite_edgeoffset_bottom = autocvar_g_waypointsprite_edgeoffset_bottom;
711 waypointsprite_edgeoffset_left = autocvar_g_waypointsprite_edgeoffset_left;
712 waypointsprite_edgeoffset_right = autocvar_g_waypointsprite_edgeoffset_right;
713 waypointsprite_edgeoffset_top = autocvar_g_waypointsprite_edgeoffset_top;
714 waypointsprite_crosshairfadealpha = autocvar_g_waypointsprite_crosshairfadealpha;
715 waypointsprite_crosshairfadescale = autocvar_g_waypointsprite_crosshairfadescale;
716 waypointsprite_crosshairfadedistance = autocvar_g_waypointsprite_crosshairfadedistance;
717 waypointsprite_distancefadealpha = autocvar_g_waypointsprite_distancefadealpha;
718 waypointsprite_distancefadescale = autocvar_g_waypointsprite_distancefadescale;
719 waypointsprite_distancefadedistance = waypointsprite_fadedistance * autocvar_g_waypointsprite_distancefadedistancemultiplier;
720 waypointsprite_alpha = autocvar_g_waypointsprite_alpha * (1 - autocvar__menu_alpha);
722 if(!waypointsprite_initialized)
724 WaypointSprite_Load_Frames(".tga");
725 WaypointSprite_Load_Frames(".jpg");
726 waypointsprite_initialized = true;
729 waypointsprite_count = waypointsprite_newcount;
730 waypointsprite_newcount = 0;