]> git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/client/miscfunctions.qc
Get VoreTournament code to compile with gmqcc. To be compiled with the same parameter...
[voretournament/voretournament.git] / data / qcsrc / client / miscfunctions.qc
1 float(string text, float handleColors, vector fontSize) stringwidth;\r
2 \r
3 entity players;\r
4 entity teams;\r
5 \r
6 void serverAnnouncer()\r
7 {\r
8         // check for pending announcement, play it and remove it\r
9         if(announce_snd != "")\r
10         {\r
11                 sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/", announce_snd, ".wav"), VOL_BASEVOICE, ATTN_NONE);\r
12                 strunzone(announce_snd);\r
13                 announce_snd = "";\r
14         }\r
15 }\r
16 \r
17 void restartAnnouncer_Think() {\r
18         float countdown_rounded, countdown;\r
19         countdown = getstatf(STAT_GAMESTARTTIME) - time;\r
20         countdown_rounded = floor(0.5 + countdown);\r
21         if(countdown <= 0) {\r
22                 if (!spectatee_status) //do cprint only for players\r
23                         centerprint("^1Begin!");\r
24 \r
25                 sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/begin.wav"), VOL_BASEVOICE, ATTN_NONE);\r
26                 //reset maptime announcers now as well\r
27                 announcer_5min = announcer_1min = FALSE;\r
28 \r
29                 remove(self);\r
30                 return;\r
31         }\r
32         else {\r
33                 if (!spectatee_status) //do cprint only for players\r
34                         centerprint(strcat("^1Game starts in ", ftos(countdown_rounded), " seconds"));\r
35 \r
36                 if(countdown_rounded <= 3 && countdown_rounded >= 1) {\r
37                         sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/", ftos(countdown_rounded), ".wav"), VOL_BASEVOICE, ATTN_NONE);\r
38                 }\r
39 \r
40                 self.nextthink = getstatf(STAT_GAMESTARTTIME) - (countdown - 1);\r
41         }\r
42 }\r
43 \r
44 /**\r
45  * Plays the 1minute or 5 minutes (of maptime) remaining sound, if client wants it\r
46  */\r
47 void maptimeAnnouncer() {\r
48     float timelimit;\r
49     timelimit = getstatf(STAT_TIMELIMIT);\r
50     float timeleft;\r
51     timeleft = max(0, timelimit * 60 + getstatf(STAT_GAMESTARTTIME) - time);\r
52 \r
53     float warmuplimit;\r
54     float warmuptimeleft;\r
55     if(warmup_stage) {\r
56         warmuplimit = cvar("g_warmup_limit");\r
57         if(warmuplimit > 0) {\r
58            warmuptimeleft = max(0, warmuplimit + getstatf(STAT_GAMESTARTTIME) - time); \r
59         }\r
60     }\r
61 \r
62     //5 minute check\r
63     if (cvar("cl_sound_maptime_warning") >= 2) {\r
64         //make sure that after connect (and e.g. 4 minutes left) we will not get a wrong sound\r
65         if(announcer_5min)\r
66         {\r
67                         if(((!warmup_stage || warmuplimit == 0) && timeleft > 300) || (warmup_stage && warmuplimit > 0 && warmuptimeleft > 300))\r
68                                 announcer_5min = FALSE;\r
69         }\r
70         else if (((!warmup_stage || warmuplimit == 0) && timelimit > 0 && timeleft < 300 && timeleft > 299) || (warmup_stage && warmuplimit > 0 && warmuptimeleft < 300 && warmuptimeleft > 299))\r
71         //if we're in warmup mode, check whether there's a warmup timelimit\r
72         if not (warmuplimit == -1 && warmup_stage) {\r
73                         announcer_5min = TRUE;\r
74                         //dprint("i will play the sound, I promise!\n");\r
75                         sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/5minutesremain.wav"), VOL_BASEVOICE, ATTN_NONE);\r
76                 }\r
77     }\r
78 \r
79     //1 minute check\r
80     if (cvar("cl_sound_maptime_warning") == 1 || cvar("cl_sound_maptime_warning") == 3) {\r
81         if (announcer_1min)\r
82         {\r
83                         if(((!warmup_stage || warmuplimit == 0) && timeleft > 60) || (warmup_stage && warmuplimit > 0 && warmuptimeleft > 60))\r
84                                 announcer_1min = FALSE;\r
85         }\r
86         else if (((!warmup_stage || warmuplimit == 0) && timelimit > 0 && timeleft < 60) || (warmup_stage && warmuplimit > 0 && warmuptimeleft < 60))\r
87         //if we're in warmup mode, check whether there's a warmup timelimit\r
88         if not (warmuplimit == -1 && warmup_stage) {\r
89                         announcer_1min = TRUE;\r
90                         sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/1minuteremains.wav"), VOL_BASEVOICE, ATTN_NONE);\r
91         }\r
92         }\r
93 }\r
94 \r
95  /**\r
96  * Announce carried items (e.g. flags in CTF).\r
97  */\r
98 float redflag_prev;\r
99 float blueflag_prev;\r
100 void carrierAnnouncer() {\r
101         float stat_items, redflag, blueflag;\r
102         float pickup;\r
103         string item;\r
104 \r
105         if not(cvar("cl_notify_carried_items"))\r
106                 return;\r
107 \r
108         stat_items = getstati(STAT_ITEMS);\r
109 \r
110         redflag = (stat_items/IT_RED_FLAG_TAKEN) & 3;\r
111         blueflag = (stat_items/IT_BLUE_FLAG_TAKEN) & 3;\r
112 \r
113         if (redflag == 3 && redflag != redflag_prev) {\r
114                 item = "^1RED^7 flag";\r
115                 pickup = (redflag_prev == 2);\r
116         }\r
117 \r
118         if (blueflag == 3 && blueflag != blueflag_prev) {\r
119                 item = "^4BLUE^7 flag";\r
120                 pickup = (blueflag_prev == 2);\r
121         }\r
122 \r
123         if (item)\r
124         {\r
125                 if (pickup) {\r
126                         if (cvar("cl_notify_carried_items") & 2)\r
127                                 centerprint(strcat("You picked up the ", item, "!"));\r
128                 }\r
129                 else {\r
130                         if (cvar("cl_notify_carried_items") & 1)\r
131                                 centerprint(strcat("You got the ", item, "!"));\r
132                 }\r
133         }\r
134 \r
135         blueflag_prev = blueflag;\r
136         redflag_prev = redflag;\r
137 }\r
138 \r
139 /**\r
140  * Add all future announcer sounds precaches here.\r
141  * TODO: announcer queues\r
142  */\r
143 void Announcer_Precache () {\r
144         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/1minuteremains.wav"));\r
145         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/5minutesremain.wav"));\r
146 \r
147         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/airshot.wav"));\r
148         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/03kills.wav"));\r
149         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/05kills.wav"));\r
150         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/10kills.wav"));\r
151         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/15kills.wav"));\r
152         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/20kills.wav"));\r
153         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/25kills.wav"));\r
154         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/30kills.wav"));\r
155         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/botlike.wav"));\r
156         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/yoda.wav"));\r
157         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/amazing.wav"));\r
158         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/awesome.wav"));\r
159         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/headshot.wav"));\r
160         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/impressive.wav"));\r
161 \r
162         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/prepareforbattle.wav"));\r
163         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/begin.wav"));\r
164         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/timeoutcalled.wav"));\r
165         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/1fragleft.wav"));\r
166         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/2fragsleft.wav"));\r
167         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/3fragsleft.wav"));\r
168         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/terminated.wav"));\r
169 \r
170         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/1.wav"));\r
171         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/2.wav"));\r
172         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/3.wav"));\r
173         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/4.wav"));\r
174         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/5.wav"));\r
175         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/6.wav"));\r
176         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/7.wav"));\r
177         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/8.wav"));\r
178         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/9.wav"));\r
179         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/10.wav"));\r
180 \r
181         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/lastsecond.wav"));\r
182         precache_sound (strcat("announcer/", cvar_string("cl_announcer"), "/narrowly.wav"));\r
183 \r
184         precache_sound (strcat("helper/", cvar_string("cl_helper_voice"), "/health.wav"));\r
185         precache_sound (strcat("helper/", cvar_string("cl_helper_voice"), "/armor.wav"));\r
186         precache_sound (strcat("helper/", cvar_string("cl_helper_voice"), "/ammo.wav"));\r
187         precache_sound (strcat("helper/", cvar_string("cl_helper_voice"), "/speed.wav"));\r
188         precache_sound (strcat("helper/", cvar_string("cl_helper_voice"), "/stomachload.wav"));\r
189 }\r
190 \r
191 void AuditLists()\r
192 {\r
193         entity e;\r
194         entity prev;\r
195 \r
196         prev = players;\r
197         for(e = prev.sort_next; e; prev = e, e = e.sort_next)\r
198         {\r
199                 if(prev != e.sort_prev)\r
200                         error(strcat("sort list chain error\nplease submit the output of 'prvm_edicts client' to the developers"));\r
201         }\r
202 \r
203         prev = teams;\r
204         for(e = prev.sort_next; e; prev = e, e = e.sort_next)\r
205         {\r
206                 if(prev != e.sort_prev)\r
207                         error(strcat("sort list chain error\nplease submit the output of 'prvm_edicts client' to the developers"));\r
208         }\r
209 }\r
210 \r
211 \r
212 float RegisterPlayer(entity player)\r
213 {\r
214         entity pl;\r
215         AuditLists();\r
216         for(pl = players.sort_next; pl; pl = pl.sort_next)\r
217                 if(pl == player)\r
218                         error("Player already registered!");\r
219         player.sort_next = players.sort_next;\r
220         player.sort_prev = players;\r
221         if(players.sort_next)\r
222                 players.sort_next.sort_prev = player;\r
223         players.sort_next = player;\r
224         AuditLists();\r
225         return true;\r
226 }\r
227 \r
228 void RemovePlayer(entity player)\r
229 {\r
230         entity pl, parent;\r
231         AuditLists();\r
232         parent = players;\r
233         for(pl = players.sort_next; pl && pl != player; pl = pl.sort_next)\r
234                 parent = pl;\r
235 \r
236         if(!pl)\r
237         {\r
238                 error("Trying to remove a player which is not in the playerlist!");\r
239                 return;\r
240         }\r
241         parent.sort_next = player.sort_next;\r
242         if(player.sort_next)\r
243                 player.sort_next.sort_prev = parent;\r
244         AuditLists();\r
245 }\r
246 \r
247 void MoveToLast(entity e)\r
248 {\r
249         AuditLists();\r
250         other = e.sort_next;\r
251         while(other)\r
252         {\r
253                 SORT_SWAP(other, e);\r
254                 other = e.sort_next;\r
255         }\r
256         AuditLists();\r
257 }\r
258 \r
259 float RegisterTeam(entity Team)\r
260 {\r
261         entity tm;\r
262         AuditLists();\r
263         for(tm = teams.sort_next; tm; tm = tm.sort_next)\r
264                 if(tm == Team)\r
265                         error("Team already registered!");\r
266         Team.sort_next = teams.sort_next;\r
267         Team.sort_prev = teams;\r
268         if(teams.sort_next)\r
269                 teams.sort_next.sort_prev = Team;\r
270         teams.sort_next = Team;\r
271         AuditLists();\r
272         return true;\r
273 }\r
274 \r
275 void RemoveTeam(entity Team)\r
276 {\r
277         entity tm, parent;\r
278         AuditLists();\r
279         parent = teams;\r
280         for(tm = teams.sort_next; tm && tm != Team; tm = tm.sort_next)\r
281                 parent = tm;\r
282 \r
283         if(!tm)\r
284         {\r
285                 print("Trying to remove a team which is not in the teamlist!");\r
286                 return;\r
287         }\r
288         parent.sort_next = Team.sort_next;\r
289         if(Team.sort_next)\r
290                 Team.sort_next.sort_prev = parent;\r
291         AuditLists();\r
292 }\r
293 \r
294 entity GetTeam(float Team, float add)\r
295 {\r
296         float num;\r
297         entity tm;\r
298         num = (Team == COLOR_SPECTATOR) ? 16 : Team;\r
299         if(teamslots[num])\r
300                 return teamslots[num];\r
301         if not(add)\r
302                 return NULL;\r
303         tm = spawn();\r
304         tm.team = Team;\r
305         teamslots[num] = tm;\r
306         RegisterTeam(tm);\r
307         return tm;\r
308 }\r
309 \r
310 void CSQC_CheckEngine()\r
311 {\r
312         sbar_font = FONT_USER+1;\r
313         sbar_bigfont = FONT_USER+2;\r
314 }\r
315 \r
316 vector Sbar_GetFontsize(string cvarname)\r
317 {\r
318         vector v;\r
319         v = stov(cvar_string(cvarname));\r
320         if(v_x == 0)\r
321                 v = '8 8 0';\r
322         if(v_y == 0)\r
323                 v_y = v_x;\r
324         v_z = 0;\r
325         return v;\r
326 }\r
327 \r
328 float Sbar_GetWidth(float teamcolumnwidth)\r
329 {\r
330         float f;\r
331         f = cvar("sbar_width");\r
332         if(f == 0)\r
333                 f = 640;\r
334         if(f < 320)\r
335                 f = 320;\r
336         if(f > vid_conwidth - 2 * teamcolumnwidth)\r
337                 f = vid_conwidth - 2 * teamcolumnwidth;\r
338         return f;\r
339 }\r
340 \r
341 float PreviewExists(string name)\r
342 {\r
343         float f;\r
344         string file;\r
345 \r
346         if(cvar("cl_readpicture_force"))\r
347                 return false;\r
348 \r
349         file = strcat(name, ".tga");\r
350         f = fopen(file, FILE_READ);\r
351         if(f >= 0)\r
352         {\r
353                 fclose(f);\r
354                 return true;\r
355         }\r
356         file = strcat(name, ".png");\r
357         f = fopen(file, FILE_READ);\r
358         if(f >= 0)\r
359         {\r
360                 fclose(f);\r
361                 return true;\r
362         }\r
363         file = strcat(name, ".jpg");\r
364         f = fopen(file, FILE_READ);\r
365         if(f >= 0)\r
366         {\r
367                 fclose(f);\r
368                 return true;\r
369         }\r
370         file = strcat(name, ".pcx");\r
371         f = fopen(file, FILE_READ);\r
372         if(f >= 0)\r
373         {\r
374                 fclose(f);\r
375                 return true;\r
376         }\r
377         return false;\r
378 }\r
379 \r
380 vector rotate(vector v, float a)\r
381 {\r
382         vector w;\r
383         // FTEQCC SUCKS AGAIN\r
384         w_x =      v_x * cos(a) + v_y * sin(a);\r
385         w_y = -1 * v_x * sin(a) + v_y * cos(a);\r
386         return w;\r
387 }\r
388 \r
389 float ColorTranslateMode;\r
390 \r
391 string ColorTranslateRGB(string s)\r
392 {\r
393         if(ColorTranslateMode & 1)\r
394                 return strdecolorize(s);\r
395         else\r
396                 return s;\r
397 }\r
398 \r
399 string Team_ColorCode(float teamid)\r
400 {\r
401     if (teamid == COLOR_TEAM1)\r
402         return "^1";\r
403     else if (teamid == COLOR_TEAM2)\r
404         return "^4";\r
405     else if (teamid == COLOR_TEAM3)\r
406         return "^3";\r
407     else if (teamid == COLOR_TEAM4)\r
408         return "^6";\r
409     else\r
410         return "^7";\r
411 }\r
412 \r
413 // decolorizes and team colors the player name when needed\r
414 string playername(string thename, float teamid)\r
415 {\r
416     string t;\r
417     if (teamplay)\r
418     {\r
419         t = Team_ColorCode(teamid);\r
420         return strcat(t, strdecolorize(thename));\r
421     }\r
422     else\r
423         return strdecolorize(thename);\r
424 }\r
425 \r
426 float cvar_or(string cv, float v)\r
427 {\r
428         string s;\r
429         s = cvar_string(cv);\r
430         if(s == "")\r
431                 return v;\r
432         else\r
433                 return stof(s);\r
434 }\r
435 \r
436 vector project_3d_to_2d(vector vec)\r
437 {\r
438         vec = cs_project(vec);\r
439         if(cs_project_is_b0rked > 0)\r
440         {\r
441                 vec_x *= vid_conwidth / vid_width;\r
442                 vec_y *= vid_conheight / vid_height;\r
443         }\r
444         return vec;\r
445 }\r
446 \r
447 void dummyfunction(float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8)\r
448 {\r
449 }\r
450 \r
451 float expandingbox_sizefactor_from_fadelerp(float fadelerp)\r
452 {\r
453         return 1.2 / (1.2 - fadelerp);\r
454 }\r
455 \r
456 vector expandingbox_resize_centered_box_offset(float sz, vector boxsize, float boxxsizefactor)\r
457 {\r
458         boxsize_x *= boxxsizefactor; // easier interface for text\r
459         return boxsize * (0.5 * (1 - sz));\r
460 }\r
461 \r
462 void drawborderlines(float thickness, vector pos, vector dim, vector color, float alpha, float drawflag)\r
463 {\r
464         vector line_dim;\r
465 \r
466         // left and right lines\r
467         pos_x -= thickness;\r
468         line_dim_x = thickness;\r
469         line_dim_y = dim_y;\r
470         drawfill(pos, line_dim, color, alpha, drawflag);\r
471         drawfill(pos + (dim_x + thickness) * '1 0 0', line_dim, color, alpha, drawflag);\r
472 \r
473         // upper and lower lines\r
474         pos_y -= thickness;\r
475         line_dim_x = dim_x + thickness * 2; // make upper and lower lines longer\r
476         line_dim_y = thickness;\r
477         drawfill(pos, line_dim, color, alpha, drawflag);\r
478         drawfill(pos + (dim_y + thickness) * '0 1 0', line_dim, color, alpha, drawflag);\r
479 }\r
480 \r
481 void drawpic_tiled(vector pos, string pic, vector sz, vector area, vector color, float alpha, float drawflag)\r
482 {\r
483         vector current_pos, end_pos, new_size, ratio;\r
484         end_pos = pos + area;\r
485 \r
486         current_pos_y = pos_y;\r
487         while (current_pos_y < end_pos_y)\r
488         {\r
489                 current_pos_x = pos_x;\r
490                 while (current_pos_x < end_pos_x)\r
491                 {\r
492                         new_size_x = min(sz_x, end_pos_x - current_pos_x);\r
493                         new_size_y = min(sz_y, end_pos_y - current_pos_y);\r
494                         ratio_x = new_size_x / sz_x;\r
495                         ratio_y = new_size_y / sz_y;\r
496                         drawsubpic(current_pos, new_size, pic, '0 0 0', ratio, color, alpha, drawflag);\r
497                         current_pos_x += sz_x;\r
498                 }\r
499                 current_pos_y += sz_y;\r
500         }\r
501 }\r
502 \r
503 void drawpic_expanding(vector position, string pic, vector scale, vector rgb, float alpha, float flag, float fadelerp)\r
504 {\r
505         float sz;\r
506         sz = expandingbox_sizefactor_from_fadelerp(fadelerp);\r
507 \r
508         drawpic(position + expandingbox_resize_centered_box_offset(sz, scale, 1), pic, scale * sz, rgb, alpha * (1 - fadelerp), flag);\r
509 }\r
510 \r
511 void drawpic_expanding_two(vector position, string pic, vector scale, vector rgb, float alpha, float flag, float fadelerp)\r
512 {\r
513         drawpic_expanding(position, pic, scale, rgb, alpha, flag, fadelerp);\r
514         drawpic(position, pic, scale, rgb, alpha * fadelerp, flag);\r
515 }\r
516 \r
517 vector drawfontscale;\r
518 void drawstring_expanding(vector position, string text, vector scale, vector rgb, float alpha, float flag, float fadelerp)\r
519 {\r
520         float sz;\r
521         sz = expandingbox_sizefactor_from_fadelerp(fadelerp);\r
522 \r
523         if(cvar("menu_font_size_snapping_fix"))\r
524                 drawfontscale = sz * '1 1 0';\r
525         else\r
526                 drawfontscale = '1 1 0';\r
527         dummyfunction(0, 0, 0, 0, 0, 0, 0, 0);\r
528         drawstring(position + expandingbox_resize_centered_box_offset(sz, scale, stringwidth(text, FALSE, scale * (sz / drawfontscale_x)) / (scale_x * sz)), text, scale * (sz / drawfontscale_x), rgb, alpha * (1 - fadelerp), flag);\r
529         // width parameter:\r
530         //    (scale_x * sz / drawfontscale_x) * drawfontscale_x * SIZE1 / (scale_x * sz)\r
531         //    SIZE1\r
532 \r
533         if(cvar("menu_font_size_snapping_fix"))\r
534                 drawfontscale = '1 1 0';\r
535 }\r
536 \r
537 void drawcolorcodedstring_expanding(vector position, string text, vector scale, float alpha, float flag, float fadelerp)\r
538 {\r
539         float sz;\r
540         sz = expandingbox_sizefactor_from_fadelerp(fadelerp);\r
541 \r
542         if(cvar("menu_font_size_snapping_fix"))\r
543                 drawfontscale = sz * '1 1 0';\r
544         else\r
545                 drawfontscale = '1 1 0';\r
546         dummyfunction(0, 0, 0, 0, 0, 0, 0, 0);\r
547         drawcolorcodedstring(position + expandingbox_resize_centered_box_offset(sz, scale, stringwidth(text, TRUE, scale * (sz / drawfontscale_x)) / (scale_x * sz)), text, scale * (sz / drawfontscale_x), alpha * (1 - fadelerp), flag);\r
548 \r
549         if(cvar("menu_font_size_snapping_fix"))\r
550                 drawfontscale = '1 1 0';\r
551 }\r
552 \r
553 // this draws the triangles of a model DIRECTLY. Don't expect high performance, really...\r
554 void PolyDrawModel(entity e)\r
555 {\r
556         float i_s, i_t;\r
557         float n_t;\r
558         vector tri;\r
559         string tex;\r
560         for(i_s = 0; ; ++i_s)\r
561         {\r
562                 tex = getsurfacetexture(e, i_s);\r
563                 if not(tex)\r
564                         break; // this is beyond the last one\r
565                 n_t = getsurfacenumtriangles(e, i_s);\r
566                 for(i_t = 0; i_t < n_t; ++i_t)\r
567                 {\r
568                         tri = getsurfacetriangle(e, i_s, i_t);\r
569                         R_BeginPolygon(tex, 0);\r
570                         R_PolygonVertex(getsurfacepoint(e, i_s, tri_x), getsurfacepointattribute(e, i_s, tri_x, SPA_TEXCOORDS0), '1 1 1', 1);\r
571                         R_PolygonVertex(getsurfacepoint(e, i_s, tri_y), getsurfacepointattribute(e, i_s, tri_y, SPA_TEXCOORDS0), '1 1 1', 1);\r
572                         R_PolygonVertex(getsurfacepoint(e, i_s, tri_z), getsurfacepointattribute(e, i_s, tri_z, SPA_TEXCOORDS0), '1 1 1', 1);\r
573                         R_EndPolygon();\r
574                 }\r
575         }\r
576 }\r
577 \r
578 void DrawCircleClippedPic(vector centre, float radius, string pic, float f, vector rgb, float a, float drawflag)\r
579 {\r
580         float x, y, q, d;\r
581         vector ringsize, v, t;\r
582         ringsize = radius * '1 1 0';\r
583 \r
584         x = cos(f * 2 * M_PI);\r
585         y = sin(f * 2 * M_PI);\r
586         q = fabs(x) + fabs(y);\r
587         x /= q;\r
588         y /= q;\r
589 \r
590         if(f >= 1)\r
591         {\r
592                 // draw full rectangle\r
593                 R_BeginPolygon(pic, drawflag);\r
594                         v = centre;                     t = '0.5 0.5 0';\r
595                         v_x += 0.5 * ringsize_x;        t += '0.5 0.5 0';\r
596                         R_PolygonVertex(v, t, rgb, a);\r
597 \r
598                         v = centre;                     t = '0.5 0.5 0';\r
599                         v_y += 0.5 * ringsize_y;        t += '0.5 -0.5 0';\r
600                         R_PolygonVertex(v, t, rgb, a);\r
601 \r
602                         v = centre;                     t = '0.5 0.5 0';\r
603                         v_x -= 0.5 * ringsize_x;        t -= '0.5 0.5 0';\r
604                         R_PolygonVertex(v, t, rgb, a);\r
605 \r
606                         v = centre;                     t = '0.5 0.5 0';\r
607                         v_y -= 0.5 * ringsize_y;        t -= '0.5 -0.5 0';\r
608                         R_PolygonVertex(v, t, rgb, a);\r
609                 R_EndPolygon();\r
610 \r
611                 d = q - 1;\r
612                 if(d > 0)\r
613                 {\r
614                         R_BeginPolygon(pic, drawflag);\r
615                                 v = centre;                     t = '0.5 0.5 0';\r
616                                 R_PolygonVertex(v, t, rgb, a);\r
617 \r
618                                 v = centre;                     t = '0.5 0.5 0';\r
619                                 v_x += 0.5 * ringsize_x;        t += '0.5 0.5 0';\r
620                                 R_PolygonVertex(v, t, rgb, a);\r
621                 }\r
622         }\r
623         else if(f > 0.75)\r
624         {\r
625                 // draw upper and first triangle\r
626                 R_BeginPolygon(pic, drawflag);\r
627                         v = centre;                     t = '0.5 0.5 0';\r
628                         v_x += 0.5 * ringsize_x;        t += '0.5 0.5 0';\r
629                         R_PolygonVertex(v, t, rgb, a);\r
630 \r
631                         v = centre;                     t = '0.5 0.5 0';\r
632                         v_y += 0.5 * ringsize_y;        t += '0.5 -0.5 0';\r
633                         R_PolygonVertex(v, t, rgb, a);\r
634 \r
635                         v = centre;                     t = '0.5 0.5 0';\r
636                         v_x -= 0.5 * ringsize_x;        t -= '0.5 0.5 0';\r
637                         R_PolygonVertex(v, t, rgb, a);\r
638                 R_EndPolygon();\r
639                 R_BeginPolygon(pic, drawflag);\r
640                         v = centre;                     t = '0.5 0.5 0';\r
641                         R_PolygonVertex(v, t, rgb, a);\r
642 \r
643                         v = centre;                     t = '0.5 0.5 0';\r
644                         v_x -= 0.5 * ringsize_x;        t -= '0.5 0.5 0';\r
645                         R_PolygonVertex(v, t, rgb, a);\r
646 \r
647                         v = centre;                     t = '0.5 0.5 0';\r
648                         v_y -= 0.5 * ringsize_y;        t -= '0.5 -0.5 0';\r
649                         R_PolygonVertex(v, t, rgb, a);\r
650 \r
651                 d = q - 0.75;\r
652                 if(d <= 0)\r
653                         R_EndPolygon();\r
654         }\r
655         else if(f > 0.5)\r
656         {\r
657                 // draw upper triangle\r
658                 R_BeginPolygon(pic, drawflag);\r
659                         v = centre;                     t = '0.5 0.5 0';\r
660                         v_x += 0.5 * ringsize_x;        t += '0.5 0.5 0';\r
661                         R_PolygonVertex(v, t, rgb, a);\r
662 \r
663                         v = centre;                     t = '0.5 0.5 0';\r
664                         v_y += 0.5 * ringsize_y;        t += '0.5 -0.5 0';\r
665                         R_PolygonVertex(v, t, rgb, a);\r
666 \r
667                         v = centre;                     t = '0.5 0.5 0';\r
668                         v_x -= 0.5 * ringsize_x;        t -= '0.5 0.5 0';\r
669                         R_PolygonVertex(v, t, rgb, a);\r
670                 R_EndPolygon();\r
671 \r
672                 d = q - 0.5;\r
673                 if(d > 0)\r
674                 {\r
675                         R_BeginPolygon(pic, drawflag);\r
676                                 v = centre;                     t = '0.5 0.5 0';\r
677                                 R_PolygonVertex(v, t, rgb, a);\r
678 \r
679                                 v = centre;                     t = '0.5 0.5 0';\r
680                                 v_x -= 0.5 * ringsize_x;        t -= '0.5 0.5 0';\r
681                                 R_PolygonVertex(v, t, rgb, a);\r
682                 }\r
683         }\r
684         else if(f > 0.25)\r
685         {\r
686                 // draw first triangle\r
687                 R_BeginPolygon(pic, drawflag);\r
688                         v = centre;                     t = '0.5 0.5 0';\r
689                         R_PolygonVertex(v, t, rgb, a);\r
690 \r
691                         v = centre;                     t = '0.5 0.5 0';\r
692                         v_x += 0.5 * ringsize_x;        t += '0.5 0.5 0';\r
693                         R_PolygonVertex(v, t, rgb, a);\r
694 \r
695                         v = centre;                     t = '0.5 0.5 0';\r
696                         v_y += 0.5 * ringsize_y;        t += '0.5 -0.5 0';\r
697                         R_PolygonVertex(v, t, rgb, a);\r
698 \r
699                 d = q - 0.25;\r
700                 if(d <= 0)\r
701                         R_EndPolygon();\r
702         }\r
703         else\r
704         {\r
705                 d = q;\r
706                 if(d > 0)\r
707                 {\r
708                         R_BeginPolygon(pic, drawflag);\r
709                                 v = centre;                     t = '0.5 0.5 0';\r
710                                 R_PolygonVertex(v, t, rgb, a);\r
711 \r
712                                 v = centre;                     t = '0.5 0.5 0';\r
713                                 v_x += 0.5 * ringsize_x;        t += '0.5 0.5 0';\r
714                                 R_PolygonVertex(v, t, rgb, a);\r
715                 }\r
716         }\r
717 \r
718         if(d > 0)\r
719         {\r
720                         v = centre;                     t = '0.5 0.5 0';\r
721                         v_x += x * 0.5 * ringsize_x;    t += x * '0.5 0.5 0';\r
722                         v_y += y * 0.5 * ringsize_y;    t += y * '0.5 -0.5 0';\r
723                         R_PolygonVertex(v, t, rgb, a);\r
724                 R_EndPolygon();\r
725         }\r
726 }\r
727 \r
728 const vector GETPLAYERORIGIN_ERROR = '1123581321 2357111317 3141592653'; // way out of bounds for anything on the map\r
729 vector getplayerorigin(float pl)\r
730 {\r
731         string s;\r
732         entity e;\r
733 \r
734         s = getplayerkey(pl, "TEMPHACK_origin");\r
735         if(s != "")\r
736                 return stov(s);\r
737 \r
738         e = entcs_receiver[pl];\r
739         if(e)\r
740                 return e.origin;\r
741 \r
742         return GETPLAYERORIGIN_ERROR;\r
743 }\r