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;
20 string ColoredTeamName(float t);
22 string admin_name(void)
24 if(autocvar_sv_adminnick != "")
25 return autocvar_sv_adminnick;
27 return "SERVER ADMIN";
30 float DistributeEvenly_amount;
31 float DistributeEvenly_totalweight;
32 void DistributeEvenly_Init(float amount, float totalweight)
34 if (DistributeEvenly_amount)
36 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
37 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
40 DistributeEvenly_amount = 0;
42 DistributeEvenly_amount = amount;
43 DistributeEvenly_totalweight = totalweight;
45 float DistributeEvenly_Get(float weight)
50 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
51 DistributeEvenly_totalweight -= weight;
52 DistributeEvenly_amount -= f;
56 #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
59 string STR_PLAYER = "player";
60 string STR_SPECTATOR = "spectator";
61 string STR_OBSERVER = "observer";
64 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
65 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
66 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
67 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
69 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
70 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
71 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
72 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
73 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
76 // copies a string to a tempstring (so one can strunzone it)
77 string strcat1(string s) = #115; // FRIK_FILE
82 void bcenterprint(string s)
84 // TODO replace by MSG_ALL (would show it to spectators too, though)?
87 if (clienttype(head) == CLIENTTYPE_REAL)
91 void GameLogEcho(string s)
96 if (autocvar_sv_eventlog_files)
101 matches = autocvar_sv_eventlog_files_counter + 1;
102 cvar_set("sv_eventlog_files_counter", ftos(matches));
105 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
106 fn = strcat(autocvar_sv_eventlog_files_nameprefix, fn, autocvar_sv_eventlog_files_namesuffix);
107 logfile = fopen(fn, FILE_APPEND);
108 fputs(logfile, ":logversion:3\n");
112 if (autocvar_sv_eventlog_files_timestamps)
113 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
115 fputs(logfile, strcat(s, "\n"));
118 if (autocvar_sv_eventlog_console)
127 // will be opened later
132 if (logfile_open && logfile >= 0)
143 vector PL_CROUCH_VIEW_OFS;
144 vector PL_CROUCH_MIN;
145 vector PL_CROUCH_MAX;
147 float spawnpoint_nag;
148 void relocate_spawnpoint()
150 PL_VIEW_OFS = stov(autocvar_sv_player_viewoffset);
151 PL_MIN = stov(autocvar_sv_player_mins);
152 PL_MAX = stov(autocvar_sv_player_maxs);
153 PL_HEAD = stov(autocvar_sv_player_headsize);
154 PL_CROUCH_VIEW_OFS = stov(autocvar_sv_player_crouch_viewoffset);
155 PL_CROUCH_MIN = stov(autocvar_sv_player_crouch_mins);
156 PL_CROUCH_MAX = stov(autocvar_sv_player_crouch_maxs);
158 // nudge off the floor
159 setorigin(self, self.origin + '0 0 1');
161 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
162 if (trace_startsolid)
168 if (!move_out_of_solid(self))
169 objerror("could not get out of solid at all!");
170 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
171 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
172 print(" ", ftos(self.origin_y - o_y));
173 print(" ", ftos(self.origin_z - o_z), "'\n");
174 if (autocvar_g_spawnpoints_auto_move_out_of_solid)
177 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
183 self.mins = self.maxs = '0 0 0';
184 objerror("player spawn point in solid, mapper sucks!\n");
189 self.use = spawnpoint_use;
190 self.team_saved = self.team;
194 if (have_team_spawns != 0)
196 have_team_spawns = 1;
197 have_team_spawns_forteam[self.team] = 1;
199 if (autocvar_r_showbboxes)
201 // show where spawnpoints point at too
202 makevectors(self.angles);
205 e.classname = "info_player_foo";
206 setorigin(e, self.origin + v_forward * 24);
207 setsize(e, '-8 -8 -8', '8 8 8');
208 e.solid = SOLID_TRIGGER;
212 #define strstr strstrofs
214 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
215 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
216 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
217 // BE CONSTANT OR strzoneD!
218 float strstr(string haystack, string needle, float offset)
222 len = strlen(needle);
223 endpos = strlen(haystack) - len;
224 while(offset <= endpos)
226 found = substring(haystack, offset, len);
235 float NUM_NEAREST_ENTITIES = 4;
236 entity nearest_entity[NUM_NEAREST_ENTITIES];
237 float nearest_length[NUM_NEAREST_ENTITIES];
238 entity findnearest(vector point, .string field, string value, vector axismod)
249 localhead = find(world, field, value);
252 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
253 dist = localhead.oldorigin;
255 dist = localhead.origin;
257 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
260 for (i = 0; i < num_nearest; ++i)
262 if (len < nearest_length[i])
266 // now i tells us where to insert at
267 // INSERTION SORT! YOU'VE SEEN IT! RUN!
268 if (i < NUM_NEAREST_ENTITIES)
270 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
272 nearest_length[j + 1] = nearest_length[j];
273 nearest_entity[j + 1] = nearest_entity[j];
275 nearest_length[i] = len;
276 nearest_entity[i] = localhead;
277 if (num_nearest < NUM_NEAREST_ENTITIES)
278 num_nearest = num_nearest + 1;
281 localhead = find(localhead, field, value);
284 // now use the first one from our list that we can see
285 for (i = 0; i < num_nearest; ++i)
287 traceline(point, nearest_entity[i].origin, TRUE, world);
288 if (trace_fraction == 1)
292 dprint("Nearest point (");
293 dprint(nearest_entity[0].netname);
294 dprint(") is not visible, using a visible one.\n");
296 return nearest_entity[i];
300 if (num_nearest == 0)
303 dprint("Not seeing any location point, using nearest as fallback.\n");
305 dprint("Candidates were: ");
306 for(j = 0; j < num_nearest; ++j)
310 dprint(nearest_entity[j].netname);
315 return nearest_entity[0];
318 void spawnfunc_target_location()
320 self.classname = "target_location";
321 // location name in netname
322 // eventually support: count, teamgame selectors, line of sight?
325 void spawnfunc_info_location()
327 self.classname = "target_location";
328 self.message = self.netname;
331 string NearestLocation(vector p)
336 loc = findnearest(p, classname, "target_location", '1 1 1');
343 loc = findnearest(p, target, "###item###", '1 1 4');
350 string formatmessage(string msg)
361 WarpZone_crosshair_trace(self);
362 cursor = trace_endpos;
363 cursor_ent = trace_ent;
367 break; // too many replacements
370 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
371 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
384 replacement = substring(msg, p, 2);
385 escape = substring(msg, p + 1, 1);
389 else if (escape == "\\")
391 else if (escape == "n")
393 else if (escape == "a")
394 replacement = ftos(floor(self.armorvalue));
395 else if (escape == "h")
396 replacement = ftos(floor(self.health));
397 else if (escape == "l")
398 replacement = NearestLocation(self.origin);
399 else if (escape == "y")
400 replacement = NearestLocation(cursor);
401 else if (escape == "d")
402 replacement = NearestLocation(self.death_origin);
403 else if (escape == "w") {
407 wep = self.switchweapon;
410 replacement = W_Name(wep);
411 } else if (escape == "W") {
412 if (self.items & IT_SHELLS) replacement = "shells";
413 else if (self.items & IT_NAILS) replacement = "bullets";
414 else if (self.items & IT_ROCKETS) replacement = "rockets";
415 else if (self.items & IT_CELLS) replacement = "cells";
416 else replacement = "batteries"; // ;)
417 } else if (escape == "x") {
418 replacement = cursor_ent.netname;
419 if (!replacement || !cursor_ent)
420 replacement = "nothing";
421 } else if (escape == "s")
422 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
423 else if (escape == "S")
424 replacement = ftos(vlen(self.velocity));
426 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
427 p = p + strlen(replacement);
432 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
433 return (value == 0) ? FALSE : TRUE;
442 >0: receives a cvar from name=argv(f) value=argv(f+1)
444 void GetCvars_handleString(string thisname, float f, .string field, string name)
449 strunzone(self.field);
450 self.field = string_null;
454 if (thisname == name)
457 strunzone(self.field);
458 self.field = strzone(argv(f + 1));
462 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
464 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
466 GetCvars_handleString(thisname, f, field, name);
467 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
468 if (thisname == name)
471 s = func(strcat1(self.field));
474 strunzone(self.field);
475 self.field = strzone(s);
479 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
486 if (thisname == name)
487 self.field = stof(argv(f + 1));
490 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
492 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
499 if (thisname == name)
503 self.field = stof(argv(f + 1));
512 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
515 float w_getbestweapon(entity e);
516 string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(string wo)
519 o = W_FixWeaponOrder_ForceComplete(wo);
520 if(self.weaponorder_byimpulse)
522 strunzone(self.weaponorder_byimpulse);
523 self.weaponorder_byimpulse = string_null;
525 self.weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
528 void GetCvars(float f)
533 s = strcat1(argv(f));
537 MUTATOR_CALLHOOK(GetCvars);
538 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
539 GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
540 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
541 GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
542 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
543 GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
544 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
545 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
546 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
547 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
548 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
549 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
550 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
551 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
552 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
553 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
554 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
555 GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode");
556 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
557 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
558 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
559 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
560 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
561 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
563 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
564 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
566 #ifdef ALLOW_FORCEMODELS
567 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
568 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromxonotic, "cl_forceplayermodelsfromxonotic");
570 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
571 GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
572 GetCvars_handleFloat(s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
573 GetCvars_handleFloat(s, f, cvar_cl_movement_track_canjump, "cl_movement_track_canjump");
574 GetCvars_handleFloat(s, f, cvar_cl_newusekeysupported, "cl_newusekeysupported");
576 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
579 if (s == "cl_weaponpriority")
580 self.switchweapon = w_getbestweapon(self);
581 if (s == "cl_allow_uidtracking")
582 PlayerStats_AddPlayer(self);
586 void backtrace(string msg)
589 dev = autocvar_developer;
590 war = autocvar_prvm_backtraceforwarnings;
591 cvar_set("developer", "1");
592 cvar_set("prvm_backtraceforwarnings", "1");
594 print("--- CUT HERE ---\nWARNING: ");
597 remove(world); // isn't there any better way to cause a backtrace?
598 print("\n--- CUT UNTIL HERE ---\n");
599 cvar_set("developer", ftos(dev));
600 cvar_set("prvm_backtraceforwarnings", ftos(war));
603 string Team_ColorCode(float teamid)
605 if (teamid == COLOR_TEAM1)
607 else if (teamid == COLOR_TEAM2)
609 else if (teamid == COLOR_TEAM3)
611 else if (teamid == COLOR_TEAM4)
617 string Team_ColorName(float t)
619 // fixme: Search for team entities and get their .netname's!
620 if (t == COLOR_TEAM1)
622 if (t == COLOR_TEAM2)
624 if (t == COLOR_TEAM3)
626 if (t == COLOR_TEAM4)
631 string Team_ColorNameLowerCase(float t)
633 // fixme: Search for team entities and get their .netname's!
634 if (t == COLOR_TEAM1)
636 if (t == COLOR_TEAM2)
638 if (t == COLOR_TEAM3)
640 if (t == COLOR_TEAM4)
645 float ColourToNumber(string team_colour)
647 if (team_colour == "red")
650 if (team_colour == "blue")
653 if (team_colour == "yellow")
656 if (team_colour == "pink")
659 if (team_colour == "auto")
665 float NumberToTeamNumber(float number)
682 // decolorizes and team colors the player name when needed
683 string playername(entity p)
686 if (teamplay && !intermission_running && p.classname == "player")
688 t = Team_ColorCode(p.team);
689 return strcat(t, strdecolorize(p.netname));
695 vector randompos(vector m1, vector m2)
699 v_x = m2_x * random() + m1_x;
700 v_y = m2_y * random() + m1_y;
701 v_z = m2_z * random() + m1_z;
705 //#NO AUTOCVARS START
707 float g_pickup_shells;
708 float g_pickup_shells_max;
709 float g_pickup_nails;
710 float g_pickup_nails_max;
711 float g_pickup_rockets;
712 float g_pickup_rockets_max;
713 float g_pickup_cells;
714 float g_pickup_cells_max;
716 float g_pickup_fuel_jetpack;
717 float g_pickup_fuel_max;
718 float g_pickup_armorsmall;
719 float g_pickup_armorsmall_max;
720 float g_pickup_armorsmall_anyway;
721 float g_pickup_armormedium;
722 float g_pickup_armormedium_max;
723 float g_pickup_armormedium_anyway;
724 float g_pickup_armorbig;
725 float g_pickup_armorbig_max;
726 float g_pickup_armorbig_anyway;
727 float g_pickup_armorlarge;
728 float g_pickup_armorlarge_max;
729 float g_pickup_armorlarge_anyway;
730 float g_pickup_healthsmall;
731 float g_pickup_healthsmall_max;
732 float g_pickup_healthsmall_anyway;
733 float g_pickup_healthmedium;
734 float g_pickup_healthmedium_max;
735 float g_pickup_healthmedium_anyway;
736 float g_pickup_healthlarge;
737 float g_pickup_healthlarge_max;
738 float g_pickup_healthlarge_anyway;
739 float g_pickup_healthmega;
740 float g_pickup_healthmega_max;
741 float g_pickup_healthmega_anyway;
742 float g_pickup_ammo_anyway;
743 float g_pickup_weapons_anyway;
745 float g_weaponarena_random;
746 float g_weaponarena_random_with_laser;
747 string g_weaponarena_list;
748 float g_weaponspeedfactor;
749 float g_weaponratefactor;
750 float g_weapondamagefactor;
751 float g_weaponforcefactor;
752 float g_weaponspreadfactor;
756 float start_ammo_shells;
757 float start_ammo_nails;
758 float start_ammo_rockets;
759 float start_ammo_cells;
760 float start_ammo_fuel;
762 float start_armorvalue;
763 float warmup_start_weapons;
764 float warmup_start_ammo_shells;
765 float warmup_start_ammo_nails;
766 float warmup_start_ammo_rockets;
767 float warmup_start_ammo_cells;
768 float warmup_start_ammo_fuel;
769 float warmup_start_health;
770 float warmup_start_armorvalue;
774 entity get_weaponinfo(float w);
776 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
778 var float i = weaponinfo.weapon;
783 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
785 if (t < 0) // "default" weapon selection
787 if (g_lms || g_ca || allguns)
788 t = (weaponinfo.spawnflags & WEP_FLAG_NORMAL);
792 t = (i == WEP_SHOTGUN);
794 t = 0; // weapon is set a few lines later
796 t = (i == WEP_LASER || i == WEP_SHOTGUN);
797 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
798 t |= (i == WEP_HOOK);
801 // we cannot disable porto in Nexball, we must force it
802 if(g_nexball && i == WEP_PORTO)
808 void readplayerstartcvars()
814 // initialize starting values for players
817 start_ammo_shells = 0;
818 start_ammo_nails = 0;
819 start_ammo_rockets = 0;
820 start_ammo_cells = 0;
821 start_health = cvar("g_balance_health_start");
822 start_armorvalue = cvar("g_balance_armor_start");
825 s = cvar_string("g_weaponarena");
826 if (s == "0" || s == "")
832 if (s == "0" || s == "")
838 // forcibly turn off weaponarena
842 g_weaponarena_list = "All Weapons";
843 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
845 e = get_weaponinfo(j);
846 g_weaponarena |= e.weapons;
847 weapon_action(e.weapon, WR_PRECACHE);
850 else if (s == "most")
852 g_weaponarena_list = "Most Weapons";
853 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
855 e = get_weaponinfo(j);
856 if (e.spawnflags & WEP_FLAG_NORMAL)
858 g_weaponarena |= e.weapons;
859 weapon_action(e.weapon, WR_PRECACHE);
863 else if (s == "none")
865 g_weaponarena_list = "No Weapons";
866 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
870 t = tokenize_console(s);
871 g_weaponarena_list = "";
872 for (i = 0; i < t; ++i)
875 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
877 e = get_weaponinfo(j);
880 g_weaponarena |= e.weapons;
881 weapon_action(e.weapon, WR_PRECACHE);
882 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
888 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
891 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
895 g_weaponarena_random = cvar("g_weaponarena_random");
897 g_weaponarena_random = 0;
898 g_weaponarena_random_with_laser = cvar("g_weaponarena_random_with_laser");
902 start_weapons = g_weaponarena;
904 start_items |= IT_UNLIMITED_AMMO;
906 else if (g_minstagib)
909 start_armorvalue = 0;
910 start_weapons = WEPBIT_MINSTANEX;
911 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
912 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
914 if (g_minstagib_invis_alpha <= 0)
915 g_minstagib_invis_alpha = -1;
919 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
921 e = get_weaponinfo(i);
922 if(want_weapon("g_start_weapon_", e, FALSE))
923 start_weapons |= e.weapons;
927 if(!cvar("g_use_ammunition"))
928 start_items |= IT_UNLIMITED_AMMO;
932 start_ammo_cells = cvar("g_minstagib_ammo_start");
933 start_ammo_fuel = cvar("g_start_ammo_fuel");
935 else if(start_items & IT_UNLIMITED_WEAPON_AMMO)
937 start_ammo_rockets = 999;
938 start_ammo_shells = 999;
939 start_ammo_cells = 999;
940 start_ammo_nails = 999;
941 start_ammo_fuel = 999;
947 start_ammo_shells = cvar("g_lms_start_ammo_shells");
948 start_ammo_nails = cvar("g_lms_start_ammo_nails");
949 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
950 start_ammo_cells = cvar("g_lms_start_ammo_cells");
951 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
955 start_ammo_shells = cvar("g_start_ammo_shells");
956 start_ammo_nails = cvar("g_start_ammo_nails");
957 start_ammo_rockets = cvar("g_start_ammo_rockets");
958 start_ammo_cells = cvar("g_start_ammo_cells");
959 start_ammo_fuel = cvar("g_start_ammo_fuel");
965 start_health = cvar("g_lms_start_health");
966 start_armorvalue = cvar("g_lms_start_armor");
971 warmup_start_ammo_shells = start_ammo_shells;
972 warmup_start_ammo_nails = start_ammo_nails;
973 warmup_start_ammo_rockets = start_ammo_rockets;
974 warmup_start_ammo_cells = start_ammo_cells;
975 warmup_start_ammo_fuel = start_ammo_fuel;
976 warmup_start_health = start_health;
977 warmup_start_armorvalue = start_armorvalue;
978 warmup_start_weapons = start_weapons;
980 if (!g_weaponarena && !g_minstagib && !g_ca)
982 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
983 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
984 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
985 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
986 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
987 warmup_start_health = cvar("g_warmup_start_health");
988 warmup_start_armorvalue = cvar("g_warmup_start_armor");
989 warmup_start_weapons = 0;
990 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
992 e = get_weaponinfo(i);
993 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
994 warmup_start_weapons |= e.weapons;
999 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1001 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1002 start_items |= IT_FUEL_REGEN;
1003 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1004 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1008 start_items |= IT_JETPACK;
1010 if (g_weapon_stay == 2)
1012 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1013 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1014 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1015 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1016 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1017 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1018 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1019 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1020 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1021 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1024 MUTATOR_CALLHOOK(SetStartItems);
1026 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1028 e = get_weaponinfo(i);
1029 if(e.weapons & (start_weapons | warmup_start_weapons))
1030 weapon_action(e.weapon, WR_PRECACHE);
1033 start_ammo_shells = max(0, start_ammo_shells);
1034 start_ammo_nails = max(0, start_ammo_nails);
1035 start_ammo_cells = max(0, start_ammo_cells);
1036 start_ammo_rockets = max(0, start_ammo_rockets);
1037 start_ammo_fuel = max(0, start_ammo_fuel);
1039 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1040 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1041 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1042 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1043 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1047 float g_bugrigs_planar_movement;
1048 float g_bugrigs_planar_movement_car_jumping;
1049 float g_bugrigs_reverse_spinning;
1050 float g_bugrigs_reverse_speeding;
1051 float g_bugrigs_reverse_stopping;
1052 float g_bugrigs_air_steering;
1053 float g_bugrigs_angle_smoothing;
1054 float g_bugrigs_friction_floor;
1055 float g_bugrigs_friction_brake;
1056 float g_bugrigs_friction_air;
1057 float g_bugrigs_accel;
1058 float g_bugrigs_speed_ref;
1059 float g_bugrigs_speed_pow;
1060 float g_bugrigs_steer;
1062 float g_touchexplode;
1063 float g_touchexplode_radius;
1064 float g_touchexplode_damage;
1065 float g_touchexplode_edgedamage;
1066 float g_touchexplode_force;
1073 float sv_pitch_fixyaw;
1075 string GetGametype(); // g_world.qc
1076 void readlevelcvars(void)
1078 // first load all the mutators
1079 if(cvar("g_invincible_projectiles"))
1080 MUTATOR_ADD(mutator_invincibleprojectiles);
1082 MUTATOR_ADD(mutator_nix);
1083 if(cvar("g_dodging"))
1084 MUTATOR_ADD(mutator_dodging);
1085 if(cvar("g_rocket_flying"))
1086 MUTATOR_ADD(mutator_rocketflying);
1087 if(cvar("g_vampire"))
1088 MUTATOR_ADD(mutator_vampire);
1089 if(cvar("g_spawn_near_teammate"))
1090 MUTATOR_ADD(mutator_spawn_near_teammate);
1092 if(cvar("sv_allow_fullbright"))
1093 serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
1095 g_bugrigs = cvar("g_bugrigs");
1096 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1097 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1098 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1099 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1100 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1101 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1102 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1103 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1104 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1105 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1106 g_bugrigs_accel = cvar("g_bugrigs_accel");
1107 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1108 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1109 g_bugrigs_steer = cvar("g_bugrigs_steer");
1111 g_touchexplode = cvar("g_touchexplode");
1112 g_touchexplode_radius = cvar("g_touchexplode_radius");
1113 g_touchexplode_damage = cvar("g_touchexplode_damage");
1114 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1115 g_touchexplode_force = cvar("g_touchexplode_force");
1117 #ifdef ALLOW_FORCEMODELS
1118 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1120 sv_loddistance1 = cvar("sv_loddistance1");
1121 sv_loddistance2 = cvar("sv_loddistance2");
1123 if(sv_loddistance2 <= sv_loddistance1)
1124 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1126 sv_clones = cvar("sv_clones");
1127 sv_gentle = cvar("sv_gentle");
1128 sv_foginterval = cvar("sv_foginterval");
1129 g_cloaked = cvar("g_cloaked");
1131 g_cloaked = 1; // always enable cloak in CTS
1132 g_jump_grunt = cvar("g_jump_grunt");
1133 g_footsteps = cvar("g_footsteps");
1134 g_grappling_hook = cvar("g_grappling_hook");
1135 g_jetpack = cvar("g_jetpack");
1136 g_midair = cvar("g_midair");
1137 g_minstagib = cvar("g_minstagib");
1138 g_norecoil = cvar("g_norecoil");
1139 g_bloodloss = cvar("g_bloodloss");
1140 sv_maxidle = cvar("sv_maxidle");
1141 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1142 g_ctf_reverse = cvar("g_ctf_reverse");
1143 sv_autotaunt = cvar("sv_autotaunt");
1144 sv_taunt = cvar("sv_taunt");
1146 inWarmupStage = cvar("g_warmup");
1147 g_warmup_limit = cvar("g_warmup_limit");
1148 g_warmup_allguns = cvar("g_warmup_allguns");
1149 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1151 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1152 inWarmupStage = 0; // these modes cannot work together, sorry
1154 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1155 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1156 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1157 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1158 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1159 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1160 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1161 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1162 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1163 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1164 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1165 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1167 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1168 g_weaponratefactor = cvar("g_weaponratefactor");
1169 g_weapondamagefactor = cvar("g_weapondamagefactor");
1170 g_weaponforcefactor = cvar("g_weaponforcefactor");
1171 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1173 g_pickup_shells = cvar("g_pickup_shells");
1174 g_pickup_shells_max = cvar("g_pickup_shells_max");
1175 g_pickup_nails = cvar("g_pickup_nails");
1176 g_pickup_nails_max = cvar("g_pickup_nails_max");
1177 g_pickup_rockets = cvar("g_pickup_rockets");
1178 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1179 g_pickup_cells = cvar("g_pickup_cells");
1180 g_pickup_cells_max = cvar("g_pickup_cells_max");
1181 g_pickup_fuel = cvar("g_pickup_fuel");
1182 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1183 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1184 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1185 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1186 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1187 g_pickup_armormedium = cvar("g_pickup_armormedium");
1188 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1189 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1190 g_pickup_armorbig = cvar("g_pickup_armorbig");
1191 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1192 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1193 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1194 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1195 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1196 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1197 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1198 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1199 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1200 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1201 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1202 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1203 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1204 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1205 g_pickup_healthmega = cvar("g_pickup_healthmega");
1206 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1207 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1209 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1210 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1212 g_pinata = cvar("g_pinata");
1214 g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
1216 g_weapon_stay = cvar("g_weapon_stay");
1218 g_ghost_items = cvar("g_ghost_items");
1220 if(g_ghost_items >= 1)
1221 g_ghost_items = 0.25; // default alpha value
1223 if not(inWarmupStage && !g_ca)
1224 game_starttime = cvar("g_start_delay");
1226 sv_pitch_min = cvar("sv_pitch_min");
1227 sv_pitch_max = cvar("sv_pitch_max");
1228 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1230 readplayerstartcvars();
1236 string precache_sound (string s) = #19;
1237 float precache_sound_index (string s) = #19;
1239 #define SND_VOLUME 1
1240 #define SND_ATTENUATION 2
1241 #define SND_LARGEENTITY 8
1242 #define SND_LARGESOUND 16
1244 float sound_allowed(float dest, entity e)
1246 // sounds from world may always pass
1249 if (e.classname == "body")
1251 else if (e.realowner && e.realowner != e)
1253 else if (e.owner && e.owner != e)
1258 // sounds to self may always pass
1259 if (dest == MSG_ONE)
1260 if (e == msg_entity)
1262 // sounds by players can be removed
1263 if (autocvar_bot_sound_monopoly)
1264 if (clienttype(e) == CLIENTTYPE_REAL)
1266 // anything else may pass
1270 #ifdef COMPAT_XON010_CHANNELS
1271 void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
1272 void sound(entity e, float chan, string samp, float vol, float atten)
1274 if (!sound_allowed(MSG_BROADCAST, e))
1276 builtin_sound(e, chan, samp, vol, atten);
1280 void sound(entity e, float chan, string samp, float vol, float atten)
1282 if (!sound_allowed(MSG_BROADCAST, e))
1284 sound7(e, chan, samp, vol, atten, 0, 0);
1288 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1292 if (!sound_allowed(dest, e))
1295 entno = num_for_edict(e);
1296 idx = precache_sound_index(samp);
1301 atten = floor(atten * 64);
1302 vol = floor(vol * 255);
1305 sflags |= SND_VOLUME;
1307 sflags |= SND_ATTENUATION;
1308 if (entno >= 8192 || chan < 0 || chan > 7)
1309 sflags |= SND_LARGEENTITY;
1311 sflags |= SND_LARGESOUND;
1313 WriteByte(dest, SVC_SOUND);
1314 WriteByte(dest, sflags);
1315 if (sflags & SND_VOLUME)
1316 WriteByte(dest, vol);
1317 if (sflags & SND_ATTENUATION)
1318 WriteByte(dest, atten);
1319 if (sflags & SND_LARGEENTITY)
1321 WriteShort(dest, entno);
1322 WriteByte(dest, chan);
1326 WriteShort(dest, entno * 8 + chan);
1328 if (sflags & SND_LARGESOUND)
1329 WriteShort(dest, idx);
1331 WriteByte(dest, idx);
1333 WriteCoord(dest, o_x);
1334 WriteCoord(dest, o_y);
1335 WriteCoord(dest, o_z);
1337 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1341 if (!sound_allowed(dest, e))
1344 o = e.origin + 0.5 * (e.mins + e.maxs);
1345 soundtoat(dest, e, o, chan, samp, vol, atten);
1347 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1349 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, atten);
1351 void stopsoundto(float dest, entity e, float chan)
1355 if (!sound_allowed(dest, e))
1358 entno = num_for_edict(e);
1360 if (entno >= 8192 || chan < 0 || chan > 7)
1363 idx = precache_sound_index("misc/null.wav");
1364 sflags = SND_LARGEENTITY;
1366 sflags |= SND_LARGESOUND;
1367 WriteByte(dest, SVC_SOUND);
1368 WriteByte(dest, sflags);
1369 WriteShort(dest, entno);
1370 WriteByte(dest, chan);
1371 if (sflags & SND_LARGESOUND)
1372 WriteShort(dest, idx);
1374 WriteByte(dest, idx);
1375 WriteCoord(dest, e.origin_x);
1376 WriteCoord(dest, e.origin_y);
1377 WriteCoord(dest, e.origin_z);
1381 WriteByte(dest, SVC_STOPSOUND);
1382 WriteShort(dest, entno * 8 + chan);
1385 void stopsound(entity e, float chan)
1387 if (!sound_allowed(MSG_BROADCAST, e))
1390 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1391 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1394 void play2(entity e, string filename)
1396 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1398 soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTN_NONE);
1401 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1403 float spamsound(entity e, float chan, string samp, float vol, float atten)
1405 if (!sound_allowed(MSG_BROADCAST, e))
1408 if (time > e.spamtime)
1411 sound(e, chan, samp, vol, atten);
1417 void play2team(float t, string filename)
1421 if (autocvar_bot_sound_monopoly)
1424 FOR_EACH_REALPLAYER(head)
1427 play2(head, filename);
1431 void play2all(string samp)
1433 if (autocvar_bot_sound_monopoly)
1436 sound(world, CH_INFO, samp, VOL_BASE, ATTN_NONE);
1439 void PrecachePlayerSounds(string f);
1440 void precache_playermodel(string m)
1442 float globhandle, i, n;
1445 if(substring(m, -9,5) == "_lod1")
1447 if(substring(m, -9,5) == "_lod2")
1452 f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
1455 f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
1460 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1463 n = search_getsize(globhandle);
1464 for (i = 0; i < n; ++i)
1466 //print(search_getfilename(globhandle, i), "\n");
1467 f = search_getfilename(globhandle, i);
1468 PrecachePlayerSounds(f);
1470 search_end(globhandle);
1472 void precache_all_playermodels(string pattern)
1474 float globhandle, i, n;
1477 globhandle = search_begin(pattern, TRUE, FALSE);
1480 n = search_getsize(globhandle);
1481 for (i = 0; i < n; ++i)
1483 //print(search_getfilename(globhandle, i), "\n");
1484 f = search_getfilename(globhandle, i);
1485 precache_playermodel(f);
1487 search_end(globhandle);
1492 // gamemode related things
1493 precache_model ("models/misc/chatbubble.spr");
1496 precache_model ("models/runematch/curse.mdl");
1497 precache_model ("models/runematch/rune.mdl");
1500 #ifdef TTURRETS_ENABLED
1501 if (autocvar_g_turrets)
1505 // Precache all player models if desired
1506 if (autocvar_sv_precacheplayermodels)
1508 PrecachePlayerSounds("sound/player/default.sounds");
1509 precache_all_playermodels("models/player/*.zym");
1510 precache_all_playermodels("models/player/*.dpm");
1511 precache_all_playermodels("models/player/*.md3");
1512 precache_all_playermodels("models/player/*.psk");
1513 precache_all_playermodels("models/player/*.iqm");
1516 if (autocvar_sv_defaultcharacter)
1519 s = autocvar_sv_defaultplayermodel_red;
1521 precache_playermodel(s);
1522 s = autocvar_sv_defaultplayermodel_blue;
1524 precache_playermodel(s);
1525 s = autocvar_sv_defaultplayermodel_yellow;
1527 precache_playermodel(s);
1528 s = autocvar_sv_defaultplayermodel_pink;
1530 precache_playermodel(s);
1531 s = autocvar_sv_defaultplayermodel;
1533 precache_playermodel(s);
1538 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1539 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1542 // gore and miscellaneous sounds
1543 //precache_sound ("misc/h2ohit.wav");
1544 precache_model ("models/hook.md3");
1545 precache_sound ("misc/armorimpact.wav");
1546 precache_sound ("misc/bodyimpact1.wav");
1547 precache_sound ("misc/bodyimpact2.wav");
1548 precache_sound ("misc/gib.wav");
1549 precache_sound ("misc/gib_splat01.wav");
1550 precache_sound ("misc/gib_splat02.wav");
1551 precache_sound ("misc/gib_splat03.wav");
1552 precache_sound ("misc/gib_splat04.wav");
1553 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1554 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1555 precache_sound ("misc/null.wav");
1556 precache_sound ("misc/spawn.wav");
1557 precache_sound ("misc/talk.wav");
1558 precache_sound ("misc/teleport.wav");
1559 precache_sound ("misc/poweroff.wav");
1560 precache_sound ("player/lava.wav");
1561 precache_sound ("player/slime.wav");
1564 precache_sound ("misc/jetpack_fly.wav");
1566 precache_model ("models/sprites/0.spr32");
1567 precache_model ("models/sprites/1.spr32");
1568 precache_model ("models/sprites/2.spr32");
1569 precache_model ("models/sprites/3.spr32");
1570 precache_model ("models/sprites/4.spr32");
1571 precache_model ("models/sprites/5.spr32");
1572 precache_model ("models/sprites/6.spr32");
1573 precache_model ("models/sprites/7.spr32");
1574 precache_model ("models/sprites/8.spr32");
1575 precache_model ("models/sprites/9.spr32");
1576 precache_model ("models/sprites/10.spr32");
1578 // common weapon precaches
1579 precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound here
1580 precache_sound ("weapons/weapon_switch.wav");
1581 precache_sound ("weapons/weaponpickup.wav");
1582 precache_sound ("weapons/unavailable.wav");
1583 precache_sound ("weapons/dryfire.wav");
1584 if (g_grappling_hook)
1586 precache_sound ("weapons/hook_fire.wav"); // hook
1587 precache_sound ("weapons/hook_impact.wav"); // hook
1590 if(autocvar_sv_precacheweapons)
1592 //precache weapon models/sounds
1595 while (wep <= WEP_LAST)
1597 weapon_action(wep, WR_PRECACHE);
1602 precache_model("models/elaser.mdl");
1603 precache_model("models/laser.mdl");
1604 precache_model("models/ebomb.mdl");
1607 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1609 if (!self.noise && self.music) // quake 3 uses the music field
1610 self.noise = self.music;
1612 // plays music for the level if there is any
1615 precache_sound (self.noise);
1616 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1621 // sorry, but using \ in macros breaks line numbers
1622 #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
1623 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1624 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1627 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
1629 if (clienttype(e) == CLIENTTYPE_REAL)
1632 WRITESPECTATABLE_MSG_ONE({
1633 WriteByte(MSG_ONE, SVC_TEMPENTITY);
1634 WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
1635 WriteByte(MSG_ONE, id);
1636 WriteString(MSG_ONE, s);
1637 if (id != 0 && s != "")
1639 WriteByte(MSG_ONE, duration);
1640 WriteByte(MSG_ONE, countdown_num);
1645 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
1647 Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
1649 // WARNING: this kills the trace globals
1650 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1651 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1653 #define INITPRIO_FIRST 0
1654 #define INITPRIO_GAMETYPE 0
1655 #define INITPRIO_GAMETYPE_FALLBACK 1
1656 #define INITPRIO_FINDTARGET 10
1657 #define INITPRIO_DROPTOFLOOR 20
1658 #define INITPRIO_SETLOCATION 90
1659 #define INITPRIO_LINKDOORS 91
1660 #define INITPRIO_LAST 99
1662 .void(void) initialize_entity;
1663 .float initialize_entity_order;
1664 .entity initialize_entity_next;
1665 entity initialize_entity_first;
1667 void make_safe_for_remove(entity e)
1669 if (e.initialize_entity)
1672 for (ent = initialize_entity_first; ent; )
1674 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1676 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1677 // skip it in linked list
1680 prev.initialize_entity_next = ent.initialize_entity_next;
1681 ent = prev.initialize_entity_next;
1685 initialize_entity_first = ent.initialize_entity_next;
1686 ent = initialize_entity_first;
1692 ent = ent.initialize_entity_next;
1698 void objerror(string s)
1700 make_safe_for_remove(self);
1701 builtin_objerror(s);
1704 .float remove_except_protected_forbidden;
1705 void remove_except_protected(entity e)
1707 if(e.remove_except_protected_forbidden)
1708 error("not allowed to remove this at this point");
1712 void remove_unsafely(entity e)
1714 if(e.classname == "spike")
1715 error("Removing spikes is forbidden (crylink bug), please report");
1719 void remove_safely(entity e)
1721 make_safe_for_remove(e);
1725 void InitializeEntity(entity e, void(void) func, float order)
1729 if (!e || e.initialize_entity)
1731 // make a proxy initializer entity
1735 e.classname = "initialize_entity";
1739 e.initialize_entity = func;
1740 e.initialize_entity_order = order;
1742 cur = initialize_entity_first;
1745 if (!cur || cur.initialize_entity_order > order)
1747 // insert between prev and cur
1749 prev.initialize_entity_next = e;
1751 initialize_entity_first = e;
1752 e.initialize_entity_next = cur;
1756 cur = cur.initialize_entity_next;
1759 void InitializeEntitiesRun()
1762 startoflist = initialize_entity_first;
1763 initialize_entity_first = world;
1764 remove = remove_except_protected;
1765 for (self = startoflist; self; self = self.initialize_entity_next)
1767 self.remove_except_protected_forbidden = 1;
1769 for (self = startoflist; self; )
1772 var void(void) func;
1773 e = self.initialize_entity_next;
1774 func = self.initialize_entity;
1775 self.initialize_entity_order = 0;
1776 self.initialize_entity = func_null;
1777 self.initialize_entity_next = world;
1778 self.remove_except_protected_forbidden = 0;
1779 if (self.classname == "initialize_entity")
1783 builtin_remove(self);
1786 //dprint("Delayed initialization: ", self.classname, "\n");
1787 if(func != func_null)
1792 backtrace(strcat("Null function in: ", self.classname, "\n"));
1796 remove = remove_unsafely;
1799 .float uncustomizeentityforclient_set;
1800 .void(void) uncustomizeentityforclient;
1801 void(void) SUB_Nullpointer = #0;
1802 void UncustomizeEntitiesRun()
1806 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1807 self.uncustomizeentityforclient();
1810 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1812 e.customizeentityforclient = customizer;
1813 e.uncustomizeentityforclient = uncustomizer;
1814 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1818 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1821 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1825 if (e.classname == "")
1826 e.classname = "net_linked";
1828 if (e.model == "" || self.modelindex == 0)
1832 setmodel(e, "null");
1836 e.SendEntity = sendfunc;
1837 e.SendFlags = 0xFFFFFF;
1840 e.effects |= EF_NODEPTHTEST;
1844 e.nextthink = time + dt;
1845 e.think = SUB_Remove;
1849 void adaptor_think2touch()
1858 void adaptor_think2use()
1870 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1872 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
1873 self.projectiledeathtype |= HITTYPE_SPLASH;
1874 adaptor_think2use();
1877 // deferred dropping
1878 void DropToFloor_Handler()
1880 builtin_droptofloor();
1881 self.dropped_origin = self.origin;
1886 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1891 float trace_hits_box_a0, trace_hits_box_a1;
1893 float trace_hits_box_1d(float end, float thmi, float thma)
1897 // just check if x is in range
1905 // do the trace with respect to x
1906 // 0 -> end has to stay in thmi -> thma
1907 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1908 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1909 if (trace_hits_box_a0 > trace_hits_box_a1)
1915 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1920 // now it is a trace from 0 to end
1922 trace_hits_box_a0 = 0;
1923 trace_hits_box_a1 = 1;
1925 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1927 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1929 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1935 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1937 return trace_hits_box(start, end, thmi - ma, thma - mi);
1940 float SUB_NoImpactCheck()
1942 // zero hitcontents = this is not the real impact, but either the
1943 // mirror-impact of something hitting the projectile instead of the
1944 // projectile hitting the something, or a touchareagrid one. Neither of
1945 // these stop the projectile from moving, so...
1946 if(trace_dphitcontents == 0)
1948 //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1949 dprint(sprintf(_("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Profectile will self-destruct. (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.origin)));
1952 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1954 if (other == world && self.size != '0 0 0')
1957 tic = self.velocity * sys_frametime;
1958 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1959 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1960 if (trace_fraction >= 1)
1962 dprint("Odd... did not hit...?\n");
1964 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1966 dprint("Detected and prevented the sky-grapple bug.\n");
1974 #define SUB_OwnerCheck() (other && (other == self.owner))
1976 void RemoveGrapplingHook(entity pl);
1977 void W_Crylink_Dequeue(entity e);
1978 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
1980 if(SUB_OwnerCheck())
1982 if(SUB_NoImpactCheck())
1984 if(self.classname == "grapplinghook")
1985 RemoveGrapplingHook(self.realowner);
1986 else if(self.classname == "spike")
1988 W_Crylink_Dequeue(self);
1995 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
1996 UpdateCSQCProjectile(self);
1999 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
2001 float MAX_IPBAN_URIS = 16;
2003 float URI_GET_DISCARD = 0;
2004 float URI_GET_IPBAN = 1;
2005 float URI_GET_IPBAN_END = 16;
2007 void URI_Get_Callback(float id, float status, string data)
2009 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2011 dprint("\nEnd of data.\n");
2013 if(url_URI_Get_Callback(id, status, data))
2017 else if (id == URI_GET_DISCARD)
2021 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2024 OnlineBanList_URI_Get_Callback(id, status, data);
2028 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2032 void print_to(entity e, string s)
2035 sprint(e, strcat(s, "\n"));
2040 string uid2name(string myuid) {
2042 s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
2044 // FIXME remove this later after 0.6 release
2045 // convert old style broken records to correct style
2048 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
2051 db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
2052 db_put(ServerProgsDB, strcat("uid2name", myuid), "");
2057 s = "^1Unregistered Player";
2061 float race_readTime(string map, float pos)
2069 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
2072 string race_readUID(string map, float pos)
2080 return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
2083 float race_readPos(string map, float t) {
2085 for (i = 1; i <= RANKINGS_CNT; ++i)
2086 if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
2089 return 0; // pos is zero if unranked
2092 void race_writeTime(string map, float t, string myuid)
2101 newpos = race_readPos(map, t);
2104 for(i = 1; i <= RANKINGS_CNT; ++i)
2106 if(race_readUID(map, i) == myuid)
2109 if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
2110 for (i = prevpos; i > newpos; --i) {
2111 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
2112 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
2114 } else { // player has no ranked record yet
2115 for (i = RANKINGS_CNT; i > newpos; --i) {
2116 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
2117 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
2121 // store new time itself
2122 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
2123 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
2126 string race_readName(string map, float pos)
2134 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
2137 string race_placeName(float pos) {
2138 if(floor((mod(pos, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
2140 if(mod(pos, 10) == 1)
2141 return strcat(ftos(pos), "st");
2142 else if(mod(pos, 10) == 2)
2143 return strcat(ftos(pos), "nd");
2144 else if(mod(pos, 10) == 3)
2145 return strcat(ftos(pos), "rd");
2147 return strcat(ftos(pos), "th");
2150 return strcat(ftos(pos), "th");
2152 string getrecords(float page) // 50 records per page
2166 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
2168 if (MapInfo_Get_ByID(i))
2170 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2174 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2175 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2183 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
2185 if (MapInfo_Get_ByID(i))
2187 r = race_readTime(MapInfo_Map_bspname, 1);
2190 h = race_readName(MapInfo_Map_bspname, 1);
2191 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2199 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
2201 if (MapInfo_Get_ByID(i))
2203 r = race_readTime(MapInfo_Map_bspname, 1);
2206 h = race_readName(MapInfo_Map_bspname, 1);
2207 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2213 MapInfo_ClearTemps();
2215 if (s == "" && page == 0)
2216 return "No records are available on this server.\n";
2221 string getrankings()
2234 for (i = 1; i <= RANKINGS_CNT; ++i)
2236 t = race_readTime(map, i);
2239 n = race_readName(map, i);
2240 p = race_placeName(i);
2241 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
2244 MapInfo_ClearTemps();
2247 return strcat("No records are available for the map: ", map, "\n");
2249 return strcat("Records for ", map, ":\n", s);
2252 #define LADDER_FIRSTPOINT 100
2253 #define LADDER_CNT 10
2254 // position X still gives LADDER_FIRSTPOINT/X points
2255 #define LADDER_SIZE 30
2256 // ladder shows the top X players
2257 string top_uids[LADDER_SIZE];
2258 float top_scores[LADDER_SIZE];
2261 float i, j, k, uidcnt;
2275 for (k = 0; k < MapInfo_count; ++k)
2277 if (MapInfo_Get_ByID(k))
2279 for (i = 0; i <= LADDER_CNT; ++i) { // i = 0 because it is the speed award
2280 if(i == 0) // speed award
2282 if(stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0)
2285 myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp"));
2287 else // normal record, if it exists (else break)
2289 if(race_readTime(MapInfo_Map_bspname, i) == 0)
2292 myuid = race_readUID(MapInfo_Map_bspname, i);
2295 // string s contains:
2296 // arg 0 = # of speed recs
2297 // arg 1 = # of 1st place recs
2298 // arg 2 = # of 2nd place recs
2300 // LADDER_CNT+1 = total points
2302 temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
2305 db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid);
2307 for (j = 0; j <= LADDER_CNT + 1; ++j)
2309 if(j != LADDER_CNT + 1)
2310 temp_s = strcat(temp_s, "0 ");
2312 temp_s = strcat(temp_s, "0");
2316 tokenize_console(temp_s);
2319 if(i == 0) // speed award
2320 for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
2322 if(j == 0) // speed award
2323 s = strcat(s, ftos(stof(argv(j)) +1)); // add 1 to speed rec count and write
2325 s = strcat(s, " ", argv(j)); // just copy over everything else
2328 for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
2331 s = strcat(s, argv(j)); // speed award, dont prefix with " "
2332 else if(j == i) // wanted rec!
2333 s = strcat(s, " ", ftos(stof(argv(j)) +1)); // update argv(j)
2335 s = strcat(s, " ", argv(j)); // just copy over everything else
2338 // total points are (by default) calculated like this:
2339 // speedrec = floor(100 / 10) = 10 points
2340 // 1st place = floor(100 / 1) = 100 points
2341 // 2nd place = floor(100 / 2) = 50 points
2342 // 3rd place = floor(100 / 3) = 33 points
2343 // 4th place = floor(100 / 4) = 25 points
2344 // 5th place = floor(100 / 5) = 20 points
2348 s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
2350 s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
2352 db_put(TemporaryDB, strcat("ladder", myuid), s);
2359 for (i = 0; i <= uidcnt; ++i) // for each known uid
2361 thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
2362 temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
2363 tokenize_console(temp_s);
2364 thiscnt = stof(argv(LADDER_CNT+1));
2366 if(thiscnt > top_scores[LADDER_SIZE-1])
2367 for (j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
2369 if(thiscnt > top_scores[j])
2371 for (k = LADDER_SIZE-1; k >= j; --k)
2373 top_uids[k] = top_uids[k-1];
2374 top_scores[k] = top_scores[k-1];
2376 top_uids[j] = thisuid;
2377 top_scores[j] = thiscnt;
2383 s = "^3-----------------------\n\n";
2385 s = strcat(s, "Pos ^3|");
2386 s = strcat(s, " ^7Total ^3|");
2387 for (i = 1; i <= LADDER_CNT; ++i)
2389 s = strcat(s, " ^7", race_placeName(i), " ^3|");
2391 s = strcat(s, " ^7Speed awards ^3| ^7Name");
2393 s = strcat(s, "\n^3----+--------");
2394 for (i = 1; i <= min(9, LADDER_CNT); ++i)
2396 s = strcat(s, "+-----");
2399 for (i = 1; i <= LADDER_CNT - 9; ++i)
2401 s = strcat(s, "+------");
2405 s = strcat(s, "+--------------+--------------------\n");
2407 for (i = 0; i < LADDER_SIZE; ++i)
2409 temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
2410 tokenize_console(temp_s);
2411 if (argv(LADDER_CNT+1) == "") // total is 0, skip
2413 s = strcat(s, strpad(4, race_placeName(i+1)), "^3| ^7"); // pos
2414 s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total
2415 for (j = 1; j <= min(9, LADDER_CNT); ++j)
2417 s = strcat(s, strpad(4, argv(j)), "^3| ^7"); // 1st, 2nd, 3rd etc cnt
2420 for (j = 10; j <= LADDER_CNT; ++j)
2422 s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt
2426 s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt
2427 s = strcat(s, uid2name(top_uids[i]), "\n"); // name
2430 MapInfo_ClearTemps();
2433 return "No ladder on this server!\n";
2435 return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
2439 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2442 vector start, org, delta, end, enddown, mstart;
2445 m = e.dphitcontentsmask;
2446 e.dphitcontentsmask = goodcontents | badcontents;
2449 delta = world.maxs - world.mins;
2451 for (i = 0; i < attempts; ++i)
2453 start_x = org_x + random() * delta_x;
2454 start_y = org_y + random() * delta_y;
2455 start_z = org_z + random() * delta_z;
2457 // rule 1: start inside world bounds, and outside
2458 // solid, and don't start from somewhere where you can
2459 // fall down to evil
2460 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2461 if (trace_fraction >= 1)
2463 if (trace_startsolid)
2465 if (trace_dphitcontents & badcontents)
2467 if (trace_dphitq3surfaceflags & badsurfaceflags)
2470 // rule 2: if we are too high, lower the point
2471 if (trace_fraction * delta_z > maxaboveground)
2472 start = trace_endpos + '0 0 1' * maxaboveground;
2473 enddown = trace_endpos;
2475 // rule 3: make sure we aren't outside the map. This only works
2476 // for somewhat well formed maps. A good rule of thumb is that
2477 // the map should have a convex outside hull.
2478 // these can be traceLINES as we already verified the starting box
2479 mstart = start + 0.5 * (e.mins + e.maxs);
2480 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2481 if (trace_fraction >= 1)
2483 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2484 if (trace_fraction >= 1)
2486 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2487 if (trace_fraction >= 1)
2489 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2490 if (trace_fraction >= 1)
2492 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2493 if (trace_fraction >= 1)
2496 // rule 4: we must "see" some spawnpoint
2497 for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
2498 if(checkpvs(mstart, sp))
2502 for(sp = world; (sp = findflags(sp, flags, FL_ITEM)); )
2503 if(checkpvs(mstart, sp))
2509 // find a random vector to "look at"
2510 end_x = org_x + random() * delta_x;
2511 end_y = org_y + random() * delta_y;
2512 end_z = org_z + random() * delta_z;
2513 end = start + normalize(end - start) * vlen(delta);
2515 // rule 4: start TO end must not be too short
2516 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2517 if (trace_startsolid)
2519 if (trace_fraction < minviewdistance / vlen(delta))
2522 // rule 5: don't want to look at sky
2523 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2526 // rule 6: we must not end up in trigger_hurt
2527 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2533 e.dphitcontentsmask = m;
2537 setorigin(e, start);
2538 e.angles = vectoangles(end - start);
2539 dprint("Needed ", ftos(i + 1), " attempts\n");
2546 float zcurveparticles_effectno;
2547 vector zcurveparticles_start;
2548 float zcurveparticles_spd;
2550 void endzcurveparticles()
2552 if(zcurveparticles_effectno)
2555 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2557 zcurveparticles_effectno = 0;
2560 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2562 spd = bound(0, floor(spd / 16), 32767);
2563 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2565 endzcurveparticles();
2566 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2567 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2568 WriteShort(MSG_BROADCAST, effectno);
2569 WriteCoord(MSG_BROADCAST, start_x);
2570 WriteCoord(MSG_BROADCAST, start_y);
2571 WriteCoord(MSG_BROADCAST, start_z);
2572 zcurveparticles_effectno = effectno;
2573 zcurveparticles_start = start;
2576 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2577 WriteCoord(MSG_BROADCAST, end_x);
2578 WriteCoord(MSG_BROADCAST, end_y);
2579 WriteCoord(MSG_BROADCAST, end_z);
2580 WriteCoord(MSG_BROADCAST, end_dz);
2581 zcurveparticles_spd = spd;
2584 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2587 vector vecxy, velxy;
2589 vecxy = end - start;
2594 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2596 endzcurveparticles();
2597 trailparticles(world, effectno, start, end);
2601 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2602 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2605 void write_recordmarker(entity pl, float tstart, float dt)
2607 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2609 // also write a marker into demo files for demotc-race-record-extractor to find
2612 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2613 " ", ftos(tstart), " ", ftos(dt), "\n"));
2616 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2629 if(allowcenter) // 2: allow center handedness
2642 if(allowcenter) // 2: allow center handedness
2658 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2663 if (autocvar_g_shootfromeye)
2676 else if (autocvar_g_shootfromcenter)
2681 else if ((s = autocvar_g_shootfromfixedorigin) != "")
2691 else if (autocvar_g_shootfromclient)
2693 vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn);
2698 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2700 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2704 void attach_sameorigin(entity e, entity to, string tag)
2706 vector org, t_forward, t_left, t_up, e_forward, e_up;
2713 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2714 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2715 t_forward = v_forward * tagscale;
2716 t_left = v_right * -tagscale;
2717 t_up = v_up * tagscale;
2719 e.origin_x = org * t_forward;
2720 e.origin_y = org * t_left;
2721 e.origin_z = org * t_up;
2723 // current forward and up directions
2724 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2725 e.angles = AnglesTransform_FromVAngles(e.angles);
2727 e.angles = AnglesTransform_FromAngles(e.angles);
2728 fixedmakevectors(e.angles);
2730 // untransform forward, up!
2731 e_forward_x = v_forward * t_forward;
2732 e_forward_y = v_forward * t_left;
2733 e_forward_z = v_forward * t_up;
2734 e_up_x = v_up * t_forward;
2735 e_up_y = v_up * t_left;
2736 e_up_z = v_up * t_up;
2738 e.angles = fixedvectoangles2(e_forward, e_up);
2739 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2740 e.angles = AnglesTransform_ToVAngles(e.angles);
2742 e.angles = AnglesTransform_ToAngles(e.angles);
2744 setattachment(e, to, tag);
2745 setorigin(e, e.origin);
2748 void detach_sameorigin(entity e)
2751 org = gettaginfo(e, 0);
2752 e.angles = fixedvectoangles2(v_forward, v_up);
2753 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2754 e.angles = AnglesTransform_ToVAngles(e.angles);
2756 e.angles = AnglesTransform_ToAngles(e.angles);
2758 setattachment(e, world, "");
2759 setorigin(e, e.origin);
2762 void follow_sameorigin(entity e, entity to)
2764 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2765 e.aiment = to; // make the hole follow bmodel
2766 e.punchangle = to.angles; // the original angles of bmodel
2767 e.view_ofs = e.origin - to.origin; // relative origin
2768 e.v_angle = e.angles - to.angles; // relative angles
2771 void unfollow_sameorigin(entity e)
2773 e.movetype = MOVETYPE_NONE;
2776 entity gettaginfo_relative_ent;
2777 vector gettaginfo_relative(entity e, float tag)
2779 if (!gettaginfo_relative_ent)
2781 gettaginfo_relative_ent = spawn();
2782 gettaginfo_relative_ent.effects = EF_NODRAW;
2784 gettaginfo_relative_ent.model = e.model;
2785 gettaginfo_relative_ent.modelindex = e.modelindex;
2786 gettaginfo_relative_ent.frame = e.frame;
2787 return gettaginfo(gettaginfo_relative_ent, tag);
2790 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2794 if (pl.soundentity.cnt & p)
2796 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2797 pl.soundentity.cnt |= p;
2800 void SoundEntity_StopSound(entity pl, float chan)
2804 if (pl.soundentity.cnt & p)
2806 stopsoundto(MSG_ALL, pl.soundentity, chan);
2807 pl.soundentity.cnt &~= p;
2811 void SoundEntity_Attach(entity pl)
2813 pl.soundentity = spawn();
2814 pl.soundentity.classname = "soundentity";
2815 pl.soundentity.owner = pl;
2816 setattachment(pl.soundentity, pl, "");
2817 setmodel(pl.soundentity, "null");
2820 void SoundEntity_Detach(entity pl)
2823 for (i = 0; i <= 7; ++i)
2824 SoundEntity_StopSound(pl, i);
2828 float ParseCommandPlayerSlotTarget_firsttoken;
2829 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2837 ParseCommandPlayerSlotTarget_firsttoken = -1;
2841 if (substring(argv(idx), 0, 1) == "#")
2843 s = substring(argv(idx), 1, -1);
2845 if (s == "") if (tokens > idx)
2850 ParseCommandPlayerSlotTarget_firsttoken = idx;
2852 if (s == ftos(n) && n > 0 && n <= maxclients)
2855 if (e.flags & FL_CLIENT)
2861 // it must be a nick name
2864 ParseCommandPlayerSlotTarget_firsttoken = idx;
2867 FOR_EACH_CLIENT(head)
2868 if (head.netname == s)
2876 s = strdecolorize(s);
2878 FOR_EACH_CLIENT(head)
2879 if (strdecolorize(head.netname) == s)
2894 float modeleffect_SendEntity(entity to, float sf)
2897 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2900 if(self.velocity != '0 0 0')
2902 if(self.angles != '0 0 0')
2904 if(self.avelocity != '0 0 0')
2907 WriteByte(MSG_ENTITY, f);
2908 WriteShort(MSG_ENTITY, self.modelindex);
2909 WriteByte(MSG_ENTITY, self.skin);
2910 WriteByte(MSG_ENTITY, self.frame);
2911 WriteCoord(MSG_ENTITY, self.origin_x);
2912 WriteCoord(MSG_ENTITY, self.origin_y);
2913 WriteCoord(MSG_ENTITY, self.origin_z);
2916 WriteCoord(MSG_ENTITY, self.velocity_x);
2917 WriteCoord(MSG_ENTITY, self.velocity_y);
2918 WriteCoord(MSG_ENTITY, self.velocity_z);
2922 WriteCoord(MSG_ENTITY, self.angles_x);
2923 WriteCoord(MSG_ENTITY, self.angles_y);
2924 WriteCoord(MSG_ENTITY, self.angles_z);
2928 WriteCoord(MSG_ENTITY, self.avelocity_x);
2929 WriteCoord(MSG_ENTITY, self.avelocity_y);
2930 WriteCoord(MSG_ENTITY, self.avelocity_z);
2932 WriteShort(MSG_ENTITY, self.scale * 256.0);
2933 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2934 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2935 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2936 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2941 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)
2946 e.classname = "modeleffect";
2954 e.teleport_time = t1;
2958 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2962 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2965 sz = max(e.scale, e.scale2);
2966 setsize(e, e.mins * sz, e.maxs * sz);
2967 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2970 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2972 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2975 float randombit(float bits)
2977 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2986 for(f = 1; f <= bits; f *= 2)
2995 r = (r - 1) / (n - 1);
3002 float randombits(float bits, float k, float error_return)
3006 while(k > 0 && bits != r)
3008 r += randombit(bits - r);
3017 void randombit_test(float bits, float iter)
3021 print(ftos(randombit(bits)), "\n");
3026 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
3028 if(halflifedist > 0)
3029 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
3030 else if(halflifedist < 0)
3031 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
3040 #define cvar_string_normal builtin_cvar_string
3041 #define cvar_normal builtin_cvar
3043 string cvar_string_normal(string n)
3045 if not(cvar_type(n) & 1)
3046 backtrace(strcat("Attempt to access undefined cvar: ", n));
3047 return builtin_cvar_string(n);
3050 float cvar_normal(string n)
3052 return stof(cvar_string_normal(n));
3055 #define cvar_set_normal builtin_cvar_set
3063 oself.think = SUB_Remove;
3064 oself.nextthink = time;
3070 Execute func() after time + fdelay.
3071 self when func is executed = self when defer is called
3073 void defer(float fdelay, void() func)
3080 e.think = defer_think;
3081 e.nextthink = time + fdelay;
3084 .string aiment_classname;
3085 .float aiment_deadflag;
3086 void SetMovetypeFollow(entity ent, entity e)
3088 // FIXME this may not be warpzone aware
3089 ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
3090 ent.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid - this means this cannot be teleported by warpzones any more! Instead, we must notice when our owner gets teleported.
3091 ent.aiment = e; // make the hole follow bmodel
3092 ent.punchangle = e.angles; // the original angles of bmodel
3093 ent.view_ofs = ent.origin - e.origin; // relative origin
3094 ent.v_angle = ent.angles - e.angles; // relative angles
3095 ent.aiment_classname = strzone(e.classname);
3096 ent.aiment_deadflag = e.deadflag;
3098 void UnsetMovetypeFollow(entity ent)
3100 ent.movetype = MOVETYPE_FLY;
3101 PROJECTILE_MAKETRIGGER(ent);
3104 float LostMovetypeFollow(entity ent)
3107 if(ent.movetype != MOVETYPE_FOLLOW)
3113 if(ent.aiment.classname != ent.aiment_classname)
3115 if(ent.aiment.deadflag != ent.aiment_deadflag)
3121 float isPushable(entity e)
3128 case "droppedweapon":
3129 case "keepawayball":
3130 case "nexball_basketball":
3131 case "nexball_football":
3133 case "bullet": // antilagged bullets can't hit this either
3136 if (e.projectiledeathtype)