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