4 void(string s) bcenterprint
7 head = find(world, classname, "player");
10 if(clienttype(head) == CLIENTTYPE_REAL)
12 head = find(head, classname, "player");
16 void(string s, float check_dangerous) ServerConsoleEcho =
24 ch = substring(s, 0, 1);
25 if(ch != "\"" && ch != "\r" && ch != "\n")
27 s = substring(s, 1, strlen(s) - 1);
37 void(string s, float check_dangerous) GameLogEcho =
42 if(cvar("sv_eventlog_files"))
47 matches = cvar("sv_eventlog_files_counter") + 1;
48 cvar_set("sv_eventlog_files_counter", ftos(matches));
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);
56 fputs(logfile, strcat(s, "\n"));
58 if(cvar("sv_eventlog_console"))
60 ServerConsoleEcho(s, check_dangerous);
67 // will be opened later
72 if(logfile_open && logfile >= 0)
79 float math_mod(float a, float b)
81 return a - (floor(a / b) * b);
84 vector find_floor(vector org)
86 traceline(org + '0 0 5', org - '0 0 255', TRUE, self);
87 if (trace_fraction < 1)
93 void relocate_spawnpoint()
98 error_msg = "spawn point too close to a wall";
100 org = find_floor(self.origin) + '0 0 30';
102 traceline(org, org - '18 0 0', TRUE, world);
103 if(trace_fraction < 1)
106 traceline(loc, loc + '36 0 0', TRUE, world);
107 if(trace_fraction >= 1 && !self.noalign)
108 org = loc + '18 0 0';
116 traceline (org, org - '-18 0 0', TRUE, world);
117 if (trace_fraction < 1)
120 traceline (loc, loc + '-36 0 0', TRUE, world);
121 if(trace_fraction >= 1 && !self.noalign)
122 org = loc + '-18 0 0';
130 traceline (org, org - '0 18 0' , TRUE, world);
131 if (trace_fraction < 1)
134 traceline (loc, loc + '0 36 0', TRUE, world);
135 if(trace_fraction >= 1 && !self.noalign)
136 org = loc + '0 18 0';
144 traceline (org, org - '0 -18 0', TRUE, world);
145 if (trace_fraction < 1)
148 traceline (loc, loc + '0 -36 0', TRUE, world);
149 if(trace_fraction >= 1 && !self.noalign)
150 org = loc + '0 -18 0';
159 setorigin(self, org);
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 =
170 len = strlen(needle);
171 endpos = strlen(haystack) - len;
172 while(offset < endpos)
174 found = substring(haystack, offset, len);
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 =
196 localhead = find(world, field, value);
199 if((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
200 dist = localhead.oldorigin;
202 dist = localhead.origin;
204 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
207 for(i = 0; i < num_nearest; ++i)
209 if(len < nearest_length[i])
213 // now i tells us where to insert at
214 // INSERTION SORT! YOU'VE SEEN IT! RUN!
215 if(i < NUM_NEAREST_ENTITIES)
217 for(j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
219 nearest_length[j + 1] = nearest_length[j];
220 nearest_entity[j + 1] = nearest_entity[j];
222 nearest_length[i] = len;
223 nearest_entity[i] = localhead;
224 if(num_nearest < NUM_NEAREST_ENTITIES)
225 num_nearest = num_nearest + 1;
228 localhead = find(localhead, field, value);
231 // now use the first one from our list that we can see
232 for(i = 0; i < num_nearest; ++i)
234 traceline(point, nearest_entity[i].origin, TRUE, world);
235 if(trace_fraction == 1)
239 dprint("Nearest point (");
240 dprint(nearest_entity[0].netname);
241 dprint(") is not visible, using a visible one.\n");
243 return nearest_entity[i];
250 dprint("Not seeing any location point, using nearest as fallback.\n");
252 dprint("Candidates were: ");
253 for(j = 0; j < num_nearest; ++j)
257 dprint(nearest_entity[j].netname);
262 return nearest_entity[0];
265 void() target_location =
267 self.classname = "target_location";
268 // location name in netname
269 // eventually support: count, teamgame selectors, line of sight?
272 void() info_location =
274 self.classname = "target_location";
275 self.message = self.netname;
278 string NearestLocation(vector p)
283 loc = findnearest(p, classname, "target_location", '1 1 1');
290 loc = findnearest(p, target, "###item###", '1 1 4');
297 string(string msg) formatmessage =
304 msg_save = strzone(msg);
310 break; // too many replacements
312 p = strstr(msg_save, "%", p); // NOTE: this destroys msg as it's a tempstring!
315 replacement = substring(msg_save, p, 2);
316 escape = substring(msg_save, p + 1, 1);
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")
334 wep = self.switchweapon;
337 replacement = W_Name(wep);
339 else if(escape == "W")
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"; // ;)
347 else if(escape == "x")
349 replacement = self.cursor_trace_ent.netname;
350 if(!replacement || !self.cursor_trace_ent)
351 replacement = "nothing";
353 msg = strcat(substring(msg_save, 0, p), replacement);
354 msg = strcat(msg, substring(msg_save, p+2, strlen(msg_save) - (p+2)));
356 msg_save = strzone(msg);
359 msg = strcat(msg_save);
370 >0: receives a cvar from name=argv(f) value=argv(f+1)
372 void GetCvars_handleString(float f, .string field, string name)
377 self.field = argv(f + 1);
380 stuffcmd(self, strcat("cmd reportcvar ", name, " $", name, "\n"));
382 void GetCvars_handleFloat(float f, .float field, string name)
387 self.field = stof(argv(f + 1));
390 stuffcmd(self, strcat("cmd reportcvar ", name, " $", name, "\n"));
392 void GetCvars(float f)
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");
399 float fexists(string f)
402 fh = fopen(f, FILE_READ);
409 void backtrace(string msg)
412 dev = cvar("developer");
413 cvar_set("developer", "1");
415 dprint("--- CUT HERE ---\nWARNING: ");
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));
423 void DistributeFragsAmongTeam(entity p, float targetteam, float factor)
435 // p.frags = 0; // do not harm the new team!
436 // return; // won't distribute negative scores
442 f = ceil(factor * p.frags);
443 p.frags = p.frags - f;
446 head = find(world, classname, "player");
450 if(head.team == targetteam)
452 head = find(head, classname, "player");
458 head = find(world, classname, "player");
462 if(head.team == targetteam)
464 d = floor(f / nTeam);
465 head.frags = head.frags + d;
469 head = find(head, classname, "player");
473 error("nPlayers in team changed!");
475 error(strcat("There were ", ftos(f), " frags left. BAD!"));
478 string Team_ColorCode(float teamid)
480 if(teamid == COLOR_TEAM1)
482 else if(teamid == COLOR_TEAM2)
484 else if(teamid == COLOR_TEAM3)
486 else if(teamid == COLOR_TEAM4)