1 void setsize(entity e, vector boxmin, vector boxmax);
3 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
4 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
5 string STR_PLAYER = "player";
6 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
7 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
9 // change that to actually calling strcat when running on an engine without
10 // unlimited tempstrings:
11 // string strcat1(string s) = #115; // FRIK_FILE
12 #define strcat1(s) (s)
17 void(string s) bcenterprint
19 // TODO replace by MSG_ALL (would show it to spectators too, though)?
22 if(clienttype(head) == CLIENTTYPE_REAL)
26 void(string s, float check_dangerous) ServerConsoleEcho =
29 if (checkextension("DP_SV_PRINT"))
38 ch = substring(s, 0, 1);
39 if(ch != "\"" && ch != "\r" && ch != "\n")
41 s = substring(s, 1, strlen(s) - 1);
52 void(string s, float check_dangerous) GameLogEcho =
57 if(cvar("sv_eventlog_files"))
62 matches = cvar("sv_eventlog_files_counter") + 1;
63 cvar_set("sv_eventlog_files_counter", ftos(matches));
66 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
67 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
68 logfile = fopen(fn, FILE_APPEND);
71 fputs(logfile, strcat(s, "\n"));
73 if(cvar("sv_eventlog_console"))
75 ServerConsoleEcho(s, check_dangerous);
82 // will be opened later
87 if(logfile_open && logfile >= 0)
94 float math_mod(float a, float b)
96 return a - (floor(a / b) * b);
99 void relocate_spawnpoint()
101 // nudge off the floor
102 setorigin(self, self.origin + '0 0 1');
104 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
105 if (trace_startsolid)
107 objerror("player spawn point in solid, mapper sucks!\n");
112 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
113 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
114 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
115 // BE CONSTANT OR strzoneD!
116 float(string haystack, string needle, float offset) strstr =
120 len = strlen(needle);
121 endpos = strlen(haystack) - len;
122 while(offset <= endpos)
124 found = substring(haystack, offset, len);
132 float NUM_NEAREST_ENTITIES = 4;
133 entity nearest_entity[NUM_NEAREST_ENTITIES];
134 float nearest_length[NUM_NEAREST_ENTITIES];
135 entity(vector point, .string field, string value, vector axismod) findnearest =
146 localhead = find(world, field, value);
149 if((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
150 dist = localhead.oldorigin;
152 dist = localhead.origin;
154 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
157 for(i = 0; i < num_nearest; ++i)
159 if(len < nearest_length[i])
163 // now i tells us where to insert at
164 // INSERTION SORT! YOU'VE SEEN IT! RUN!
165 if(i < NUM_NEAREST_ENTITIES)
167 for(j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
169 nearest_length[j + 1] = nearest_length[j];
170 nearest_entity[j + 1] = nearest_entity[j];
172 nearest_length[i] = len;
173 nearest_entity[i] = localhead;
174 if(num_nearest < NUM_NEAREST_ENTITIES)
175 num_nearest = num_nearest + 1;
178 localhead = find(localhead, field, value);
181 // now use the first one from our list that we can see
182 for(i = 0; i < num_nearest; ++i)
184 traceline(point, nearest_entity[i].origin, TRUE, world);
185 if(trace_fraction == 1)
189 dprint("Nearest point (");
190 dprint(nearest_entity[0].netname);
191 dprint(") is not visible, using a visible one.\n");
193 return nearest_entity[i];
200 dprint("Not seeing any location point, using nearest as fallback.\n");
202 dprint("Candidates were: ");
203 for(j = 0; j < num_nearest; ++j)
207 dprint(nearest_entity[j].netname);
212 return nearest_entity[0];
215 void() target_location =
217 self.classname = "target_location";
218 // location name in netname
219 // eventually support: count, teamgame selectors, line of sight?
222 void() info_location =
224 self.classname = "target_location";
225 self.message = self.netname;
228 string NearestLocation(vector p)
233 loc = findnearest(p, classname, "target_location", '1 1 1');
240 loc = findnearest(p, target, "###item###", '1 1 4');
247 string(string msg) formatmessage =
254 msg_save = strzone(msg);
260 break; // too many replacements
262 p = strstr(msg_save, "%", p); // NOTE: this destroys msg as it's a tempstring!
265 replacement = substring(msg_save, p, 2);
266 escape = substring(msg_save, p + 1, 1);
269 else if(escape == "a")
270 replacement = ftos(floor(self.armorvalue));
271 else if(escape == "h")
272 replacement = ftos(floor(self.health));
273 else if(escape == "l")
274 replacement = NearestLocation(self.origin);
275 else if(escape == "y")
276 replacement = NearestLocation(self.cursor_trace_endpos);
277 else if(escape == "d")
278 replacement = NearestLocation(self.death_origin);
279 else if(escape == "w")
284 wep = self.switchweapon;
287 replacement = W_Name(wep);
289 else if(escape == "W")
291 if(self.items & IT_SHELLS) replacement = "shells";
292 else if(self.items & IT_NAILS) replacement = "bullets";
293 else if(self.items & IT_ROCKETS) replacement = "rockets";
294 else if(self.items & IT_CELLS) replacement = "cells";
295 else replacement = "batteries"; // ;)
297 else if(escape == "x")
299 replacement = self.cursor_trace_ent.netname;
300 if(!replacement || !self.cursor_trace_ent)
301 replacement = "nothing";
303 else if(escape == "p")
305 if(self.last_selected_player)
306 replacement = self.last_selected_player.netname;
308 replacement = "(nobody)";
310 msg = strcat(substring(msg_save, 0, p), replacement);
311 msg = strcat(msg, substring(msg_save, p+2, strlen(msg_save) - (p+2)));
313 msg_save = strzone(msg);
316 msg = strcat(msg_save, "");
327 >0: receives a cvar from name=argv(f) value=argv(f+1)
329 void GetCvars_handleString(float f, .string field, string name)
334 strunzone(self.field);
341 strunzone(self.field);
342 self.field = strzone(argv(f + 1));
346 stuffcmd(self, strcat("cmd reportcvar ", name, " $", name, "\n"));
348 void GetCvars_handleFloat(float f, .float field, string name)
356 self.field = stof(argv(f + 1));
359 stuffcmd(self, strcat("cmd reportcvar ", name, " $", name, "\n"));
361 void GetCvars(float f)
363 GetCvars_handleFloat(f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
364 GetCvars_handleFloat(f, cvar_cl_nogibs, "cl_nogibs");
365 GetCvars_handleFloat(f, cvar_scr_centertime, "scr_centertime");
366 GetCvars_handleFloat(f, cvar_cl_shownames, "cl_shownames");
367 GetCvars_handleString(f, cvar_g_nexuizversion, "g_nexuizversion");
370 float fexists(string f)
373 fh = fopen(f, FILE_READ);
380 void backtrace(string msg)
383 dev = cvar("developer");
384 cvar_set("developer", "1");
386 dprint("--- CUT HERE ---\nWARNING: ");
389 remove(world); // isn't there any better way to cause a backtrace?
390 dprint("\n--- CUT UNTIL HERE ---\n");
391 cvar_set("developer", ftos(dev));
394 void DistributeFragsAmongTeam(entity p, float targetteam, float factor)
406 // p.frags = 0; // do not harm the new team!
407 // return; // won't distribute negative scores
413 f = ceil(factor * p.frags);
414 p.frags = p.frags - f;
417 FOR_EACH_PLAYER(head)
419 if(head.team == targetteam)
425 FOR_EACH_PLAYER(head)
427 if(head.team == targetteam)
429 d = floor(f / nTeam);
430 head.frags = head.frags + d;
436 error("nPlayers in team changed!");
438 error(strcat("There were ", ftos(f), " frags left. BAD!"));
441 string Team_ColorCode(float teamid)
443 if(teamid == COLOR_TEAM1)
445 else if(teamid == COLOR_TEAM2)
447 else if(teamid == COLOR_TEAM3)
449 else if(teamid == COLOR_TEAM4)
455 string decolorize(string s)
464 ch1 = substring(s, 0, 1);
465 ch2 = substring(s, 1, 1);
470 out = strcat(out, "^^");
494 out = strcat(out, "^^");
496 s = substring(s, n, strlen(s) - n);
500 s = substring(s, 1, strlen(s) - 1);
501 out = strcat(out, ch1);
506 #define strdecolorize(s) decolorize(s)
507 #define strlennocol(s) strlen(decolorize(s))
509 #define CENTERPRIO_POINT 1
510 #define CENTERPRIO_REBALANCE 2
511 #define CENTERPRIO_VOTE 4
512 #define CENTERPRIO_NORMAL 5
513 #define CENTERPRIO_MAPVOTE 9
514 .float centerprint_priority;
515 .float centerprint_expires;
516 void centerprint_atprio(entity e, float prio, string s)
518 if(intermission_running)
519 if(prio < CENTERPRIO_MAPVOTE)
521 if(time > e.centerprint_expires)
522 e.centerprint_priority = 0;
523 if(prio >= e.centerprint_priority)
525 e.centerprint_priority = prio;
526 e.centerprint_expires = time + e.cvar_scr_centertime;
527 centerprint_builtin(e, s);
530 void centerprint_expire(entity e, float prio)
532 if(prio == e.centerprint_priority)
534 e.centerprint_priority = 0;
535 centerprint_builtin(e, "");
538 void centerprint(entity e, string s)
540 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
545 // decolorizes and team colors the player name when needed
546 string playername(entity p)
549 if(teams_matter && !intermission_running && p.classname == "player")
551 t = Team_ColorCode(p.team);
552 return strcat(t, strdecolorize(p.netname));
558 void setsize(entity e, vector boxmin, vector boxmax)
562 vector boxdiff, hullsize;
565 boxsize = boxmax - boxmin;
567 if(maptype == MAPTYPE_Q1BSP)
572 else if(boxsize_x < 32.1)
573 hullsize = '32 32 56';
575 hullsize = '64 64 88';
577 else if(maptype == MAPTYPE_HLBSP)
582 else if(boxsize_x < 32.1)
585 hullsize = '32 32 36';
587 hullsize = '32 32 72';
590 hullsize = '64 64 64';
595 boxdiff = hullsize - boxsize;
596 //dprint("Adjusted size from ");
597 //dprint(vtos(boxmin), "-");
598 //dprint(vtos(boxmax), " to ");
599 boxmin = '0.5 0 0' * (boxmin_x + boxmax_x - hullsize_x) + '0 0.5 0' * (boxmin_y + boxmax_y - hullsize_y) + '0 0 1' * boxmin_z;
600 boxmax = boxmin + hullsize;
601 //dprint(vtos(boxmin), "-");
602 //dprint(vtos(boxmax), "\n");
605 setsize_builtin(e, boxmin, boxmax);