1 var void remove(entity e);
2 void objerror(string s);
4 .vector dropped_origin;
6 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
7 void crosshair_trace(entity pl)
9 traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
11 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
12 void WarpZone_crosshair_trace(entity pl)
14 WarpZone_traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
17 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
18 void() spawnpoint_use;
19 string race_GetName(float pos);
20 string race_PlaceName(float pos);
22 string ColoredTeamName(float t);
24 string admin_name(void)
26 if(cvar_string("sv_adminnick") != "")
27 return cvar_string("sv_adminnick");
29 return "SERVER ADMIN";
32 float DistributeEvenly_amount;
33 float DistributeEvenly_totalweight;
34 void DistributeEvenly_Init(float amount, float totalweight)
36 if (DistributeEvenly_amount)
38 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
39 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
42 DistributeEvenly_amount = 0;
44 DistributeEvenly_amount = amount;
45 DistributeEvenly_totalweight = totalweight;
47 float DistributeEvenly_Get(float weight)
52 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
53 DistributeEvenly_totalweight -= weight;
54 DistributeEvenly_amount -= f;
58 #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
61 string STR_PLAYER = "player";
62 string STR_SPECTATOR = "spectator";
63 string STR_OBSERVER = "observer";
66 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
67 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
68 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
69 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
71 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
72 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
73 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
74 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
75 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
78 // copies a string to a tempstring (so one can strunzone it)
79 string strcat1(string s) = #115; // FRIK_FILE
84 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
86 local float nPlayerHealth = rint(enPlayer.health);
87 local float nPlayerArmor = rint(enPlayer.armorvalue);
88 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
89 local float nPlayerPing = rint(enPlayer.ping);
90 local string strPlayerPingColor;
91 local string strMessage;
92 if(nPlayerPing >= 150)
93 strPlayerPingColor = "^1";
95 strPlayerPingColor = "^2";
97 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
98 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
100 if(cvar("sv_fragmessage_information_ping")) {
101 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
102 strMessage = strcat(strMessage, " ^7(^2Bot");
104 strMessage = strcat(strMessage, " ^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
105 if(cvar("sv_fragmessage_information_handicap"))
106 if(cvar("sv_fragmessage_information_handicap") == 2)
107 if(nPlayerHandicap <= 1)
108 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
110 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
111 else if not(nPlayerHandicap <= 1)
112 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
114 strMessage = strcat(strMessage, "^7)");
115 } else if(cvar("sv_fragmessage_information_handicap")) {
116 if(cvar("sv_fragmessage_information_handicap") == 2)
117 if(nPlayerHandicap <= 1)
118 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
120 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
121 else if(nPlayerHandicap > 1)
122 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
126 void bcenterprint(string s)
128 // TODO replace by MSG_ALL (would show it to spectators too, though)?
130 FOR_EACH_PLAYER(head)
131 if (clienttype(head) == CLIENTTYPE_REAL)
132 centerprint(head, s);
135 void GameLogEcho(string s)
140 if (cvar("sv_eventlog_files"))
145 matches = cvar("sv_eventlog_files_counter") + 1;
146 cvar_set("sv_eventlog_files_counter", ftos(matches));
149 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
150 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
151 logfile = fopen(fn, FILE_APPEND);
152 fputs(logfile, ":logversion:3\n");
156 if (cvar("sv_eventlog_files_timestamps"))
157 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
159 fputs(logfile, strcat(s, "\n"));
162 if (cvar("sv_eventlog_console"))
171 // will be opened later
176 if (logfile_open && logfile >= 0)
186 vector PL_CROUCH_VIEW_OFS;
187 vector PL_CROUCH_MIN;
188 vector PL_CROUCH_MAX;
190 float spawnpoint_nag;
191 void relocate_spawnpoint()
193 PL_VIEW_OFS = stov(cvar_string("sv_player_viewoffset"));
194 PL_MIN = stov(cvar_string("sv_player_mins"));
195 PL_MAX = stov(cvar_string("sv_player_maxs"));
196 PL_CROUCH_VIEW_OFS = stov(cvar_string("sv_player_crouch_viewoffset"));
197 PL_CROUCH_MIN = stov(cvar_string("sv_player_crouch_mins"));
198 PL_CROUCH_MAX = stov(cvar_string("sv_player_crouch_maxs"));
200 // nudge off the floor
201 setorigin(self, self.origin + '0 0 1');
203 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
204 if (trace_startsolid)
210 if (!move_out_of_solid(self))
211 objerror("could not get out of solid at all!");
212 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
213 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
214 print(" ", ftos(self.origin_y - o_y));
215 print(" ", ftos(self.origin_z - o_z), "'\n");
216 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
219 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
225 self.mins = self.maxs = '0 0 0';
226 objerror("player spawn point in solid, mapper sucks!\n");
231 self.use = spawnpoint_use;
232 self.team_saved = self.team;
236 if (have_team_spawns != 0)
238 have_team_spawns = 1;
240 if (cvar("r_showbboxes"))
242 // show where spawnpoints point at too
243 makevectors(self.angles);
246 e.classname = "info_player_foo";
247 setorigin(e, self.origin + v_forward * 24);
248 setsize(e, '-8 -8 -8', '8 8 8');
249 e.solid = SOLID_TRIGGER;
253 #define strstr strstrofs
255 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
256 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
257 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
258 // BE CONSTANT OR strzoneD!
259 float strstr(string haystack, string needle, float offset)
263 len = strlen(needle);
264 endpos = strlen(haystack) - len;
265 while(offset <= endpos)
267 found = substring(haystack, offset, len);
276 float NUM_NEAREST_ENTITIES = 4;
277 entity nearest_entity[NUM_NEAREST_ENTITIES];
278 float nearest_length[NUM_NEAREST_ENTITIES];
279 entity findnearest(vector point, .string field, string value, vector axismod)
290 localhead = find(world, field, value);
293 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
294 dist = localhead.oldorigin;
296 dist = localhead.origin;
298 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
301 for (i = 0; i < num_nearest; ++i)
303 if (len < nearest_length[i])
307 // now i tells us where to insert at
308 // INSERTION SORT! YOU'VE SEEN IT! RUN!
309 if (i < NUM_NEAREST_ENTITIES)
311 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
313 nearest_length[j + 1] = nearest_length[j];
314 nearest_entity[j + 1] = nearest_entity[j];
316 nearest_length[i] = len;
317 nearest_entity[i] = localhead;
318 if (num_nearest < NUM_NEAREST_ENTITIES)
319 num_nearest = num_nearest + 1;
322 localhead = find(localhead, field, value);
325 // now use the first one from our list that we can see
326 for (i = 0; i < num_nearest; ++i)
328 traceline(point, nearest_entity[i].origin, TRUE, world);
329 if (trace_fraction == 1)
333 dprint("Nearest point (");
334 dprint(nearest_entity[0].netname);
335 dprint(") is not visible, using a visible one.\n");
337 return nearest_entity[i];
341 if (num_nearest == 0)
344 dprint("Not seeing any location point, using nearest as fallback.\n");
346 dprint("Candidates were: ");
347 for(j = 0; j < num_nearest; ++j)
351 dprint(nearest_entity[j].netname);
356 return nearest_entity[0];
359 void spawnfunc_target_location()
361 self.classname = "target_location";
362 // location name in netname
363 // eventually support: count, teamgame selectors, line of sight?
366 void spawnfunc_info_location()
368 self.classname = "target_location";
369 self.message = self.netname;
372 string NearestLocation(vector p)
377 loc = findnearest(p, classname, "target_location", '1 1 1');
384 loc = findnearest(p, target, "###item###", '1 1 4');
391 string formatmessage(string msg)
402 WarpZone_crosshair_trace(self);
403 cursor = trace_endpos;
404 cursor_ent = trace_ent;
408 break; // too many replacements
411 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
412 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
425 replacement = substring(msg, p, 2);
426 escape = substring(msg, p + 1, 1);
430 else if (escape == "\\")
432 else if (escape == "n")
434 else if (escape == "a")
435 replacement = ftos(floor(self.armorvalue));
436 else if (escape == "h")
437 replacement = ftos(floor(self.health));
438 else if (escape == "l")
439 replacement = NearestLocation(self.origin);
440 else if (escape == "y")
441 replacement = NearestLocation(cursor);
442 else if (escape == "d")
443 replacement = NearestLocation(self.death_origin);
444 else if (escape == "w") {
448 wep = self.switchweapon;
451 replacement = W_Name(wep);
452 } else if (escape == "W") {
453 if (self.items & IT_SHELLS) replacement = "shells";
454 else if (self.items & IT_NAILS) replacement = "bullets";
455 else if (self.items & IT_ROCKETS) replacement = "rockets";
456 else if (self.items & IT_CELLS) replacement = "cells";
457 else replacement = "batteries"; // ;)
458 } else if (escape == "x") {
459 replacement = cursor_ent.netname;
460 if (!replacement || !cursor_ent)
461 replacement = "nothing";
462 } else if (escape == "p") {
463 if (self.last_selected_player)
464 replacement = self.last_selected_player.netname;
466 replacement = "(nobody)";
467 } else if (escape == "s")
468 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
469 else if (escape == "S")
470 replacement = ftos(vlen(self.velocity));
471 else if (escape == "v") {
475 if(self.classname == "spectator")
480 weapon_number = stats.weapon;
483 weapon_number = stats.switchweapon;
486 weapon_number = stats.cnt;
488 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
489 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
491 replacement = "~"; // or something to indicate NULL, not available
494 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
495 p = p + strlen(replacement);
500 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
501 return (value == 0) ? FALSE : TRUE;
510 >0: receives a cvar from name=argv(f) value=argv(f+1)
512 void GetCvars_handleString(string thisname, float f, .string field, string name)
517 strunzone(self.field);
518 self.field = string_null;
522 if (thisname == name)
525 strunzone(self.field);
526 self.field = strzone(argv(f + 1));
530 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
532 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
534 GetCvars_handleString(thisname, f, field, name);
535 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
536 if (thisname == name)
539 s = func(strcat1(self.field));
542 strunzone(self.field);
543 self.field = strzone(s);
547 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
554 if (thisname == name)
555 self.field = stof(argv(f + 1));
558 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
560 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
567 if (thisname == name)
571 self.field = stof(argv(f + 1));
580 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
583 string W_FixWeaponOrder_ForceComplete(string s);
584 string W_FixWeaponOrder_AllowIncomplete(string s);
585 float w_getbestweapon(entity e);
586 void GetCvars(float f)
591 s = strcat1(argv(f));
595 MUTATOR_CALLHOOK(GetCvars);
596 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
597 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
598 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
599 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
600 GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
601 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
602 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
603 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
604 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
605 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
606 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
607 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
608 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
609 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
610 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
611 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
612 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
613 GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode");
614 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
615 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
616 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
617 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
618 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
619 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
620 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
622 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
623 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
625 #ifdef ALLOW_FORCEMODELS
626 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
627 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromxonotic, "cl_forceplayermodelsfromxonotic");
629 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
631 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
634 if (s == "cl_weaponpriority")
635 self.switchweapon = w_getbestweapon(self);
639 float fexists(string f)
642 fh = fopen(f, FILE_READ);
649 void backtrace(string msg)
652 dev = cvar("developer");
653 war = cvar("prvm_backtraceforwarnings");
654 cvar_set("developer", "1");
655 cvar_set("prvm_backtraceforwarnings", "1");
657 print("--- CUT HERE ---\nWARNING: ");
660 remove(world); // isn't there any better way to cause a backtrace?
661 print("\n--- CUT UNTIL HERE ---\n");
662 cvar_set("developer", ftos(dev));
663 cvar_set("prvm_backtraceforwarnings", ftos(war));
666 string Team_ColorCode(float teamid)
668 if (teamid == COLOR_TEAM1)
670 else if (teamid == COLOR_TEAM2)
672 else if (teamid == COLOR_TEAM3)
674 else if (teamid == COLOR_TEAM4)
680 string Team_ColorName(float t)
682 // fixme: Search for team entities and get their .netname's!
683 if (t == COLOR_TEAM1)
685 if (t == COLOR_TEAM2)
687 if (t == COLOR_TEAM3)
689 if (t == COLOR_TEAM4)
694 string Team_ColorNameLowerCase(float t)
696 // fixme: Search for team entities and get their .netname's!
697 if (t == COLOR_TEAM1)
699 if (t == COLOR_TEAM2)
701 if (t == COLOR_TEAM3)
703 if (t == COLOR_TEAM4)
708 float ColourToNumber(string team_colour)
710 if (team_colour == "red")
713 if (team_colour == "blue")
716 if (team_colour == "yellow")
719 if (team_colour == "pink")
722 if (team_colour == "auto")
728 float NumberToTeamNumber(float number)
745 #define CENTERPRIO_POINT 1
746 #define CENTERPRIO_SPAM 2
747 #define CENTERPRIO_VOTE 4
748 #define CENTERPRIO_NORMAL 5
749 #define CENTERPRIO_SHIELDING 7
750 #define CENTERPRIO_MAPVOTE 9
751 #define CENTERPRIO_IDLEKICK 50
752 #define CENTERPRIO_ADMIN 99
753 .float centerprint_priority;
754 .float centerprint_expires;
755 void centerprint_atprio(entity e, float prio, string s)
757 if (intermission_running)
758 if (prio < CENTERPRIO_MAPVOTE)
760 if (time > e.centerprint_expires)
761 e.centerprint_priority = 0;
762 if (prio >= e.centerprint_priority)
764 e.centerprint_priority = prio;
765 if (timeoutStatus == 2)
766 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
768 e.centerprint_expires = time + e.cvar_scr_centertime;
769 centerprint_builtin(e, s);
772 void centerprint_expire(entity e, float prio)
774 if (prio == e.centerprint_priority)
776 e.centerprint_priority = 0;
777 centerprint_builtin(e, "");
780 void centerprint(entity e, string s)
782 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
785 // decolorizes and team colors the player name when needed
786 string playername(entity p)
789 if (teams_matter && !intermission_running && p.classname == "player")
791 t = Team_ColorCode(p.team);
792 return strcat(t, strdecolorize(p.netname));
798 vector randompos(vector m1, vector m2)
802 v_x = m2_x * random() + m1_x;
803 v_y = m2_y * random() + m1_y;
804 v_z = m2_z * random() + m1_z;
808 float g_pickup_shells;
809 float g_pickup_shells_max;
810 float g_pickup_nails;
811 float g_pickup_nails_max;
812 float g_pickup_rockets;
813 float g_pickup_rockets_max;
814 float g_pickup_cells;
815 float g_pickup_cells_max;
817 float g_pickup_fuel_jetpack;
818 float g_pickup_fuel_max;
819 float g_pickup_armorsmall;
820 float g_pickup_armorsmall_max;
821 float g_pickup_armorsmall_anyway;
822 float g_pickup_armormedium;
823 float g_pickup_armormedium_max;
824 float g_pickup_armormedium_anyway;
825 float g_pickup_armorbig;
826 float g_pickup_armorbig_max;
827 float g_pickup_armorbig_anyway;
828 float g_pickup_armorlarge;
829 float g_pickup_armorlarge_max;
830 float g_pickup_armorlarge_anyway;
831 float g_pickup_healthsmall;
832 float g_pickup_healthsmall_max;
833 float g_pickup_healthsmall_anyway;
834 float g_pickup_healthmedium;
835 float g_pickup_healthmedium_max;
836 float g_pickup_healthmedium_anyway;
837 float g_pickup_healthlarge;
838 float g_pickup_healthlarge_max;
839 float g_pickup_healthlarge_anyway;
840 float g_pickup_healthmega;
841 float g_pickup_healthmega_max;
842 float g_pickup_healthmega_anyway;
843 float g_pickup_ammo_anyway;
844 float g_pickup_weapons_anyway;
846 float g_weaponarena_random;
847 string g_weaponarena_list;
848 float g_weaponspeedfactor;
849 float g_weaponratefactor;
850 float g_weapondamagefactor;
851 float g_weaponforcefactor;
852 float g_weaponspreadfactor;
856 float start_ammo_shells;
857 float start_ammo_nails;
858 float start_ammo_rockets;
859 float start_ammo_cells;
860 float start_ammo_fuel;
862 float start_armorvalue;
863 float warmup_start_weapons;
864 float warmup_start_ammo_shells;
865 float warmup_start_ammo_nails;
866 float warmup_start_ammo_rockets;
867 float warmup_start_ammo_cells;
868 float warmup_start_ammo_fuel;
869 float warmup_start_health;
870 float warmup_start_armorvalue;
874 entity get_weaponinfo(float w);
876 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
878 var float i = weaponinfo.weapon;
883 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
885 if (t < 0) // "default" weapon selection
887 if (g_lms || g_ca || allguns)
888 t = (weaponinfo.spawnflags & WEP_FLAG_NORMAL);
891 else if (g_race || g_cts)
892 t = (i == WEP_LASER);
894 t = 0; // weapon is set a few lines later
896 t = (i == WEP_LASER || i == WEP_SHOTGUN);
897 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
898 t |= (i == WEP_HOOK);
901 // we cannot disable porto in Nexball, we must force it
902 if(g_nexball && i == WEP_PORTO)
908 void readplayerstartcvars()
914 // initialize starting values for players
917 start_ammo_shells = 0;
918 start_ammo_nails = 0;
919 start_ammo_rockets = 0;
920 start_ammo_cells = 0;
921 start_health = cvar("g_balance_health_start");
922 start_armorvalue = cvar("g_balance_armor_start");
925 s = cvar_string("g_weaponarena");
931 g_weaponarena_list = "All Weapons";
932 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
934 e = get_weaponinfo(j);
935 g_weaponarena |= e.weapons;
936 weapon_action(e.weapon, WR_PRECACHE);
939 else if (s == "most")
941 g_weaponarena_list = "Most Weapons";
942 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
944 e = get_weaponinfo(j);
945 if (e.spawnflags & WEP_FLAG_NORMAL)
947 g_weaponarena |= e.weapons;
948 weapon_action(e.weapon, WR_PRECACHE);
952 else if (s == "none")
954 g_weaponarena_list = "No Weapons";
955 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
959 t = tokenize_console(s);
960 g_weaponarena_list = "";
961 for (i = 0; i < t; ++i)
964 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
966 e = get_weaponinfo(j);
969 g_weaponarena |= e.weapons;
970 weapon_action(e.weapon, WR_PRECACHE);
971 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
977 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
980 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
984 g_weaponarena_random = cvar("g_weaponarena_random");
986 g_weaponarena_random = 0;
990 start_weapons = g_weaponarena;
991 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_MINE_LAYER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
992 start_ammo_rockets = 999;
993 if (g_weaponarena & WEPBIT_SHOTGUN)
994 start_ammo_shells = 999;
995 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
996 start_ammo_cells = 999;
997 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
998 start_ammo_nails = 999;
999 if (g_weaponarena & WEPBIT_HOOK)
1000 start_ammo_fuel = 999;
1001 start_items |= IT_UNLIMITED_AMMO;
1003 else if (g_minstagib)
1006 start_armorvalue = 0;
1007 start_weapons = WEPBIT_MINSTANEX;
1008 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
1009 start_ammo_cells = cvar("g_minstagib_ammo_start");
1010 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
1011 start_ammo_fuel = cvar("g_start_ammo_fuel");
1013 if (g_minstagib_invis_alpha <= 0)
1014 g_minstagib_invis_alpha = -1;
1020 start_ammo_shells = cvar("g_lms_start_ammo_shells");
1021 start_ammo_nails = cvar("g_lms_start_ammo_nails");
1022 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
1023 start_ammo_cells = cvar("g_lms_start_ammo_cells");
1024 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
1025 start_health = cvar("g_lms_start_health");
1026 start_armorvalue = cvar("g_lms_start_armor");
1030 start_ammo_shells = cvar("g_start_ammo_shells");
1031 start_ammo_nails = cvar("g_start_ammo_nails");
1032 start_ammo_rockets = cvar("g_start_ammo_rockets");
1033 start_ammo_cells = cvar("g_start_ammo_cells");
1034 start_ammo_fuel = cvar("g_start_ammo_fuel");
1037 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1039 e = get_weaponinfo(i);
1040 if(want_weapon("g_start_weapon_", e, FALSE))
1041 start_weapons |= e.weapons;
1047 warmup_start_ammo_shells = start_ammo_shells;
1048 warmup_start_ammo_nails = start_ammo_nails;
1049 warmup_start_ammo_rockets = start_ammo_rockets;
1050 warmup_start_ammo_cells = start_ammo_cells;
1051 warmup_start_ammo_fuel = start_ammo_fuel;
1052 warmup_start_health = start_health;
1053 warmup_start_armorvalue = start_armorvalue;
1054 warmup_start_weapons = start_weapons;
1056 if (!g_weaponarena && !g_minstagib && !g_ca)
1058 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1059 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1060 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1061 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1062 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1063 warmup_start_health = cvar("g_warmup_start_health");
1064 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1065 warmup_start_weapons = 0;
1066 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1068 e = get_weaponinfo(i);
1069 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
1070 warmup_start_weapons |= e.weapons;
1075 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1077 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1078 start_items |= IT_FUEL_REGEN;
1079 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1080 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1083 if(!cvar("g_use_ammunition"))
1085 start_ammo_shells = cvar("g_pickup_shells_max");
1086 start_ammo_nails = cvar("g_pickup_nails_max");
1087 start_ammo_rockets = cvar("g_pickup_rockets_max");
1088 start_ammo_cells = cvar("g_pickup_cells_max");
1089 start_ammo_fuel = cvar("g_pickup_fuel_max");
1090 start_items |= IT_UNLIMITED_AMMO;
1091 warmup_start_ammo_shells = cvar("g_pickup_shells_max");
1092 warmup_start_ammo_nails = cvar("g_pickup_nails_max");
1093 warmup_start_ammo_rockets = cvar("g_pickup_rockets_max");
1094 warmup_start_ammo_cells = cvar("g_pickup_cells_max");
1095 warmup_start_ammo_fuel = cvar("g_pickup_fuel_max");
1096 //warmup_start_items |= IT_UNLIMITED_AMMO;
1100 start_items |= IT_JETPACK;
1102 if (g_weapon_stay == 2)
1104 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1105 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1106 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1107 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1108 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1109 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1110 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1111 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1112 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1113 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1116 MUTATOR_CALLHOOK(SetStartItems);
1118 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1120 e = get_weaponinfo(i);
1121 if(e.weapons & (start_weapons | warmup_start_weapons))
1122 weapon_action(e.weapon, WR_PRECACHE);
1125 start_ammo_shells = max(0, start_ammo_shells);
1126 start_ammo_nails = max(0, start_ammo_nails);
1127 start_ammo_cells = max(0, start_ammo_cells);
1128 start_ammo_rockets = max(0, start_ammo_rockets);
1129 start_ammo_fuel = max(0, start_ammo_fuel);
1131 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1132 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1133 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1134 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1135 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1139 float g_bugrigs_planar_movement;
1140 float g_bugrigs_planar_movement_car_jumping;
1141 float g_bugrigs_reverse_spinning;
1142 float g_bugrigs_reverse_speeding;
1143 float g_bugrigs_reverse_stopping;
1144 float g_bugrigs_air_steering;
1145 float g_bugrigs_angle_smoothing;
1146 float g_bugrigs_friction_floor;
1147 float g_bugrigs_friction_brake;
1148 float g_bugrigs_friction_air;
1149 float g_bugrigs_accel;
1150 float g_bugrigs_speed_ref;
1151 float g_bugrigs_speed_pow;
1152 float g_bugrigs_steer;
1154 float g_touchexplode;
1155 float g_touchexplode_radius;
1156 float g_touchexplode_damage;
1157 float g_touchexplode_edgedamage;
1158 float g_touchexplode_force;
1165 float sv_pitch_fixyaw;
1167 float sv_accuracy_data_share;
1169 void readlevelcvars(void)
1171 // first load all the mutators
1173 MUTATOR_ADD(mutator_nix);
1174 if(cvar("g_dodging"))
1175 MUTATOR_ADD(mutator_dodging);
1176 if(cvar("g_rocket_flying") || (cvar("g_balance_rocketlauncher_detonatedelay") == 0 && stof(cvar_defstring("g_balance_rocketlauncher_detonatedelay")) != 0))
1177 MUTATOR_ADD(mutator_rocketflying);
1179 g_bugrigs = cvar("g_bugrigs");
1180 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1181 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1182 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1183 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1184 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1185 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1186 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1187 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1188 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1189 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1190 g_bugrigs_accel = cvar("g_bugrigs_accel");
1191 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1192 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1193 g_bugrigs_steer = cvar("g_bugrigs_steer");
1195 g_touchexplode = cvar("g_touchexplode");
1196 g_touchexplode_radius = cvar("g_touchexplode_radius");
1197 g_touchexplode_damage = cvar("g_touchexplode_damage");
1198 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1199 g_touchexplode_force = cvar("g_touchexplode_force");
1201 #ifdef ALLOW_FORCEMODELS
1202 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1204 sv_loddistance1 = cvar("sv_loddistance1");
1205 sv_loddistance2 = cvar("sv_loddistance2");
1207 if(sv_loddistance2 <= sv_loddistance1)
1208 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1210 sv_clones = cvar("sv_clones");
1211 sv_gentle = cvar("sv_gentle");
1212 sv_foginterval = cvar("sv_foginterval");
1213 g_cloaked = cvar("g_cloaked");
1214 g_jump_grunt = cvar("g_jump_grunt");
1215 g_footsteps = cvar("g_footsteps");
1216 g_grappling_hook = cvar("g_grappling_hook");
1217 g_jetpack = cvar("g_jetpack");
1218 g_laserguided_missile = cvar("g_laserguided_missile");
1219 g_midair = cvar("g_midair");
1220 g_minstagib = cvar("g_minstagib");
1221 g_norecoil = cvar("g_norecoil");
1222 g_vampire = cvar("g_vampire");
1223 g_bloodloss = cvar("g_bloodloss");
1224 sv_maxidle = cvar("sv_maxidle");
1225 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1226 sv_pogostick = cvar("sv_pogostick");
1227 g_ctf_reverse = cvar("g_ctf_reverse");
1228 sv_autotaunt = cvar("sv_autotaunt");
1229 sv_taunt = cvar("sv_taunt");
1231 inWarmupStage = cvar("g_warmup");
1232 g_warmup_limit = cvar("g_warmup_limit");
1233 g_warmup_allguns = cvar("g_warmup_allguns");
1234 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1236 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1237 inWarmupStage = 0; // these modes cannot work together, sorry
1239 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1240 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1241 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1242 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1243 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1244 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1245 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1246 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1247 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1248 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1249 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1250 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1252 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1253 g_weaponratefactor = cvar("g_weaponratefactor");
1254 g_weapondamagefactor = cvar("g_weapondamagefactor");
1255 g_weaponforcefactor = cvar("g_weaponforcefactor");
1256 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1258 g_pickup_shells = cvar("g_pickup_shells");
1259 g_pickup_shells_max = cvar("g_pickup_shells_max");
1260 g_pickup_nails = cvar("g_pickup_nails");
1261 g_pickup_nails_max = cvar("g_pickup_nails_max");
1262 g_pickup_rockets = cvar("g_pickup_rockets");
1263 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1264 g_pickup_cells = cvar("g_pickup_cells");
1265 g_pickup_cells_max = cvar("g_pickup_cells_max");
1266 g_pickup_fuel = cvar("g_pickup_fuel");
1267 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1268 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1269 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1270 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1271 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1272 g_pickup_armormedium = cvar("g_pickup_armormedium");
1273 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1274 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1275 g_pickup_armorbig = cvar("g_pickup_armorbig");
1276 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1277 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1278 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1279 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1280 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1281 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1282 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1283 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1284 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1285 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1286 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1287 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1288 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1289 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1290 g_pickup_healthmega = cvar("g_pickup_healthmega");
1291 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1292 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1294 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1295 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1297 g_pinata = cvar("g_pinata");
1299 g_weapon_stay = cvar("g_weapon_stay");
1301 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1304 g_ghost_items = cvar("g_ghost_items");
1306 if(g_ghost_items >= 1)
1307 g_ghost_items = 0.25; // default alpha value
1309 if not(inWarmupStage && !g_ca)
1310 game_starttime = cvar("g_start_delay");
1312 sv_pitch_min = cvar("sv_pitch_min");
1313 sv_pitch_max = cvar("sv_pitch_max");
1314 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1316 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
1318 readplayerstartcvars();
1322 // TODO sound pack system
1325 string precache_sound_builtin (string s) = #19;
1326 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1327 string precache_sound(string s)
1329 return precache_sound_builtin(strcat(soundpack, s));
1331 void play2(entity e, string filename)
1333 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1335 void sound(entity e, float chan, string samp, float vol, float atten)
1337 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1342 string precache_sound (string s) = #19;
1343 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1344 float precache_sound_index (string s) = #19;
1346 #define SND_VOLUME 1
1347 #define SND_ATTENUATION 2
1348 #define SND_LARGEENTITY 8
1349 #define SND_LARGESOUND 16
1351 float sound_allowed(float dest, entity e)
1353 // sounds from world may always pass
1356 if (e.classname == "body")
1358 if (e.owner && e.owner != e)
1363 // sounds to self may always pass
1364 if (dest == MSG_ONE)
1365 if (e == msg_entity)
1367 // sounds by players can be removed
1368 if (cvar("bot_sound_monopoly"))
1369 if (clienttype(e) == CLIENTTYPE_REAL)
1371 // anything else may pass
1375 void sound(entity e, float chan, string samp, float vol, float atten)
1377 if (!sound_allowed(MSG_BROADCAST, e))
1379 sound_builtin(e, chan, samp, vol, atten);
1381 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1385 if (!sound_allowed(dest, e))
1388 entno = num_for_edict(e);
1389 idx = precache_sound_index(samp);
1394 atten = floor(atten * 64);
1395 vol = floor(vol * 255);
1398 sflags |= SND_VOLUME;
1400 sflags |= SND_ATTENUATION;
1402 sflags |= SND_LARGEENTITY;
1404 sflags |= SND_LARGESOUND;
1406 WriteByte(dest, SVC_SOUND);
1407 WriteByte(dest, sflags);
1408 if (sflags & SND_VOLUME)
1409 WriteByte(dest, vol);
1410 if (sflags & SND_ATTENUATION)
1411 WriteByte(dest, atten);
1412 if (sflags & SND_LARGEENTITY)
1414 WriteShort(dest, entno);
1415 WriteByte(dest, chan);
1419 WriteShort(dest, entno * 8 + chan);
1421 if (sflags & SND_LARGESOUND)
1422 WriteShort(dest, idx);
1424 WriteByte(dest, idx);
1426 WriteCoord(dest, o_x);
1427 WriteCoord(dest, o_y);
1428 WriteCoord(dest, o_z);
1430 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1434 if (!sound_allowed(dest, e))
1437 o = e.origin + 0.5 * (e.mins + e.maxs);
1438 soundtoat(dest, e, o, chan, samp, vol, atten);
1440 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1442 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1444 void stopsoundto(float dest, entity e, float chan)
1448 if (!sound_allowed(dest, e))
1451 entno = num_for_edict(e);
1456 idx = precache_sound_index("misc/null.wav");
1457 sflags = SND_LARGEENTITY;
1459 sflags |= SND_LARGESOUND;
1460 WriteByte(dest, SVC_SOUND);
1461 WriteByte(dest, sflags);
1462 WriteShort(dest, entno);
1463 WriteByte(dest, chan);
1464 if (sflags & SND_LARGESOUND)
1465 WriteShort(dest, idx);
1467 WriteByte(dest, idx);
1468 WriteCoord(dest, e.origin_x);
1469 WriteCoord(dest, e.origin_y);
1470 WriteCoord(dest, e.origin_z);
1474 WriteByte(dest, SVC_STOPSOUND);
1475 WriteShort(dest, entno * 8 + chan);
1478 void stopsound(entity e, float chan)
1480 if (!sound_allowed(MSG_BROADCAST, e))
1483 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1484 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1487 void play2(entity e, string filename)
1489 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1491 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1494 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1496 float spamsound(entity e, float chan, string samp, float vol, float atten)
1498 if (!sound_allowed(MSG_BROADCAST, e))
1501 if (time > e.spamtime)
1504 sound(e, chan, samp, vol, atten);
1510 void play2team(float t, string filename)
1514 if (cvar("bot_sound_monopoly"))
1517 FOR_EACH_REALPLAYER(head)
1520 play2(head, filename);
1524 void play2all(string samp)
1526 if (cvar("bot_sound_monopoly"))
1529 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1532 void PrecachePlayerSounds(string f);
1533 void precache_playermodel(string m)
1535 float globhandle, i, n;
1538 if(substring(m, -9,5) == "_lod1")
1540 if(substring(m, -9,5) == "_lod2")
1545 precache_model(strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1)));
1546 precache_model(strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1)));
1549 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1552 n = search_getsize(globhandle);
1553 for (i = 0; i < n; ++i)
1555 //print(search_getfilename(globhandle, i), "\n");
1556 f = search_getfilename(globhandle, i);
1557 PrecachePlayerSounds(f);
1559 search_end(globhandle);
1561 void precache_all_playermodels(string pattern)
1563 float globhandle, i, n;
1566 globhandle = search_begin(pattern, TRUE, FALSE);
1569 n = search_getsize(globhandle);
1570 for (i = 0; i < n; ++i)
1572 //print(search_getfilename(globhandle, i), "\n");
1573 f = search_getfilename(globhandle, i);
1574 precache_playermodel(f);
1576 search_end(globhandle);
1581 // gamemode related things
1582 precache_model ("models/misc/chatbubble.spr");
1583 precache_model ("models/misc/teambubble.spr");
1586 precache_model ("models/runematch/curse.mdl");
1587 precache_model ("models/runematch/rune.mdl");
1590 #ifdef TTURRETS_ENABLED
1591 if (cvar("g_turrets"))
1595 // Precache all player models if desired
1596 if (cvar("sv_precacheplayermodels"))
1598 PrecachePlayerSounds("sound/player/default.sounds");
1599 precache_all_playermodels("models/player/*.zym");
1600 precache_all_playermodels("models/player/*.dpm");
1601 precache_all_playermodels("models/player/*.md3");
1602 precache_all_playermodels("models/player/*.psk");
1603 precache_all_playermodels("models/player/*.iqm");
1606 if (cvar("sv_defaultcharacter"))
1609 s = cvar_string("sv_defaultplayermodel_red");
1611 precache_playermodel(s);
1612 s = cvar_string("sv_defaultplayermodel_blue");
1614 precache_playermodel(s);
1615 s = cvar_string("sv_defaultplayermodel_yellow");
1617 precache_playermodel(s);
1618 s = cvar_string("sv_defaultplayermodel_pink");
1620 precache_playermodel(s);
1621 s = cvar_string("sv_defaultplayermodel");
1623 precache_playermodel(s);
1628 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1629 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1632 // gore and miscellaneous sounds
1633 //precache_sound ("misc/h2ohit.wav");
1634 precache_model ("models/hook.md3");
1635 precache_sound ("misc/armorimpact.wav");
1636 precache_sound ("misc/bodyimpact1.wav");
1637 precache_sound ("misc/bodyimpact2.wav");
1638 precache_sound ("misc/gib.wav");
1639 precache_sound ("misc/gib_splat01.wav");
1640 precache_sound ("misc/gib_splat02.wav");
1641 precache_sound ("misc/gib_splat03.wav");
1642 precache_sound ("misc/gib_splat04.wav");
1643 precache_sound ("misc/hit.wav");
1644 precache_sound ("misc/typehit.wav");
1645 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1646 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1647 precache_sound ("misc/null.wav");
1648 precache_sound ("misc/spawn.wav");
1649 precache_sound ("misc/talk.wav");
1650 precache_sound ("misc/teleport.wav");
1651 precache_sound ("misc/poweroff.wav");
1652 precache_sound ("player/lava.wav");
1653 precache_sound ("player/slime.wav");
1656 precache_sound ("misc/jetpack_fly.wav");
1658 precache_model ("models/sprites/0.spr32");
1659 precache_model ("models/sprites/1.spr32");
1660 precache_model ("models/sprites/2.spr32");
1661 precache_model ("models/sprites/3.spr32");
1662 precache_model ("models/sprites/4.spr32");
1663 precache_model ("models/sprites/5.spr32");
1664 precache_model ("models/sprites/6.spr32");
1665 precache_model ("models/sprites/7.spr32");
1666 precache_model ("models/sprites/8.spr32");
1667 precache_model ("models/sprites/9.spr32");
1668 precache_model ("models/sprites/10.spr32");
1670 // common weapon precaches
1671 precache_sound ("weapons/weapon_switch.wav");
1672 precache_sound ("weapons/weaponpickup.wav");
1673 precache_sound ("weapons/unavailable.wav");
1674 precache_sound ("weapons/dryfire.wav");
1675 if (g_grappling_hook)
1677 precache_sound ("weapons/hook_fire.wav"); // hook
1678 precache_sound ("weapons/hook_impact.wav"); // hook
1681 if(cvar("sv_precacheweapons"))
1683 //precache weapon models/sounds
1686 while (wep <= WEP_LAST)
1688 weapon_action(wep, WR_PRECACHE);
1693 precache_model("models/elaser.mdl");
1694 precache_model("models/laser.mdl");
1695 precache_model("models/ebomb.mdl");
1698 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1700 if (!self.noise && self.music) // quake 3 uses the music field
1701 self.noise = self.music;
1703 // plays music for the level if there is any
1706 precache_sound (self.noise);
1707 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1712 // sorry, but using \ in macros breaks line numbers
1713 #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
1714 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1715 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1717 // WARNING: this kills the trace globals
1718 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1719 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1721 #define INITPRIO_FIRST 0
1722 #define INITPRIO_GAMETYPE 0
1723 #define INITPRIO_GAMETYPE_FALLBACK 1
1724 #define INITPRIO_CVARS 5
1725 #define INITPRIO_FINDTARGET 10
1726 #define INITPRIO_DROPTOFLOOR 20
1727 #define INITPRIO_SETLOCATION 90
1728 #define INITPRIO_LINKDOORS 91
1729 #define INITPRIO_LAST 99
1731 .void(void) initialize_entity;
1732 .float initialize_entity_order;
1733 .entity initialize_entity_next;
1734 entity initialize_entity_first;
1736 void make_safe_for_remove(entity e)
1738 if (e.initialize_entity)
1741 for (ent = initialize_entity_first; ent; )
1743 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1745 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1746 // skip it in linked list
1749 prev.initialize_entity_next = ent.initialize_entity_next;
1750 ent = prev.initialize_entity_next;
1754 initialize_entity_first = ent.initialize_entity_next;
1755 ent = initialize_entity_first;
1761 ent = ent.initialize_entity_next;
1767 void objerror(string s)
1769 make_safe_for_remove(self);
1770 objerror_builtin(s);
1773 void remove_unsafely(entity e)
1778 void remove_safely(entity e)
1780 make_safe_for_remove(e);
1784 void InitializeEntity(entity e, void(void) func, float order)
1788 if (!e || e.initialize_entity)
1790 // make a proxy initializer entity
1794 e.classname = "initialize_entity";
1798 e.initialize_entity = func;
1799 e.initialize_entity_order = order;
1801 cur = initialize_entity_first;
1804 if (!cur || cur.initialize_entity_order > order)
1806 // insert between prev and cur
1808 prev.initialize_entity_next = e;
1810 initialize_entity_first = e;
1811 e.initialize_entity_next = cur;
1815 cur = cur.initialize_entity_next;
1818 void InitializeEntitiesRun()
1821 startoflist = initialize_entity_first;
1822 initialize_entity_first = world;
1823 for (self = startoflist; self; )
1826 var void(void) func;
1827 e = self.initialize_entity_next;
1828 func = self.initialize_entity;
1829 self.initialize_entity_order = 0;
1830 self.initialize_entity = func_null;
1831 self.initialize_entity_next = world;
1832 if (self.classname == "initialize_entity")
1836 remove_builtin(self);
1839 //dprint("Delayed initialization: ", self.classname, "\n");
1845 .float uncustomizeentityforclient_set;
1846 .void(void) uncustomizeentityforclient;
1847 void(void) SUB_Nullpointer = #0;
1848 void UncustomizeEntitiesRun()
1852 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1853 self.uncustomizeentityforclient();
1856 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1858 e.customizeentityforclient = customizer;
1859 e.uncustomizeentityforclient = uncustomizer;
1860 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1864 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1867 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1871 if (e.classname == "")
1872 e.classname = "net_linked";
1874 if (e.model == "" || self.modelindex == 0)
1878 setmodel(e, "null");
1882 e.SendEntity = sendfunc;
1883 e.SendFlags = 0xFFFFFF;
1886 e.effects |= EF_NODEPTHTEST;
1890 e.nextthink = time + dt;
1891 e.think = SUB_Remove;
1895 void adaptor_think2touch()
1904 void adaptor_think2use()
1916 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1918 if not(self.flags & FL_ONGROUND) // if onground, we ARE touching something, but HITTYPE_SPLASH is to be networked if the damage causing projectile is not touching ANYTHING
1919 self.projectiledeathtype |= HITTYPE_SPLASH;
1920 adaptor_think2use();
1923 // deferred dropping
1924 void DropToFloor_Handler()
1926 droptofloor_builtin();
1927 self.dropped_origin = self.origin;
1932 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1937 float trace_hits_box_a0, trace_hits_box_a1;
1939 float trace_hits_box_1d(float end, float thmi, float thma)
1943 // just check if x is in range
1951 // do the trace with respect to x
1952 // 0 -> end has to stay in thmi -> thma
1953 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1954 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1955 if (trace_hits_box_a0 > trace_hits_box_a1)
1961 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1966 // now it is a trace from 0 to end
1968 trace_hits_box_a0 = 0;
1969 trace_hits_box_a1 = 1;
1971 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1973 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1975 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1981 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1983 return trace_hits_box(start, end, thmi - ma, thma - mi);
1986 float SUB_NoImpactCheck()
1988 // zero hitcontents = this is not the real impact, but either the
1989 // mirror-impact of something hitting the projectile instead of the
1990 // projectile hitting the something, or a touchareagrid one. Neither of
1991 // these stop the projectile from moving, so...
1992 if(trace_dphitcontents == 0)
1994 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1997 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1999 if (other == world && self.size != '0 0 0')
2002 tic = self.velocity * sys_frametime;
2003 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
2004 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
2005 if (trace_fraction >= 1)
2007 dprint("Odd... did not hit...?\n");
2009 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2011 dprint("Detected and prevented the sky-grapple bug.\n");
2019 #define SUB_OwnerCheck() (other && (other == self.owner))
2021 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
2023 if(SUB_OwnerCheck())
2025 if(SUB_NoImpactCheck())
2030 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
2031 UpdateCSQCProjectileNextFrame(self);
2034 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
2036 float MAX_IPBAN_URIS = 16;
2038 float URI_GET_DISCARD = 0;
2039 float URI_GET_IPBAN = 1;
2040 float URI_GET_IPBAN_END = 16;
2042 void URI_Get_Callback(float id, float status, string data)
2044 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2046 dprint("\nEnd of data.\n");
2048 if (id == URI_GET_DISCARD)
2052 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2055 OnlineBanList_URI_Get_Callback(id, status, data);
2059 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2063 void print_to(entity e, string s)
2066 sprint(e, strcat(s, "\n"));
2071 string uid2name(string myuid) {
2073 // store uid in separate uid2name db IF CLIENT ALLOWS THIS
2074 // - make it global for all mods
2075 // perhaps show 10 first digits here if missing name?
2077 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
2080 s = "^1Unregistered Player";
2084 float race_GetTime(string map, float pos)
2092 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
2095 string race_GetUID(string map, float pos)
2103 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
2106 string race_GetName(string map, float pos)
2114 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
2117 string race_PlaceName(float pos) {
2118 if(floor((pos % 100)/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
2121 return strcat(ftos(pos), "st");
2122 else if(pos % 10 == 2)
2123 return strcat(ftos(pos), "nd");
2124 else if(pos % 10 == 3)
2125 return strcat(ftos(pos), "rd");
2127 return strcat(ftos(pos), "th");
2130 return strcat(ftos(pos), "th");
2132 string getrecords(float page) // 50 records per page
2146 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
2148 if (MapInfo_Get_ByID(i))
2150 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2154 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2155 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2163 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
2165 if (MapInfo_Get_ByID(i))
2167 r = race_GetTime(MapInfo_Map_bspname, 1);
2170 h = race_GetName(MapInfo_Map_bspname, 1)
2171 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2179 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
2181 if (MapInfo_Get_ByID(i))
2183 r = race_GetTime(MapInfo_Map_bspname, 1);
2186 h = race_GetName(MapInfo_Map_bspname, 1)
2187 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2193 MapInfo_ClearTemps();
2195 if (s == "" && page == 0)
2196 return "No records are available on this server.\n";
2201 string getrankings()
2214 for (i = 1; i <= RANKINGS_CNT; ++i)
2216 t = race_GetTime(map, i);
2219 n = race_GetName(map, i);
2220 p = race_PlaceName(i);
2221 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
2224 MapInfo_ClearTemps();
2227 return strcat("No records are available for the map: ", map, "\n");
2229 return strcat("Records for ", map, ":\n", s);
2232 const float LADDER_FIRSTPOINT = 100;
2233 const float LADDER_CNT = 10; // position X still gives LADDER_FIRSTPOINT/X points
2234 const float LADDER_SIZE = 30; // ladder shows the top X players
2235 string top_uids[LADDER_SIZE];
2236 float top_scores[LADDER_SIZE];
2241 string s, len, temp_s;
2248 for (k = 0; k < MapInfo_count; ++k)
2250 if (MapInfo_Get_ByID(k))
2252 for (i = 0; i < LADDER_CNT; ++i) {
2253 if(stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "time", ftos(Ii)))) == 0)
2256 myuid = db_get(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp", ftos(i)));
2258 // string s contains:
2259 // arg 0 = # of speed recs
2260 // arg 1 = # of 1st place recs
2261 // arg 2 = # of 2nd place recs
2263 // LADDER_CNT+1 = total points
2265 temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
2268 db_put(TemporaryDB, strcat("uid", ftos(UIDCNT)), myuid);
2270 for (j = 0; j <= LADDER_CNT + 1; ++j)
2272 if(j != LADDER_CNT + 1)
2273 temp_s = strcat(temp_s, "0 ");
2275 temp_s = strcat(temp_s, "0");
2279 len = tokenize_console(temp_s);
2282 if(i == 0) // speedrec
2283 for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
2285 if(j == 0) // speed rec!
2286 s = strcat(s, ftos(stof(argv(j)) +1)); // add 1 to speed rec count and write
2288 s = strcat(s, " ", argv(j)); // just copy over everything else
2291 for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
2294 s = strcat(s, argv(j)); // speed rec, dont prefix with " "
2295 else if(j == i) // wanted rec!
2296 s = strcat(s, " ", ftos(stof(argv(j)) +1)); // update argv(j)
2298 s = strcat(s, " ", argv(j)); // just copy over everything else
2301 // total points are (by default) calculated like this:
2302 // speedrec = floor(100 / 10) = 10 points
2303 // 1st place = floor(100 / 1) = 100 points
2304 // 2nd place = floor(100 / 2) = 50 points
2305 // 3rd place = floor(100 / 3) = 33 points
2306 // 4th place = floor(100 / 4) = 25 points
2307 // 5th place = floor(100 / 5) = 20 points
2311 s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + LADDER_FIRSTPOINT / 10)); // speedrec, add LADDER_FIRSTPOINT / 10 points
2313 s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
2315 db_put(TemporaryDB, strcat("ladder", myuid), s);
2323 for (i = 0; i <= UIDCNT; ++i) // for each known uid
2325 thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
2326 temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
2327 len = tokenize_console(temp_s);
2328 thiscnt = stof(argv(LADDER_CNT+1));
2330 if(thiscnt > top_scores[LADDER_SIZE-1])
2331 for (j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
2333 if(thiscnt > top_scores[j])
2335 for (k = LADDER_SIZE-1; k >= j; --k)
2337 top_uids[k] = top_uids[k-1];
2338 top_scores[k] = top_scores[k-1];
2340 top_uids[j] = thisuid;
2341 top_scores[j] = thiscnt;
2347 s = "^3-----------------------\n\n";
2349 s = strcat(s, "Pos ^3|");
2350 s = strcat(s, " ^7Total ^3|");
2351 for (i = 1; i <= LADDER_CNT; ++i)
2353 s = strcat(s, " ^7", race_PlaceName(i), " ^3|");
2355 s = strcat(s, " ^7Speed awards ^3| ^7Name");
2357 s = strcat(s, "\n^3----+--------");
2358 for (i = 1; i <= LADDER_CNT; ++i)
2360 s = strcat(s, "+-----");
2362 s = strcat(s, "+--------------+--------------------\n");
2364 for (i = 0; i < LADDER_SIZE; ++i)
2366 temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
2367 len = tokenize_console(temp_s);
2368 if (argv(LADDER_CNT+1) == "") // total is 0, skip
2370 s = strcat(s, strpad(4, race_PlaceName(i+1)), "^3| ^7"); // pos
2371 s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total
2372 for (j = 1; j <= LADDER_CNT; ++j)
2374 s = strcat(s, strpad(4, argv(j)), "^3| ^7"); // 1st, 2nd, 3rd etc cnt
2376 s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed rec cnt
2377 s = strcat(s, race_GetName_OfUID(top_uids[i]), "\n"); // name
2380 MapInfo_ClearTemps();
2383 return "No ladder on this server!\n";
2385 return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
2389 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2392 vector start, org, delta, end, enddown, mstart;
2394 m = e.dphitcontentsmask;
2395 e.dphitcontentsmask = goodcontents | badcontents;
2398 delta = world.maxs - world.mins;
2400 for (i = 0; i < attempts; ++i)
2402 start_x = org_x + random() * delta_x;
2403 start_y = org_y + random() * delta_y;
2404 start_z = org_z + random() * delta_z;
2406 // rule 1: start inside world bounds, and outside
2407 // solid, and don't start from somewhere where you can
2408 // fall down to evil
2409 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2410 if (trace_fraction >= 1)
2412 if (trace_startsolid)
2414 if (trace_dphitcontents & badcontents)
2416 if (trace_dphitq3surfaceflags & badsurfaceflags)
2419 // rule 2: if we are too high, lower the point
2420 if (trace_fraction * delta_z > maxaboveground)
2421 start = trace_endpos + '0 0 1' * maxaboveground;
2422 enddown = trace_endpos;
2424 // rule 3: make sure we aren't outside the map. This only works
2425 // for somewhat well formed maps. A good rule of thumb is that
2426 // the map should have a convex outside hull.
2427 // these can be traceLINES as we already verified the starting box
2428 mstart = start + 0.5 * (e.mins + e.maxs);
2429 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2430 if (trace_fraction >= 1)
2432 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2433 if (trace_fraction >= 1)
2435 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2436 if (trace_fraction >= 1)
2438 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2439 if (trace_fraction >= 1)
2441 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2442 if (trace_fraction >= 1)
2445 // find a random vector to "look at"
2446 end_x = org_x + random() * delta_x;
2447 end_y = org_y + random() * delta_y;
2448 end_z = org_z + random() * delta_z;
2449 end = start + normalize(end - start) * vlen(delta);
2451 // rule 4: start TO end must not be too short
2452 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2453 if (trace_startsolid)
2455 if (trace_fraction < minviewdistance / vlen(delta))
2458 // rule 5: don't want to look at sky
2459 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2462 // rule 6: we must not end up in trigger_hurt
2463 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2465 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2472 e.dphitcontentsmask = m;
2476 setorigin(e, start);
2477 e.angles = vectoangles(end - start);
2478 dprint("Needed ", ftos(i + 1), " attempts\n");
2485 float zcurveparticles_effectno;
2486 vector zcurveparticles_start;
2487 float zcurveparticles_spd;
2489 void endzcurveparticles()
2491 if(zcurveparticles_effectno)
2494 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2496 zcurveparticles_effectno = 0;
2499 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2501 spd = bound(0, floor(spd / 16), 32767);
2502 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2504 endzcurveparticles();
2505 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2506 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2507 WriteShort(MSG_BROADCAST, effectno);
2508 WriteCoord(MSG_BROADCAST, start_x);
2509 WriteCoord(MSG_BROADCAST, start_y);
2510 WriteCoord(MSG_BROADCAST, start_z);
2511 zcurveparticles_effectno = effectno;
2512 zcurveparticles_start = start;
2515 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2516 WriteCoord(MSG_BROADCAST, end_x);
2517 WriteCoord(MSG_BROADCAST, end_y);
2518 WriteCoord(MSG_BROADCAST, end_z);
2519 WriteCoord(MSG_BROADCAST, end_dz);
2520 zcurveparticles_spd = spd;
2523 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2526 vector vecxy, velxy;
2528 vecxy = end - start;
2533 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2535 endzcurveparticles();
2536 trailparticles(world, effectno, start, end);
2540 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2541 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2544 string GetGametype(); // g_world.qc
2545 void write_recordmarker(entity pl, float tstart, float dt)
2547 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2549 // also write a marker into demo files for demotc-race-record-extractor to find
2552 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2553 " ", ftos(tstart), " ", ftos(dt), "\n"));
2556 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2569 if(allowcenter) // 2: allow center handedness
2582 if(allowcenter) // 2: allow center handedness
2598 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2603 if (cvar("g_shootfromeye"))
2607 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE, algn);
2615 else if (cvar("g_shootfromcenter"))
2619 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE, algn);
2627 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2637 else if (cvar("g_shootfromclient"))
2639 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2), algn);
2644 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2646 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2650 void attach_sameorigin(entity e, entity to, string tag)
2652 vector org, t_forward, t_left, t_up, e_forward, e_up;
2659 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2660 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2661 t_forward = v_forward * tagscale;
2662 t_left = v_right * -tagscale;
2663 t_up = v_up * tagscale;
2665 e.origin_x = org * t_forward;
2666 e.origin_y = org * t_left;
2667 e.origin_z = org * t_up;
2669 // current forward and up directions
2670 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2671 e.angles = AnglesTransform_FromVAngles(e.angles);
2673 e.angles = AnglesTransform_FromAngles(e.angles);
2674 fixedmakevectors(e.angles);
2676 // untransform forward, up!
2677 e_forward_x = v_forward * t_forward;
2678 e_forward_y = v_forward * t_left;
2679 e_forward_z = v_forward * t_up;
2680 e_up_x = v_up * t_forward;
2681 e_up_y = v_up * t_left;
2682 e_up_z = v_up * t_up;
2684 e.angles = fixedvectoangles2(e_forward, e_up);
2685 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2686 e.angles = AnglesTransform_ToVAngles(e.angles);
2688 e.angles = AnglesTransform_ToAngles(e.angles);
2690 setattachment(e, to, tag);
2691 setorigin(e, e.origin);
2694 void detach_sameorigin(entity e)
2697 org = gettaginfo(e, 0);
2698 e.angles = fixedvectoangles2(v_forward, v_up);
2699 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2700 e.angles = AnglesTransform_ToVAngles(e.angles);
2702 e.angles = AnglesTransform_ToAngles(e.angles);
2704 setattachment(e, world, "");
2705 setorigin(e, e.origin);
2708 void follow_sameorigin(entity e, entity to)
2710 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2711 e.aiment = to; // make the hole follow bmodel
2712 e.punchangle = to.angles; // the original angles of bmodel
2713 e.view_ofs = e.origin - to.origin; // relative origin
2714 e.v_angle = e.angles - to.angles; // relative angles
2717 void unfollow_sameorigin(entity e)
2719 e.movetype = MOVETYPE_NONE;
2722 entity gettaginfo_relative_ent;
2723 vector gettaginfo_relative(entity e, float tag)
2725 if (!gettaginfo_relative_ent)
2727 gettaginfo_relative_ent = spawn();
2728 gettaginfo_relative_ent.effects = EF_NODRAW;
2730 gettaginfo_relative_ent.model = e.model;
2731 gettaginfo_relative_ent.modelindex = e.modelindex;
2732 gettaginfo_relative_ent.frame = e.frame;
2733 return gettaginfo(gettaginfo_relative_ent, tag);
2736 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2740 if (pl.soundentity.cnt & p)
2742 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2743 pl.soundentity.cnt |= p;
2746 void SoundEntity_StopSound(entity pl, float chan)
2750 if (pl.soundentity.cnt & p)
2752 stopsoundto(MSG_ALL, pl.soundentity, chan);
2753 pl.soundentity.cnt &~= p;
2757 void SoundEntity_Attach(entity pl)
2759 pl.soundentity = spawn();
2760 pl.soundentity.classname = "soundentity";
2761 pl.soundentity.owner = pl;
2762 setattachment(pl.soundentity, pl, "");
2763 setmodel(pl.soundentity, "null");
2766 void SoundEntity_Detach(entity pl)
2769 for (i = 0; i <= 7; ++i)
2770 SoundEntity_StopSound(pl, i);
2774 float ParseCommandPlayerSlotTarget_firsttoken;
2775 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2783 ParseCommandPlayerSlotTarget_firsttoken = -1;
2787 if (substring(argv(idx), 0, 1) == "#")
2789 s = substring(argv(idx), 1, -1);
2797 ParseCommandPlayerSlotTarget_firsttoken = idx;
2798 if (s == ftos(stof(s)))
2800 e = edict_num(stof(s));
2801 if (e.flags & FL_CLIENT)
2807 // it must be a nick name
2810 ParseCommandPlayerSlotTarget_firsttoken = idx;
2813 FOR_EACH_CLIENT(head)
2814 if (head.netname == s)
2822 s = strdecolorize(s);
2824 FOR_EACH_CLIENT(head)
2825 if (strdecolorize(head.netname) == s)
2840 float modeleffect_SendEntity(entity to, float sf)
2843 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2846 if(self.velocity != '0 0 0')
2848 if(self.angles != '0 0 0')
2850 if(self.avelocity != '0 0 0')
2853 WriteByte(MSG_ENTITY, f);
2854 WriteShort(MSG_ENTITY, self.modelindex);
2855 WriteByte(MSG_ENTITY, self.skin);
2856 WriteByte(MSG_ENTITY, self.frame);
2857 WriteCoord(MSG_ENTITY, self.origin_x);
2858 WriteCoord(MSG_ENTITY, self.origin_y);
2859 WriteCoord(MSG_ENTITY, self.origin_z);
2862 WriteCoord(MSG_ENTITY, self.velocity_x);
2863 WriteCoord(MSG_ENTITY, self.velocity_y);
2864 WriteCoord(MSG_ENTITY, self.velocity_z);
2868 WriteCoord(MSG_ENTITY, self.angles_x);
2869 WriteCoord(MSG_ENTITY, self.angles_y);
2870 WriteCoord(MSG_ENTITY, self.angles_z);
2874 WriteCoord(MSG_ENTITY, self.avelocity_x);
2875 WriteCoord(MSG_ENTITY, self.avelocity_y);
2876 WriteCoord(MSG_ENTITY, self.avelocity_z);
2878 WriteShort(MSG_ENTITY, self.scale * 256.0);
2879 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2880 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2881 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2882 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2887 void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2)
2892 e.classname = "modeleffect";
2900 e.teleport_time = t1;
2904 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2908 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2911 sz = max(e.scale, e.scale2);
2912 setsize(e, e.mins * sz, e.maxs * sz);
2913 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2916 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2918 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2921 float randombit(float bits)
2923 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2932 for(f = 1; f <= bits; f *= 2)
2941 r = (r - 1) / (n - 1);
2948 float randombits(float bits, float k, float error_return)
2952 while(k > 0 && bits != r)
2954 r += randombit(bits - r);
2963 void randombit_test(float bits, float iter)
2967 print(ftos(randombit(bits)), "\n");
2972 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2974 if(halflifedist > 0)
2975 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2976 else if(halflifedist < 0)
2977 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2986 #define cvar_string_normal cvar_string_builtin
2987 #define cvar_normal cvar_builtin
2989 string cvar_string_normal(string n)
2991 if not(cvar_type(n) & 1)
2992 backtrace(strcat("Attempt to access undefined cvar: ", n));
2993 return cvar_string_builtin(n);
2996 float cvar_normal(string n)
2998 return stof(cvar_string_normal(n));
3001 #define cvar_set_normal cvar_set_builtin
3009 oself.think = SUB_Remove;
3010 oself.nextthink = time;
3016 Execute func() after time + fdelay.
3017 self when func is executed = self when defer is called
3019 void defer(float fdelay, void() func)
3026 e.think = defer_think;
3027 e.nextthink = time + fdelay;