]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/miscfunctions.qc
fix droptofloor parameters
[divverent/nexuiz.git] / data / qcsrc / server / miscfunctions.qc
1 float logfile_open;
2 float logfile;
3
4 void(string s) bcenterprint
5 {
6         entity head;
7         head = find(world, classname, "player");
8         while(head)
9         {
10                 if(clienttype(head) == CLIENTTYPE_REAL)
11                         centerprint(head, s);
12                 head = find(head, classname, "player");
13         }
14 }
15
16 void(string s, float check_dangerous) ServerConsoleEcho =
17 {
18         local string ch;
19         if (checkextension("DP_SV_PRINT"))
20                 print(s);
21         else
22         {
23                 localcmd("echo \"");
24                 if(check_dangerous)
25                 {
26                         while(strlen(s))
27                         {
28                                 ch = substring(s, 0, 1);
29                                 if(ch != "\"" && ch != "\r" && ch != "\n")
30                                         localcmd(ch);
31                                 s = substring(s, 1, strlen(s) - 1);
32                         }
33                 }
34                 else
35                 {
36                         localcmd(s);
37                 }
38                 localcmd("\"\n");
39         }
40 }
41
42 void(string s, float check_dangerous) GameLogEcho =
43 {
44         string fn;
45         float matches;
46
47         if(cvar("sv_eventlog_files"))
48         {
49                 if(!logfile_open)
50                 {
51                         logfile_open = TRUE;
52                         matches = cvar("sv_eventlog_files_counter") + 1;
53                         cvar_set("sv_eventlog_files_counter", ftos(matches));
54                         fn = ftos(matches);
55                         if(strlen(fn) < 8)
56                                 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
57                         fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
58                         logfile = fopen(fn, FILE_APPEND);
59                 }
60                 if(logfile >= 0)
61                         fputs(logfile, strcat(s, "\n"));
62         }
63         if(cvar("sv_eventlog_console"))
64         {
65                 ServerConsoleEcho(s, check_dangerous);
66         }
67 }
68
69 void() GameLogInit =
70 {
71         logfile_open = 0;
72         // will be opened later
73 }
74
75 void() GameLogClose =
76 {
77         if(logfile_open && logfile >= 0)
78         {
79                 fclose(logfile);
80                 logfile = -1;
81         }
82 }
83
84 float math_mod(float a, float b)
85 {
86         return a - (floor(a / b) * b);
87 }
88
89 void relocate_spawnpoint()
90 {
91         // nudge off the floor
92         setorigin(self, self.origin + '0 0 1');
93
94         tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
95         if (trace_startsolid)
96         {
97                 objerror("player spawn point in solid, mapper sucks!\n");
98                 return;
99         }
100 }
101
102 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
103 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
104 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
105 // BE CONSTANT OR strzoneD!
106 float(string haystack, string needle, float offset) strstr =
107 {
108         float len, endpos;
109         string found;
110         len = strlen(needle);
111         endpos = strlen(haystack) - len;
112         while(offset <= endpos)
113         {
114                 found = substring(haystack, offset, len);
115                 if(found == needle)
116                         return offset;
117                 offset = offset + 1;
118         }
119         return -1;
120 }
121
122 float NUM_NEAREST_ENTITIES = 4;
123 entity nearest_entity[NUM_NEAREST_ENTITIES];
124 float nearest_length[NUM_NEAREST_ENTITIES];
125 entity(vector point, .string field, string value, vector axismod) findnearest =
126 {
127         entity localhead;
128         float i;
129         float j;
130         float len;
131         vector dist;
132
133         float num_nearest;
134         num_nearest = 0;
135
136         localhead = find(world, field, value);
137         while(localhead)
138         {
139                 if((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
140                         dist = localhead.oldorigin;
141                 else
142                         dist = localhead.origin;
143                 dist = dist - point;
144                 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
145                 len = vlen(dist);
146
147                 for(i = 0; i < num_nearest; ++i)
148                 {
149                         if(len < nearest_length[i])
150                                 break;
151                 }
152
153                 // now i tells us where to insert at
154                 //   INSERTION SORT! YOU'VE SEEN IT! RUN!
155                 if(i < NUM_NEAREST_ENTITIES)
156                 {
157                         for(j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
158                         {
159                                 nearest_length[j + 1] = nearest_length[j];
160                                 nearest_entity[j + 1] = nearest_entity[j];
161                         }
162                         nearest_length[i] = len;
163                         nearest_entity[i] = localhead;
164                         if(num_nearest < NUM_NEAREST_ENTITIES)
165                                 num_nearest = num_nearest + 1;
166                 }
167
168                 localhead = find(localhead, field, value);
169         }
170
171         // now use the first one from our list that we can see
172         for(i = 0; i < num_nearest; ++i)
173         {
174                 traceline(point, nearest_entity[i].origin, TRUE, world);
175                 if(trace_fraction == 1)
176                 {
177                         if(i != 0)
178                         {
179                                 dprint("Nearest point (");
180                                 dprint(nearest_entity[0].netname);
181                                 dprint(") is not visible, using a visible one.\n");
182                         }
183                         return nearest_entity[i];
184                 }
185         }
186
187         if(num_nearest == 0)
188                 return world;
189
190         dprint("Not seeing any location point, using nearest as fallback.\n");
191         /* DEBUGGING CODE:
192         dprint("Candidates were: ");
193         for(j = 0; j < num_nearest; ++j)
194         {
195                 if(j != 0)
196                         dprint(", ");
197                 dprint(nearest_entity[j].netname);
198         }
199         dprint("\n");
200         */
201
202         return nearest_entity[0];
203 }
204
205 void() target_location =
206 {
207         self.classname = "target_location";
208         // location name in netname
209         // eventually support: count, teamgame selectors, line of sight?
210 };
211
212 void() info_location =
213 {
214         self.classname = "target_location";
215         self.message = self.netname;
216 };
217
218 string NearestLocation(vector p)
219 {
220         entity loc;
221         string ret;
222         ret = "somewhere";
223         loc = findnearest(p, classname, "target_location", '1 1 1');
224         if(loc)
225         {
226                 ret = loc.message;
227         }
228         else
229         {
230                 loc = findnearest(p, target, "###item###", '1 1 4');
231                 if(loc)
232                         ret = loc.netname;
233         }
234         return ret;
235 }
236
237 string(string msg) formatmessage =
238 {
239         float p;
240         float n;
241         string msg_save;
242         string escape;
243         string replacement;
244         msg_save = strzone(msg);
245         p = 0;
246         n = 7;
247         while(1)
248         {
249                 if(n < 1)
250                         break; // too many replacements
251                 n = n - 1;
252                 p = strstr(msg_save, "%", p); // NOTE: this destroys msg as it's a tempstring!
253                 if(p < 0)
254                         break;
255                 replacement = substring(msg_save, p, 2);
256                 escape = substring(msg_save, p + 1, 1);
257                 if(escape == "%")
258                         replacement = "%";
259                 else if(escape == "a")
260                         replacement = ftos(floor(self.armorvalue));
261                 else if(escape == "h")
262                         replacement = ftos(floor(self.health));
263                 else if(escape == "l")
264                         replacement = NearestLocation(self.origin);
265                 else if(escape == "y")
266                         replacement = NearestLocation(self.cursor_trace_endpos);
267                 else if(escape == "d")
268                         replacement = NearestLocation(self.death_origin);
269                 else if(escape == "w")
270                 {
271                         float wep;
272                         wep = self.weapon;
273                         if(!wep)
274                                 wep = self.switchweapon;
275                         if(!wep)
276                                 wep = self.cnt;
277                         replacement = W_Name(wep);
278                 }
279                 else if(escape == "W")
280                 {
281                         if(self.items & IT_SHELLS) replacement = "shells";
282                         else if(self.items & IT_NAILS) replacement = "bullets";
283                         else if(self.items & IT_ROCKETS) replacement = "rockets";
284                         else if(self.items & IT_CELLS) replacement = "cells";
285                         else replacement = "batteries"; // ;)
286                 }
287                 else if(escape == "x")
288                 {
289                         replacement = self.cursor_trace_ent.netname;
290                         if(!replacement || !self.cursor_trace_ent)
291                                 replacement = "nothing";
292                 }
293                 else if(escape == "p")
294                 {
295                         if(self.last_selected_player)
296                                 replacement = self.last_selected_player.netname;
297                         else
298                                 replacement = "(nobody)";
299                 }
300                 msg = strcat(substring(msg_save, 0, p), replacement);
301                 msg = strcat(msg, substring(msg_save, p+2, strlen(msg_save) - (p+2)));
302                 strunzone(msg_save);
303                 msg_save = strzone(msg);
304                 p = p + 2;
305         }
306         msg = strcat(msg_save);
307         strunzone(msg_save);
308         return msg;
309 }
310
311 /*
312 =============
313 GetCvars
314 =============
315 Called with:
316   0:  sends the request
317   >0: receives a cvar from name=argv(f) value=argv(f+1)
318 */
319 void GetCvars_handleString(float f, .string field, string name)
320 {
321         if(f < 0)
322         {
323                 if(self.field)
324                         strunzone(self.field);
325         }
326         else if(f > 0)
327         {
328                 if(argv(f) == name)
329                 {
330                         if(self.field)
331                                 strunzone(self.field);
332                         self.field = strzone(argv(f + 1));
333                 }
334         }
335         else
336                 stuffcmd(self, strcat("cmd reportcvar ", name, " $", name, "\n"));
337 }
338 void GetCvars_handleFloat(float f, .float field, string name)
339 {
340         if(f < 0)
341         {
342         }
343         else if(f > 0)
344         {
345                 if(argv(f) == name)
346                         self.field = stof(argv(f + 1));
347         }
348         else
349                 stuffcmd(self, strcat("cmd reportcvar ", name, " $", name, "\n"));
350 }
351 void GetCvars(float f)
352 {
353         GetCvars_handleFloat(f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
354         GetCvars_handleFloat(f, cvar_cl_nogibs, "cl_nogibs");
355         GetCvars_handleFloat(f, cvar_scr_centertime, "scr_centertime");
356         GetCvars_handleFloat(f, cvar_cl_shownames, "cl_shownames");
357         GetCvars_handleString(f, cvar_g_nexuizversion, "g_nexuizversion");
358 }
359
360 float fexists(string f)
361 {
362         float fh;
363         fh = fopen(f, FILE_READ);
364         if(fh < 0)
365                 return FALSE;
366         fclose(fh);
367         return TRUE;
368 }
369
370 void backtrace(string msg)
371 {
372         float dev;
373         dev = cvar("developer");
374         cvar_set("developer", "1");
375         dprint("\n");
376         dprint("--- CUT HERE ---\nWARNING: ");
377         dprint(msg);
378         dprint("\n");
379         remove(world); // isn't there any better way to cause a backtrace?
380         dprint("\n--- CUT UNTIL HERE ---\n");
381         cvar_set("developer", ftos(dev));
382 }
383
384 void DistributeFragsAmongTeam(entity p, float targetteam, float factor)
385 {
386         float f;
387         float d;
388         float nTeam;
389         entity head;
390
391         if(!teams_matter)
392                 return;
393
394         //if(p.frags < 0)
395         //{
396         //      p.frags = 0; // do not harm the new team!
397         //      return; // won't distribute negative scores
398         //}
399
400         if(p.frags == -666)
401                 return;
402
403         f = ceil(factor * p.frags);
404         p.frags = p.frags - f;
405
406         nTeam = 0;
407         head = find(world, classname, "player");
408         while(head)
409         {
410                 if(head != p)
411                         if(head.team == targetteam)
412                                 nTeam = nTeam + 1;
413                 head = find(head, classname, "player");
414         }
415
416         if(nTeam == 0)
417                 return;
418
419         head = find(world, classname, "player");
420         while(head)
421         {
422                 if(head != p)
423                         if(head.team == targetteam)
424                         {
425                                 d = floor(f / nTeam);
426                                 head.frags = head.frags + d;
427                                 f = f - d;
428                                 nTeam = nTeam - 1;
429                         }
430                 head = find(head, classname, "player");
431         }
432
433         if(nTeam != 0)
434                 error("nPlayers in team changed!");
435         if(f != 0)
436                 error(strcat("There were ", ftos(f), " frags left. BAD!"));
437 }
438
439 string Team_ColorCode(float teamid)
440 {
441         if(teamid == COLOR_TEAM1)
442                 return "^1";
443         else if(teamid == COLOR_TEAM2)
444                 return "^4";
445         else if(teamid == COLOR_TEAM3)
446                 return "^6";
447         else if(teamid == COLOR_TEAM4)
448                 return "^3";
449         else
450                 return "^7";
451 }
452
453 string decolorize(string s)
454 {
455         string out;
456         out = "";
457         while(s != "")
458         {
459                 float n;
460                 string ch1, ch2;
461                 n = 1;
462                 ch1 = substring(s, 0, 1);
463                 ch2 = substring(s, 1, 1);
464                 if(ch1 == "^")
465                 {
466                         n = 2;
467                         if(ch2 == "^")
468                                 out = strcat(out, "^^");
469                         else if(ch2 == "0")
470                                 out = strcat(out);
471                         else if(ch2 == "1")
472                                 out = strcat(out);
473                         else if(ch2 == "2")
474                                 out = strcat(out);
475                         else if(ch2 == "3")
476                                 out = strcat(out);
477                         else if(ch2 == "4")
478                                 out = strcat(out);
479                         else if(ch2 == "5")
480                                 out = strcat(out);
481                         else if(ch2 == "6")
482                                 out = strcat(out);
483                         else if(ch2 == "7")
484                                 out = strcat(out);
485                         else if(ch2 == "8")
486                                 out = strcat(out);
487                         else if(ch2 == "9")
488                                 out = strcat(out);
489                         else
490                         {
491                                 n = 1;
492                                 out = strcat(out, "^^");
493                         }
494                         s = substring(s, n, strlen(s) - n);
495                 }
496                 else
497                 {
498                         s = substring(s, 1, strlen(s) - 1);
499                         out = strcat(out, ch1);
500                 }
501         }
502         return out;
503 }
504
505 #define CENTERPRIO_POINT 1
506 #define CENTERPRIO_NORMAL 5
507 .float centerprint_priority;
508 .float centerprint_expires;
509 void centerprint_atprio(entity e, float prio, string s)
510 {
511         if(time > e.centerprint_expires)
512                 e.centerprint_priority = 0;
513         if(prio >= e.centerprint_priority)
514         {
515                 e.centerprint_priority = prio;
516                 e.centerprint_expires = time + e.cvar_scr_centertime;
517                 centerprint_builtin(e, s);
518         }
519 }
520 void centerprint_expire(entity e, float prio)
521 {
522         if(prio == e.centerprint_priority)
523         {
524                 e.centerprint_priority = 0;
525                 centerprint_builtin(e, "");
526         }
527 }
528 void centerprint(entity e, string s)
529 {
530         centerprint_atprio(e, CENTERPRIO_NORMAL, s);
531 }