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 "waypoint": return _("Waypoint");
208 case "ons-gen-red": return _("Generator");
209 case "ons-gen-blue": return _("Generator");
210 case "ons-gen-shielded": return _("Generator");
211 case "ons-cp-neut": return _("Control point");
212 case "ons-cp-red": return _("Control point");
213 case "ons-cp-blue": return _("Control point");
214 case "ons-cp-atck-neut": return _("Control point");
215 case "ons-cp-atck-red": return _("Control point");
216 case "ons-cp-atck-blue": return _("Control point");
217 case "ons-cp-dfnd-red": return _("Control point");
218 case "ons-cp-dfnd-blue": return _("Control point");
219 case "race-checkpoint": return _("Checkpoint");
220 case "race-finish": return _("Finish");
221 case "race-start": return _("Start");
222 case "race-start-finish": return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
223 case "goal": return _("Goal");
224 case "nb-ball": return _("Ball");
225 case "ka-ball": return _("Ball");
226 case "ka-ballcarrier": return _("Ball carrier");
227 case "dom-neut": return _("Control point");
228 case "dom-red": return _("Control point");
229 case "dom-blue": return _("Control point");
230 case "dom-yellow": return _("Control point");
231 case "dom-pink": return _("Control point");
232 case "item-invis": return _("Invisibility");
233 case "item-extralife": return _("Extra life");
234 case "item-speed": return _("Speed");
235 case "item-strength": return _("Strength");
236 case "item-shield": return _("Shield");
237 case "item-fuelregen": return _("Fuel regen");
238 case "item-jetpack": return _("Jet Pack");
239 case "frozen": return _("Frozen!");
240 case "tagged-target": return _("Tagged");
241 case "vehicle": return _("Vehicle");
242 case "intruder": return _("Intruder!");
247 vector fixrgbexcess_move(vector rgb, vector src, vector dst)
249 vector yvec = '0.299 0.587 0.114';
250 return rgb + dst * ((src * yvec) / (dst * yvec)) * ((rgb - '1 1 1') * src);
252 vector fixrgbexcess(vector rgb)
256 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 1');
259 rgb = fixrgbexcess_move(rgb, '0 1 0', '0 0 1');
265 rgb = fixrgbexcess_move(rgb, '0 0 1', '0 1 0');
272 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 1');
275 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 0 1');
281 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 0 0');
288 rgb = fixrgbexcess_move(rgb, '0 0 1', '1 1 0');
291 rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 0');
297 rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 0');
305 void Draw_WaypointSprite()
311 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
315 if(self.hideflags & 2)
316 return; // radar only
318 if(autocvar_cl_hidewaypoints >= 2)
321 if(self.hideflags & 1)
322 if(autocvar_cl_hidewaypoints)
323 return; // fixed waypoint
325 InterpolateOrigin_Do();
327 t = GetPlayerColor(player_localnum) + 1;
334 case SPRITERULE_DEFAULT:
338 spriteimage = self.netname;
343 spriteimage = self.netname;
345 case SPRITERULE_TEAMPLAY:
346 if(t == NUM_SPECTATOR + 1)
347 spriteimage = self.netname3;
348 else if(self.team == t)
349 spriteimage = self.netname2;
351 spriteimage = self.netname;
354 error("Invalid waypointsprite rule!");
358 if(spriteimage == "")
361 ++waypointsprite_newcount;
364 dist = vlen(self.origin - view_origin);
367 a = self.alpha * autocvar_hud_panel_fg_alpha;
369 if(self.maxdistance > waypointsprite_normdistance)
370 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
371 else if(self.maxdistance > 0)
372 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
375 rgb = self.teamradar_color;
376 rgb = spritelookupcolor(spriteimage, rgb);
379 self.teamradar_color = '1 0 1';
380 printf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage);
383 if(time - floor(time) > 0.5)
385 if(self.helpme && time < self.helpme)
386 a *= SPRITE_HELPME_BLINK;
388 a *= spritelookupblinkvalue(spriteimage);
400 rgb = fixrgbexcess(rgb);
405 o = project_3d_to_2d(self.origin);
407 || o.x < (vid_conwidth * waypointsprite_edgeoffset_left)
408 || o.y < (vid_conheight * waypointsprite_edgeoffset_top)
409 || o.x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
410 || o.y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
412 // scale it to be just in view
416 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
417 ang = atan2(-d.x, -d.y);
421 f1 = d.x / vid_conwidth;
422 f2 = d.y / vid_conheight;
424 if(max(f1, -f1) > max(f2, -f2))
429 d = d * ((0.5 - waypointsprite_edgeoffset_right) / f1);
434 d = d * (-(0.5 - waypointsprite_edgeoffset_left) / f1);
442 d = d * ((0.5 - waypointsprite_edgeoffset_bottom) / f2);
447 d = d * (-(0.5 - waypointsprite_edgeoffset_top) / f2);
451 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
459 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
460 ang = atan2(-d.x, -d.y);
465 float edgedistance_min, crosshairdistance;
466 edgedistance_min = min((o.y - (vid_conheight * waypointsprite_edgeoffset_top)),
467 (o.x - (vid_conwidth * waypointsprite_edgeoffset_left)),
468 (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o.x,
469 (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o.y);
472 vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
474 crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
476 t = waypointsprite_scale * vidscale;
477 a *= waypointsprite_alpha;
480 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
481 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
483 if (edgedistance_min < waypointsprite_edgefadedistance) {
484 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
485 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
487 if(crosshairdistance < waypointsprite_crosshairfadedistance) {
488 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
489 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
492 if(self.build_finished)
494 if(time < self.build_finished + 0.25)
496 if(time < self.build_started)
497 self.health = self.build_starthealth;
498 else if(time < self.build_finished)
499 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
507 o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
510 if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
513 txt = spritelookuptext(spriteimage);
514 if(self.helpme && time < self.helpme)
515 txt = sprintf(_("%s needing help!"), txt);
516 if(autocvar_g_waypointsprite_uppercase)
517 txt = strtoupper(txt);
519 draw_beginBoldFont();
522 o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
525 if(self.build_finished)
530 marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize;
532 marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize;
539 SPRITE_HEALTHBAR_WIDTH * t,
540 SPRITE_HEALTHBAR_HEIGHT * t,
542 SPRITE_HEALTHBAR_BORDER * t,
545 a * SPRITE_HEALTHBAR_BORDERALPHA,
547 a * SPRITE_HEALTHBAR_HEALTHALPHA,
553 o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
558 void Ent_RemoveWaypointSprite()
561 strunzone(self.netname);
563 strunzone(self.netname2);
565 strunzone(self.netname3);
568 void Ent_WaypointSprite()
571 sendflags = ReadByte();
574 self.spawntime = time;
576 self.draw2d = Draw_WaypointSprite;
578 InterpolateOrigin_Undo();
579 self.iflags |= IFLAG_ORIGIN;
586 self.health = t / 191.0;
587 self.build_finished = 0;
591 t = (t - 192) * 256 + ReadByte();
592 self.build_started = servertime;
593 if(self.build_finished)
594 self.build_starthealth = bound(0, self.health, 1);
596 self.build_starthealth = 0;
597 self.build_finished = servertime + t / 32;
603 self.build_finished = 0;
608 // unfortunately, this needs to be exact (for the 3D display)
609 self.origin_x = ReadCoord();
610 self.origin_y = ReadCoord();
611 self.origin_z = ReadCoord();
612 setorigin(self, self.origin);
617 self.team = ReadByte();
618 self.rule = ReadByte();
624 strunzone(self.netname);
625 self.netname = strzone(ReadString());
631 strunzone(self.netname2);
632 self.netname2 = strzone(ReadString());
638 strunzone(self.netname3);
639 self.netname3 = strzone(ReadString());
644 self.lifetime = ReadCoord();
645 self.fadetime = ReadCoord();
646 self.maxdistance = ReadShort();
647 self.hideflags = ReadByte();
653 self.teamradar_icon = (f & 0x7F);
656 self.(teamradar_times[self.teamradar_time_index]) = time;
657 self.teamradar_time_index = (self.teamradar_time_index + 1) % MAX_TEAMRADAR_TIMES;
659 self.teamradar_color_x = ReadByte() / 255.0;
660 self.teamradar_color_y = ReadByte() / 255.0;
661 self.teamradar_color_z = ReadByte() / 255.0;
662 self.helpme = ReadByte() * 0.1;
664 self.helpme += servertime;
667 InterpolateOrigin_Note();
669 self.entremove = Ent_RemoveWaypointSprite;
672 void WaypointSprite_Load_Frames(string ext)
674 float dh, n, i, o, f;
675 string s, sname, sframes;
676 dh = search_begin(strcat("models/sprites/*_frame*", ext), false, false);
679 float ext_len = strlen(ext);
680 n = search_getsize(dh);
681 for(i = 0; i < n; ++i)
683 s = search_getfilename(dh, i);
684 s = substring(s, 15, strlen(s) - 15 - ext_len); // strip models/sprites/ and extension
686 o = strstrofs(s, "_frame", 0);
687 sname = strcat("/spriteframes/", substring(s, 0, o));
688 sframes = substring(s, o + 6, strlen(s) - o - 6);
689 f = stof(sframes) + 1;
690 db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
695 void WaypointSprite_Load()
697 waypointsprite_fadedistance = vlen(mi_scale);
698 waypointsprite_normdistance = autocvar_g_waypointsprite_normdistance;
699 waypointsprite_minscale = autocvar_g_waypointsprite_minscale;
700 waypointsprite_minalpha = autocvar_g_waypointsprite_minalpha;
701 waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent;
702 waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent;
703 waypointsprite_scale = autocvar_g_waypointsprite_scale;
704 waypointsprite_fontsize = autocvar_g_waypointsprite_fontsize;
705 waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha;
706 waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale;
707 waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;
708 waypointsprite_edgeoffset_bottom = autocvar_g_waypointsprite_edgeoffset_bottom;
709 waypointsprite_edgeoffset_left = autocvar_g_waypointsprite_edgeoffset_left;
710 waypointsprite_edgeoffset_right = autocvar_g_waypointsprite_edgeoffset_right;
711 waypointsprite_edgeoffset_top = autocvar_g_waypointsprite_edgeoffset_top;
712 waypointsprite_crosshairfadealpha = autocvar_g_waypointsprite_crosshairfadealpha;
713 waypointsprite_crosshairfadescale = autocvar_g_waypointsprite_crosshairfadescale;
714 waypointsprite_crosshairfadedistance = autocvar_g_waypointsprite_crosshairfadedistance;
715 waypointsprite_distancefadealpha = autocvar_g_waypointsprite_distancefadealpha;
716 waypointsprite_distancefadescale = autocvar_g_waypointsprite_distancefadescale;
717 waypointsprite_distancefadedistance = waypointsprite_fadedistance * autocvar_g_waypointsprite_distancefadedistancemultiplier;
718 waypointsprite_alpha = autocvar_g_waypointsprite_alpha * (1 - autocvar__menu_alpha);
720 if(!waypointsprite_initialized)
722 WaypointSprite_Load_Frames(".tga");
723 WaypointSprite_Load_Frames(".jpg");
724 waypointsprite_initialized = true;
727 waypointsprite_count = waypointsprite_newcount;
728 waypointsprite_newcount = 0;