1 var void remove(entity e);
2 void objerror(string s);
4 .vector dropped_origin;
6 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
8 string ColoredTeamName(float t);
10 string admin_name(void)
12 if(cvar_string("sv_adminnick") != "")
13 return cvar_string("sv_adminnick");
15 return "SERVER ADMIN";
18 float DistributeEvenly_amount;
19 float DistributeEvenly_totalweight;
20 void DistributeEvenly_Init(float amount, float totalweight)
22 if (DistributeEvenly_amount)
24 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
25 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
28 DistributeEvenly_amount = 0;
30 DistributeEvenly_amount = amount;
31 DistributeEvenly_totalweight = totalweight;
33 float DistributeEvenly_Get(float weight)
38 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
39 DistributeEvenly_totalweight -= weight;
40 DistributeEvenly_amount -= f;
44 void move_out_of_solid_expand(entity e, vector by)
47 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
50 if (trace_fraction < 1)
53 // adjust origin in the other direction...
54 setorigin(e,e.origin - by * (1 - trace_fraction));
58 float move_out_of_solid(entity e)
63 traceline(o, o, MOVE_WORLDONLY, e);
67 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
68 if (!trace_startsolid)
75 move_out_of_solid_expand(e, '1 0 0' * m0_x);
77 move_out_of_solid_expand(e, '1 0 0' * m1_x);
79 move_out_of_solid_expand(e, '0 1 0' * m0_y);
81 move_out_of_solid_expand(e, '0 1 0' * m1_y);
83 move_out_of_solid_expand(e, '0 0 1' * m0_z);
85 move_out_of_solid_expand(e, '0 0 1' * m1_z);
87 setorigin(e, e.origin);
89 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
99 string STR_PLAYER = "player";
100 string STR_SPECTATOR = "spectator";
101 string STR_OBSERVER = "observer";
104 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
105 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
106 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
107 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
109 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
110 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
111 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
112 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
113 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
116 // copies a string to a tempstring (so one can strunzone it)
117 string strcat1(string s) = #115; // FRIK_FILE
122 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
124 local float nPlayerHealth = rint(enPlayer.health);
125 local float nPlayerArmor = rint(enPlayer.armorvalue);
126 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
127 local float nPlayerPing = rint(enPlayer.ping);
128 local string strPlayerPingColor;
129 local string strMessage;
130 if(nPlayerPing >= 150)
131 strPlayerPingColor = "^1";
133 strPlayerPingColor = "^2";
135 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
136 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
138 if(cvar("sv_fragmessage_information_ping")) {
139 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
140 strMessage = strcat(strMessage, "\n^7(^2Bot");
142 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
143 if(cvar("sv_fragmessage_information_handicap"))
144 if(cvar("sv_fragmessage_information_handicap") == 2)
145 if(nPlayerHandicap <= 1)
146 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
148 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
149 else if not(nPlayerHandicap <= 1)
150 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
152 strMessage = strcat(strMessage, "^7)");
153 } else if(cvar("sv_fragmessage_information_handicap")) {
154 if(cvar("sv_fragmessage_information_handicap") == 2)
155 if(nPlayerHandicap <= 1)
156 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
158 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
159 else if(nPlayerHandicap > 1)
160 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
164 void bcenterprint(string s)
166 // TODO replace by MSG_ALL (would show it to spectators too, though)?
168 FOR_EACH_PLAYER(head)
169 if (clienttype(head) == CLIENTTYPE_REAL)
170 centerprint(head, s);
173 void GameLogEcho(string s)
178 if (cvar("sv_eventlog_files"))
183 matches = cvar("sv_eventlog_files_counter") + 1;
184 cvar_set("sv_eventlog_files_counter", ftos(matches));
187 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
188 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
189 logfile = fopen(fn, FILE_APPEND);
190 fputs(logfile, ":logversion:3\n");
194 if (cvar("sv_eventlog_files_timestamps"))
195 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
197 fputs(logfile, strcat(s, "\n"));
200 if (cvar("sv_eventlog_console"))
209 // will be opened later
214 if (logfile_open && logfile >= 0)
224 vector PL_CROUCH_VIEW_OFS;
225 vector PL_CROUCH_MIN;
226 vector PL_CROUCH_MAX;
228 float spawnpoint_nag;
229 void relocate_spawnpoint()
231 PL_VIEW_OFS = stov(cvar_string("sv_player_viewoffset"));
232 PL_MIN = stov(cvar_string("sv_player_mins"));
233 PL_MAX = stov(cvar_string("sv_player_maxs"));
234 PL_CROUCH_VIEW_OFS = stov(cvar_string("sv_player_crouch_viewoffset"));
235 PL_CROUCH_MIN = stov(cvar_string("sv_player_crouch_mins"));
236 PL_CROUCH_MAX = stov(cvar_string("sv_player_crouch_maxs"));
238 // nudge off the floor
239 setorigin(self, self.origin + '0 0 1');
241 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
242 if (trace_startsolid)
248 if (!move_out_of_solid(self))
249 objerror("could not get out of solid at all!");
250 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
251 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
252 print(" ", ftos(self.origin_y - o_y));
253 print(" ", ftos(self.origin_z - o_z), "'\n");
254 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
257 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
263 self.mins = self.maxs = '0 0 0';
264 objerror("player spawn point in solid, mapper sucks!\n");
269 if (cvar("g_spawnpoints_autodrop"))
271 setsize(self, PL_MIN, PL_MAX);
275 self.use = spawnpoint_use;
276 self.team_saved = self.team;
280 if (have_team_spawns != 0)
282 have_team_spawns = 1;
284 if (cvar("r_showbboxes"))
286 // show where spawnpoints point at too
287 makevectors(self.angles);
290 e.classname = "info_player_foo";
291 setorigin(e, self.origin + v_forward * 24);
292 setsize(e, '-8 -8 -8', '8 8 8');
293 e.solid = SOLID_TRIGGER;
297 #define strstr strstrofs
299 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
300 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
301 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
302 // BE CONSTANT OR strzoneD!
303 float strstr(string haystack, string needle, float offset)
307 len = strlen(needle);
308 endpos = strlen(haystack) - len;
309 while(offset <= endpos)
311 found = substring(haystack, offset, len);
320 float NUM_NEAREST_ENTITIES = 4;
321 entity nearest_entity[NUM_NEAREST_ENTITIES];
322 float nearest_length[NUM_NEAREST_ENTITIES];
323 entity findnearest(vector point, .string field, string value, vector axismod)
334 localhead = find(world, field, value);
337 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
338 dist = localhead.oldorigin;
340 dist = localhead.origin;
342 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
345 for (i = 0; i < num_nearest; ++i)
347 if (len < nearest_length[i])
351 // now i tells us where to insert at
352 // INSERTION SORT! YOU'VE SEEN IT! RUN!
353 if (i < NUM_NEAREST_ENTITIES)
355 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
357 nearest_length[j + 1] = nearest_length[j];
358 nearest_entity[j + 1] = nearest_entity[j];
360 nearest_length[i] = len;
361 nearest_entity[i] = localhead;
362 if (num_nearest < NUM_NEAREST_ENTITIES)
363 num_nearest = num_nearest + 1;
366 localhead = find(localhead, field, value);
369 // now use the first one from our list that we can see
370 for (i = 0; i < num_nearest; ++i)
372 traceline(point, nearest_entity[i].origin, TRUE, world);
373 if (trace_fraction == 1)
377 dprint("Nearest point (");
378 dprint(nearest_entity[0].netname);
379 dprint(") is not visible, using a visible one.\n");
381 return nearest_entity[i];
385 if (num_nearest == 0)
388 dprint("Not seeing any location point, using nearest as fallback.\n");
390 dprint("Candidates were: ");
391 for(j = 0; j < num_nearest; ++j)
395 dprint(nearest_entity[j].netname);
400 return nearest_entity[0];
403 void spawnfunc_target_location()
405 self.classname = "target_location";
406 // location name in netname
407 // eventually support: count, teamgame selectors, line of sight?
410 void spawnfunc_info_location()
412 self.classname = "target_location";
413 self.message = self.netname;
416 string NearestLocation(vector p)
421 loc = findnearest(p, classname, "target_location", '1 1 1');
428 loc = findnearest(p, target, "###item###", '1 1 4');
435 string formatmessage(string msg)
446 break; // too many replacements
449 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
450 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
463 replacement = substring(msg, p, 2);
464 escape = substring(msg, p + 1, 1);
468 else if (escape == "\\")
470 else if (escape == "n")
472 else if (escape == "a")
473 replacement = ftos(floor(self.armorvalue));
474 else if (escape == "h")
475 replacement = ftos(floor(self.health));
476 else if (escape == "l")
477 replacement = NearestLocation(self.origin);
478 else if (escape == "y")
479 replacement = NearestLocation(self.cursor_trace_endpos);
480 else if (escape == "d")
481 replacement = NearestLocation(self.death_origin);
482 else if (escape == "w") {
486 wep = self.switchweapon;
489 replacement = W_Name(wep);
490 } else if (escape == "W") {
491 if (self.items & IT_SHELLS) replacement = "shells";
492 else if (self.items & IT_NAILS) replacement = "bullets";
493 else if (self.items & IT_ROCKETS) replacement = "rockets";
494 else if (self.items & IT_CELLS) replacement = "cells";
495 else replacement = "batteries"; // ;)
496 } else if (escape == "x") {
497 replacement = self.cursor_trace_ent.netname;
498 if (!replacement || !self.cursor_trace_ent)
499 replacement = "nothing";
500 } else if (escape == "p") {
501 if (self.last_selected_player)
502 replacement = self.last_selected_player.netname;
504 replacement = "(nobody)";
505 } else if (escape == "s")
506 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
507 else if (escape == "S")
508 replacement = ftos(vlen(self.velocity));
509 else if (escape == "v") {
513 if(self.classname == "spectator")
518 weapon_number = stats.weapon;
521 weapon_number = stats.switchweapon;
524 weapon_number = stats.cnt;
526 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
527 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
529 replacement = "~"; // or something to indicate NULL, not available
532 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
533 p = p + strlen(replacement);
538 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
539 return (value == 0) ? FALSE : TRUE;
548 >0: receives a cvar from name=argv(f) value=argv(f+1)
550 void GetCvars_handleString(string thisname, float f, .string field, string name)
555 strunzone(self.field);
556 self.field = string_null;
560 if (thisname == name)
563 strunzone(self.field);
564 self.field = strzone(argv(f + 1));
568 stuffcmd(self, strcat("sendcvar ", name, "\n"));
570 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
572 GetCvars_handleString(thisname, f, field, name);
573 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
574 if (thisname == name)
577 s = func(strcat1(self.field));
580 strunzone(self.field);
581 self.field = strzone(s);
585 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
592 if (thisname == name)
593 self.field = stof(argv(f + 1));
596 stuffcmd(self, strcat("sendcvar ", name, "\n"));
598 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
605 if (thisname == name)
609 self.field = stof(argv(f + 1));
618 stuffcmd(self, strcat("sendcvar ", name, "\n"));
621 string W_FixWeaponOrder_ForceComplete(string s);
622 string W_FixWeaponOrder_AllowIncomplete(string s);
623 float w_getbestweapon(entity e);
624 void GetCvars(float f)
628 s = strcat1(argv(f));
629 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
630 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
631 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
632 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
633 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
634 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
635 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
636 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
637 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
638 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
639 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
640 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
641 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
642 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
643 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
644 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
645 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
646 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
647 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
648 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
649 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
650 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
651 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
652 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
654 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
655 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
657 #ifdef ALLOW_FORCEMODELS
658 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
659 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
661 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
663 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
666 if (s == "cl_weaponpriority")
667 self.switchweapon = w_getbestweapon(self);
671 float fexists(string f)
674 fh = fopen(f, FILE_READ);
681 void backtrace(string msg)
684 dev = cvar("developer");
685 war = cvar("prvm_backtraceforwarnings");
686 cvar_set("developer", "1");
687 cvar_set("prvm_backtraceforwarnings", "1");
689 print("--- CUT HERE ---\nWARNING: ");
692 remove(world); // isn't there any better way to cause a backtrace?
693 print("\n--- CUT UNTIL HERE ---\n");
694 cvar_set("developer", ftos(dev));
695 cvar_set("prvm_backtraceforwarnings", ftos(war));
698 string Team_ColorCode(float teamid)
700 if (teamid == COLOR_TEAM1)
702 else if (teamid == COLOR_TEAM2)
704 else if (teamid == COLOR_TEAM3)
706 else if (teamid == COLOR_TEAM4)
712 string Team_ColorName(float t)
714 // fixme: Search for team entities and get their .netname's!
715 if (t == COLOR_TEAM1)
717 if (t == COLOR_TEAM2)
719 if (t == COLOR_TEAM3)
721 if (t == COLOR_TEAM4)
726 string Team_ColorNameLowerCase(float t)
728 // fixme: Search for team entities and get their .netname's!
729 if (t == COLOR_TEAM1)
731 if (t == COLOR_TEAM2)
733 if (t == COLOR_TEAM3)
735 if (t == COLOR_TEAM4)
740 float ColourToNumber(string team_colour)
742 if (team_colour == "red")
745 if (team_colour == "blue")
748 if (team_colour == "yellow")
751 if (team_colour == "pink")
754 if (team_colour == "auto")
760 float NumberToTeamNumber(float number)
777 #define CENTERPRIO_POINT 1
778 #define CENTERPRIO_SPAM 2
779 #define CENTERPRIO_VOTE 4
780 #define CENTERPRIO_NORMAL 5
781 #define CENTERPRIO_SHIELDING 7
782 #define CENTERPRIO_MAPVOTE 9
783 #define CENTERPRIO_IDLEKICK 50
784 #define CENTERPRIO_ADMIN 99
785 .float centerprint_priority;
786 .float centerprint_expires;
787 void centerprint_atprio(entity e, float prio, string s)
789 if (intermission_running)
790 if (prio < CENTERPRIO_MAPVOTE)
792 if (time > e.centerprint_expires)
793 e.centerprint_priority = 0;
794 if (prio >= e.centerprint_priority)
796 e.centerprint_priority = prio;
797 if (timeoutStatus == 2)
798 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
800 e.centerprint_expires = time + e.cvar_scr_centertime;
801 centerprint_builtin(e, s);
804 void centerprint_expire(entity e, float prio)
806 if (prio == e.centerprint_priority)
808 e.centerprint_priority = 0;
809 centerprint_builtin(e, "");
812 void centerprint(entity e, string s)
814 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
817 // decolorizes and team colors the player name when needed
818 string playername(entity p)
821 if (teams_matter && !intermission_running && p.classname == "player")
823 t = Team_ColorCode(p.team);
824 return strcat(t, strdecolorize(p.netname));
830 vector randompos(vector m1, vector m2)
834 v_x = m2_x * random() + m1_x;
835 v_y = m2_y * random() + m1_y;
836 v_z = m2_z * random() + m1_z;
840 float g_pickup_shells;
841 float g_pickup_shells_max;
842 float g_pickup_nails;
843 float g_pickup_nails_max;
844 float g_pickup_rockets;
845 float g_pickup_rockets_max;
846 float g_pickup_cells;
847 float g_pickup_cells_max;
849 float g_pickup_fuel_jetpack;
850 float g_pickup_fuel_max;
851 float g_pickup_armorsmall;
852 float g_pickup_armorsmall_max;
853 float g_pickup_armormedium;
854 float g_pickup_armormedium_max;
855 float g_pickup_armorbig;
856 float g_pickup_armorbig_max;
857 float g_pickup_armorlarge;
858 float g_pickup_armorlarge_max;
859 float g_pickup_healthsmall;
860 float g_pickup_healthsmall_max;
861 float g_pickup_healthmedium;
862 float g_pickup_healthmedium_max;
863 float g_pickup_healthlarge;
864 float g_pickup_healthlarge_max;
865 float g_pickup_healthmega;
866 float g_pickup_healthmega_max;
868 float g_weaponarena_random;
869 string g_weaponarena_list;
870 float g_weaponspeedfactor;
871 float g_weaponratefactor;
872 float g_weapondamagefactor;
873 float g_weaponforcefactor;
874 float g_weaponspreadfactor;
878 float start_ammo_shells;
879 float start_ammo_nails;
880 float start_ammo_rockets;
881 float start_ammo_cells;
882 float start_ammo_fuel;
884 float start_armorvalue;
885 float warmup_start_weapons;
886 float warmup_start_ammo_shells;
887 float warmup_start_ammo_nails;
888 float warmup_start_ammo_rockets;
889 float warmup_start_ammo_cells;
890 float warmup_start_ammo_fuel;
891 float warmup_start_health;
892 float warmup_start_armorvalue;
896 entity get_weaponinfo(float w);
898 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
900 var float i = weaponinfo.weapon;
905 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
907 if (t < 0) // "default" weapon selection
909 if (g_lms || g_ca || allguns)
910 t = (weaponinfo.spawnflags & WEPSPAWNFLAG_NORMAL);
913 else if (g_race || g_cts)
914 t = (i == WEP_LASER);
916 t = 0; // weapon is set a few lines later
918 t = (i == WEP_LASER || i == WEP_SHOTGUN);
919 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
920 t |= (i == WEP_HOOK);
923 // we cannot disable porto in Nexball, we must force it
924 if(g_nexball && i == WEP_PORTO)
930 float NixNex_CanChooseWeapon(float wpn);
931 void readplayerstartcvars()
937 // initialize starting values for players
940 start_ammo_shells = 0;
941 start_ammo_nails = 0;
942 start_ammo_rockets = 0;
943 start_ammo_cells = 0;
944 start_health = cvar("g_balance_health_start");
945 start_armorvalue = cvar("g_balance_armor_start");
948 s = cvar_string("g_weaponarena");
954 g_weaponarena_list = "All Weapons";
955 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
957 e = get_weaponinfo(j);
958 g_weaponarena |= e.weapons;
959 weapon_action(e.weapon, WR_PRECACHE);
962 else if (s == "most")
964 g_weaponarena_list = "Most Weapons";
965 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
967 e = get_weaponinfo(j);
968 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
970 g_weaponarena |= e.weapons;
971 weapon_action(e.weapon, WR_PRECACHE);
975 else if (s == "none")
977 g_weaponarena_list = "No Weapons";
978 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
982 t = tokenize_console(s);
983 g_weaponarena_list = "";
984 for (i = 0; i < t; ++i)
987 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
989 e = get_weaponinfo(j);
992 g_weaponarena |= e.weapons;
993 weapon_action(e.weapon, WR_PRECACHE);
994 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
1000 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
1003 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
1007 g_weaponarena_random = cvar("g_weaponarena_random");
1009 g_weaponarena_random = 0;
1014 // will be done later
1015 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1016 if (NixNex_CanChooseWeapon(i))
1017 weapon_action(i, WR_PRECACHE);
1018 if(!cvar("g_use_ammunition"))
1019 start_items |= IT_UNLIMITED_AMMO;
1021 else if (g_weaponarena)
1023 start_weapons = g_weaponarena;
1024 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
1025 start_ammo_rockets = 999;
1026 if (g_weaponarena & WEPBIT_SHOTGUN)
1027 start_ammo_shells = 999;
1028 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
1029 start_ammo_cells = 999;
1030 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
1031 start_ammo_nails = 999;
1032 if (g_weaponarena & WEPBIT_HOOK)
1033 start_ammo_fuel = 999;
1034 start_items |= IT_UNLIMITED_AMMO;
1036 else if (g_minstagib)
1039 start_armorvalue = 0;
1040 start_weapons = WEPBIT_MINSTANEX;
1041 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
1042 start_ammo_cells = cvar("g_minstagib_ammo_start");
1043 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
1044 start_ammo_fuel = cvar("g_start_ammo_fuel");
1046 if (g_minstagib_invis_alpha <= 0)
1047 g_minstagib_invis_alpha = -1;
1053 start_ammo_shells = cvar("g_lms_start_ammo_shells");
1054 start_ammo_nails = cvar("g_lms_start_ammo_nails");
1055 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
1056 start_ammo_cells = cvar("g_lms_start_ammo_cells");
1057 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
1058 start_health = cvar("g_lms_start_health");
1059 start_armorvalue = cvar("g_lms_start_armor");
1061 else if (cvar("g_use_ammunition"))
1063 start_ammo_shells = cvar("g_start_ammo_shells");
1064 start_ammo_nails = cvar("g_start_ammo_nails");
1065 start_ammo_rockets = cvar("g_start_ammo_rockets");
1066 start_ammo_cells = cvar("g_start_ammo_cells");
1067 start_ammo_fuel = cvar("g_start_ammo_fuel");
1071 start_ammo_shells = cvar("g_pickup_shells_max");
1072 start_ammo_nails = cvar("g_pickup_nails_max");
1073 start_ammo_rockets = cvar("g_pickup_rockets_max");
1074 start_ammo_cells = cvar("g_pickup_cells_max");
1075 start_ammo_fuel = cvar("g_pickup_fuel_max");
1076 start_items |= IT_UNLIMITED_AMMO;
1079 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1081 e = get_weaponinfo(i);
1082 if(want_weapon("g_start_weapon_", e, FALSE))
1084 start_weapons |= e.weapons;
1085 weapon_action(e.weapon, WR_PRECACHE);
1092 warmup_start_ammo_shells = start_ammo_shells;
1093 warmup_start_ammo_nails = start_ammo_nails;
1094 warmup_start_ammo_rockets = start_ammo_rockets;
1095 warmup_start_ammo_cells = start_ammo_cells;
1096 warmup_start_ammo_fuel = start_ammo_fuel;
1097 warmup_start_health = start_health;
1098 warmup_start_armorvalue = start_armorvalue;
1099 warmup_start_weapons = start_weapons;
1101 if (!g_weaponarena && !g_nixnex && !g_minstagib && !g_ca)
1103 if (cvar("g_use_ammunition"))
1105 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1106 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1107 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1108 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1109 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1111 warmup_start_health = cvar("g_warmup_start_health");
1112 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1113 warmup_start_weapons = 0;
1114 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1116 e = get_weaponinfo(i);
1117 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
1119 warmup_start_weapons |= e.weapons;
1120 weapon_action(e.weapon, WR_PRECACHE);
1126 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1128 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1129 start_items |= IT_FUEL_REGEN;
1130 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1131 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1135 start_items |= IT_JETPACK;
1137 if (g_weapon_stay == 2)
1139 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1140 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1141 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1142 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1143 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1144 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1145 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1146 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1147 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1148 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1151 start_ammo_shells = max(0, start_ammo_shells);
1152 start_ammo_nails = max(0, start_ammo_nails);
1153 start_ammo_cells = max(0, start_ammo_cells);
1154 start_ammo_rockets = max(0, start_ammo_rockets);
1155 start_ammo_fuel = max(0, start_ammo_fuel);
1157 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1158 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1159 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1160 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1161 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1165 float g_bugrigs_planar_movement;
1166 float g_bugrigs_planar_movement_car_jumping;
1167 float g_bugrigs_reverse_spinning;
1168 float g_bugrigs_reverse_speeding;
1169 float g_bugrigs_reverse_stopping;
1170 float g_bugrigs_air_steering;
1171 float g_bugrigs_angle_smoothing;
1172 float g_bugrigs_friction_floor;
1173 float g_bugrigs_friction_brake;
1174 float g_bugrigs_friction_air;
1175 float g_bugrigs_accel;
1176 float g_bugrigs_speed_ref;
1177 float g_bugrigs_speed_pow;
1178 float g_bugrigs_steer;
1180 float g_touchexplode;
1181 float g_touchexplode_radius;
1182 float g_touchexplode_damage;
1183 float g_touchexplode_edgedamage;
1184 float g_touchexplode_force;
1191 float sv_pitch_fixyaw;
1193 float sv_accuracy_data_share;
1195 void readlevelcvars(void)
1197 g_bugrigs = cvar("g_bugrigs");
1198 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1199 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1200 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1201 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1202 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1203 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1204 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1205 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1206 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1207 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1208 g_bugrigs_accel = cvar("g_bugrigs_accel");
1209 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1210 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1211 g_bugrigs_steer = cvar("g_bugrigs_steer");
1213 g_touchexplode = cvar("g_touchexplode");
1214 g_touchexplode_radius = cvar("g_touchexplode_radius");
1215 g_touchexplode_damage = cvar("g_touchexplode_damage");
1216 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1217 g_touchexplode_force = cvar("g_touchexplode_force");
1219 #ifdef ALLOW_FORCEMODELS
1220 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1222 sv_loddistance1 = cvar("sv_loddistance1");
1223 sv_loddistance2 = cvar("sv_loddistance2");
1225 if(sv_loddistance2 <= sv_loddistance1)
1226 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1228 sv_clones = cvar("sv_clones");
1229 sv_cheats = cvar("sv_cheats");
1230 sv_gentle = cvar("sv_gentle");
1231 sv_foginterval = cvar("sv_foginterval");
1232 g_cloaked = cvar("g_cloaked");
1233 g_jump_grunt = cvar("g_jump_grunt");
1234 g_footsteps = cvar("g_footsteps");
1235 g_grappling_hook = cvar("g_grappling_hook");
1236 g_jetpack = cvar("g_jetpack");
1237 g_laserguided_missile = cvar("g_laserguided_missile");
1238 g_midair = cvar("g_midair");
1239 g_minstagib = cvar("g_minstagib");
1240 g_nixnex = cvar("g_nixnex");
1241 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1242 g_norecoil = cvar("g_norecoil");
1243 g_vampire = cvar("g_vampire");
1244 g_bloodloss = cvar("g_bloodloss");
1245 sv_maxidle = cvar("sv_maxidle");
1246 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1247 sv_pogostick = cvar("sv_pogostick");
1248 sv_doublejump = cvar("sv_doublejump");
1249 g_ctf_reverse = cvar("g_ctf_reverse");
1250 sv_autotaunt = cvar("sv_autotaunt");
1251 sv_taunt = cvar("sv_taunt");
1253 inWarmupStage = cvar("g_warmup");
1254 g_warmup_limit = cvar("g_warmup_limit");
1255 g_warmup_allguns = cvar("g_warmup_allguns");
1256 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1258 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1259 inWarmupStage = 0; // these modes cannot work together, sorry
1261 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1262 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1263 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1264 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1265 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1266 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1267 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1268 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1269 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1270 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1271 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1272 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1274 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1275 if (g_nixnex) g_weaponarena = 0;
1278 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1279 g_weaponratefactor = cvar("g_weaponratefactor");
1280 g_weapondamagefactor = cvar("g_weapondamagefactor");
1281 g_weaponforcefactor = cvar("g_weaponforcefactor");
1282 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1284 g_pickup_shells = cvar("g_pickup_shells");
1285 g_pickup_shells_max = cvar("g_pickup_shells_max");
1286 g_pickup_nails = cvar("g_pickup_nails");
1287 g_pickup_nails_max = cvar("g_pickup_nails_max");
1288 g_pickup_rockets = cvar("g_pickup_rockets");
1289 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1290 g_pickup_cells = cvar("g_pickup_cells");
1291 g_pickup_cells_max = cvar("g_pickup_cells_max");
1292 g_pickup_fuel = cvar("g_pickup_fuel");
1293 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1294 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1295 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1296 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1297 g_pickup_armormedium = cvar("g_pickup_armormedium");
1298 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1299 g_pickup_armorbig = cvar("g_pickup_armorbig");
1300 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1301 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1302 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1303 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1304 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1305 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1306 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1307 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1308 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1309 g_pickup_healthmega = cvar("g_pickup_healthmega");
1310 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1312 g_pinata = cvar("g_pinata");
1314 g_weapon_stay = cvar("g_weapon_stay");
1316 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1319 g_ghost_items = cvar("g_ghost_items");
1321 if(g_ghost_items >= 1)
1322 g_ghost_items = 0.13; // default alpha value
1324 if not(inWarmupStage && !g_ca)
1325 game_starttime = cvar("g_start_delay");
1327 sv_pitch_min = cvar("sv_pitch_min");
1328 sv_pitch_max = cvar("sv_pitch_max");
1329 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1331 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
1333 readplayerstartcvars();
1337 // TODO sound pack system
1340 string precache_sound_builtin (string s) = #19;
1341 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1342 string precache_sound(string s)
1344 return precache_sound_builtin(strcat(soundpack, s));
1346 void play2(entity e, string filename)
1348 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1350 void sound(entity e, float chan, string samp, float vol, float atten)
1352 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1357 string precache_sound (string s) = #19;
1358 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1359 float precache_sound_index (string s) = #19;
1361 #define SND_VOLUME 1
1362 #define SND_ATTENUATION 2
1363 #define SND_LARGEENTITY 8
1364 #define SND_LARGESOUND 16
1366 float sound_allowed(float dest, entity e)
1368 // sounds from world may always pass
1371 if (e.classname == "body")
1373 if (e.owner && e.owner != e)
1378 // sounds to self may always pass
1379 if (dest == MSG_ONE)
1380 if (e == msg_entity)
1382 // sounds by players can be removed
1383 if (cvar("bot_sound_monopoly"))
1384 if (clienttype(e) == CLIENTTYPE_REAL)
1386 // anything else may pass
1390 void sound(entity e, float chan, string samp, float vol, float atten)
1392 if (!sound_allowed(MSG_BROADCAST, e))
1394 sound_builtin(e, chan, samp, vol, atten);
1396 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1400 if (!sound_allowed(dest, e))
1403 entno = num_for_edict(e);
1404 idx = precache_sound_index(samp);
1409 atten = floor(atten * 64);
1410 vol = floor(vol * 255);
1413 sflags |= SND_VOLUME;
1415 sflags |= SND_ATTENUATION;
1417 sflags |= SND_LARGEENTITY;
1419 sflags |= SND_LARGESOUND;
1421 WriteByte(dest, SVC_SOUND);
1422 WriteByte(dest, sflags);
1423 if (sflags & SND_VOLUME)
1424 WriteByte(dest, vol);
1425 if (sflags & SND_ATTENUATION)
1426 WriteByte(dest, atten);
1427 if (sflags & SND_LARGEENTITY)
1429 WriteShort(dest, entno);
1430 WriteByte(dest, chan);
1434 WriteShort(dest, entno * 8 + chan);
1436 if (sflags & SND_LARGESOUND)
1437 WriteShort(dest, idx);
1439 WriteByte(dest, idx);
1441 WriteCoord(dest, o_x);
1442 WriteCoord(dest, o_y);
1443 WriteCoord(dest, o_z);
1445 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1449 if (!sound_allowed(dest, e))
1452 o = e.origin + 0.5 * (e.mins + e.maxs);
1453 soundtoat(dest, e, o, chan, samp, vol, atten);
1455 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1457 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1459 void stopsoundto(float dest, entity e, float chan)
1463 if (!sound_allowed(dest, e))
1466 entno = num_for_edict(e);
1471 idx = precache_sound_index("misc/null.wav");
1472 sflags = SND_LARGEENTITY;
1474 sflags |= SND_LARGESOUND;
1475 WriteByte(dest, SVC_SOUND);
1476 WriteByte(dest, sflags);
1477 WriteShort(dest, entno);
1478 WriteByte(dest, chan);
1479 if (sflags & SND_LARGESOUND)
1480 WriteShort(dest, idx);
1482 WriteByte(dest, idx);
1483 WriteCoord(dest, e.origin_x);
1484 WriteCoord(dest, e.origin_y);
1485 WriteCoord(dest, e.origin_z);
1489 WriteByte(dest, SVC_STOPSOUND);
1490 WriteShort(dest, entno * 8 + chan);
1493 void stopsound(entity e, float chan)
1495 if (!sound_allowed(MSG_BROADCAST, e))
1498 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1499 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1502 void play2(entity e, string filename)
1504 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1506 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1509 .float announcetime;
1510 float announce(entity player, string msg)
1512 if (time > player.announcetime)
1513 if (clienttype(player) == CLIENTTYPE_REAL)
1515 player.announcetime = time + 0.8;
1521 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1522 float spamsound(entity e, float chan, string samp, float vol, float atten)
1524 if (!sound_allowed(MSG_BROADCAST, e))
1527 if (time > e.announcetime)
1529 e.announcetime = time;
1530 sound(e, chan, samp, vol, atten);
1536 void play2team(float t, string filename)
1540 if (cvar("bot_sound_monopoly"))
1543 FOR_EACH_REALPLAYER(head)
1546 play2(head, filename);
1550 void play2all(string samp)
1552 if (cvar("bot_sound_monopoly"))
1555 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1558 void PrecachePlayerSounds(string f);
1559 void precache_all_models(string pattern)
1561 float globhandle, i, n;
1564 globhandle = search_begin(pattern, TRUE, FALSE);
1567 n = search_getsize(globhandle);
1568 for (i = 0; i < n; ++i)
1570 //print(search_getfilename(globhandle, i), "\n");
1571 f = search_getfilename(globhandle, i);
1574 if(substring(f, -9,5) == "_lod1")
1576 if(substring(f, -9,5) == "_lod2")
1578 if(!sv_loddistance1)
1580 PrecachePlayerSounds(strcat(f, ".sounds"));
1582 search_end(globhandle);
1587 // gamemode related things
1588 precache_model ("models/misc/chatbubble.spr");
1589 precache_model ("models/misc/teambubble.spr");
1592 precache_model ("models/runematch/curse.mdl");
1593 precache_model ("models/runematch/rune.mdl");
1596 #ifdef TTURRETS_ENABLED
1597 if (cvar("g_turrets"))
1601 // Precache all player models if desired
1602 if (cvar("sv_precacheplayermodels"))
1604 PrecachePlayerSounds("sound/player/default.sounds");
1605 precache_all_models("models/player/*.zym");
1606 precache_all_models("models/player/*.dpm");
1607 precache_all_models("models/player/*.md3");
1608 precache_all_models("models/player/*.psk");
1609 //precache_model("models/player/carni.zym");
1610 //precache_model("models/player/crash.zym");
1611 //precache_model("models/player/grunt.zym");
1612 //precache_model("models/player/headhunter.zym");
1613 //precache_model("models/player/insurrectionist.zym");
1614 //precache_model("models/player/jeandarc.zym");
1615 //precache_model("models/player/lurk.zym");
1616 //precache_model("models/player/lycanthrope.zym");
1617 //precache_model("models/player/marine.zym");
1618 //precache_model("models/player/nexus.zym");
1619 //precache_model("models/player/pyria.zym");
1620 //precache_model("models/player/shock.zym");
1621 //precache_model("models/player/skadi.zym");
1622 //precache_model("models/player/specop.zym");
1623 //precache_model("models/player/visitant.zym");
1626 if (cvar("sv_defaultcharacter"))
1629 s = cvar_string("sv_defaultplayermodel_red");
1633 PrecachePlayerSounds(strcat(s, ".sounds"));
1635 s = cvar_string("sv_defaultplayermodel_blue");
1639 PrecachePlayerSounds(strcat(s, ".sounds"));
1641 s = cvar_string("sv_defaultplayermodel_yellow");
1645 PrecachePlayerSounds(strcat(s, ".sounds"));
1647 s = cvar_string("sv_defaultplayermodel_pink");
1651 PrecachePlayerSounds(strcat(s, ".sounds"));
1653 s = cvar_string("sv_defaultplayermodel");
1657 PrecachePlayerSounds(strcat(s, ".sounds"));
1663 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1664 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1667 // gore and miscellaneous sounds
1668 //precache_sound ("misc/h2ohit.wav");
1669 precache_model ("models/hook.md3");
1670 precache_sound ("misc/armorimpact.wav");
1671 precache_sound ("misc/bodyimpact1.wav");
1672 precache_sound ("misc/bodyimpact2.wav");
1673 precache_sound ("misc/gib.wav");
1674 precache_sound ("misc/gib_splat01.wav");
1675 precache_sound ("misc/gib_splat02.wav");
1676 precache_sound ("misc/gib_splat03.wav");
1677 precache_sound ("misc/gib_splat04.wav");
1678 precache_sound ("misc/hit.wav");
1679 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1680 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1681 precache_sound ("misc/null.wav");
1682 precache_sound ("misc/spawn.wav");
1683 precache_sound ("misc/talk.wav");
1684 precache_sound ("misc/teleport.wav");
1685 precache_sound ("misc/poweroff.wav");
1686 precache_sound ("player/lava.wav");
1687 precache_sound ("player/slime.wav");
1690 precache_sound ("misc/jetpack_fly.wav");
1692 // announcer sounds - male
1693 precache_sound ("announcer/male/electrobitch.wav");
1694 precache_sound ("announcer/male/airshot.wav");
1695 precache_sound ("announcer/male/03kills.wav");
1696 precache_sound ("announcer/male/05kills.wav");
1697 precache_sound ("announcer/male/10kills.wav");
1698 precache_sound ("announcer/male/15kills.wav");
1699 precache_sound ("announcer/male/20kills.wav");
1700 precache_sound ("announcer/male/25kills.wav");
1701 precache_sound ("announcer/male/30kills.wav");
1702 precache_sound ("announcer/male/botlike.wav");
1703 precache_sound ("announcer/male/yoda.wav");
1704 precache_sound ("announcer/male/amazing.wav");
1705 precache_sound ("announcer/male/awesome.wav");
1706 precache_sound ("announcer/male/headshot.wav");
1707 precache_sound ("announcer/male/impressive.wav");
1709 // announcer sounds - robotic
1710 precache_sound ("announcer/robotic/prepareforbattle.wav");
1711 precache_sound ("announcer/robotic/begin.wav");
1712 precache_sound ("announcer/robotic/timeoutcalled.wav");
1713 precache_sound ("announcer/robotic/1fragleft.wav");
1714 precache_sound ("announcer/robotic/2fragsleft.wav");
1715 precache_sound ("announcer/robotic/3fragsleft.wav");
1716 precache_sound ("announcer/robotic/terminated.wav");
1719 precache_sound ("announcer/robotic/lastsecond.wav");
1720 precache_sound ("announcer/robotic/narrowly.wav");
1723 precache_model ("models/sprites/0.spr32");
1724 precache_model ("models/sprites/1.spr32");
1725 precache_model ("models/sprites/2.spr32");
1726 precache_model ("models/sprites/3.spr32");
1727 precache_model ("models/sprites/4.spr32");
1728 precache_model ("models/sprites/5.spr32");
1729 precache_model ("models/sprites/6.spr32");
1730 precache_model ("models/sprites/7.spr32");
1731 precache_model ("models/sprites/8.spr32");
1732 precache_model ("models/sprites/9.spr32");
1733 precache_model ("models/sprites/10.spr32");
1734 precache_sound ("announcer/robotic/1.wav");
1735 precache_sound ("announcer/robotic/2.wav");
1736 precache_sound ("announcer/robotic/3.wav");
1737 precache_sound ("announcer/robotic/4.wav");
1738 precache_sound ("announcer/robotic/5.wav");
1739 precache_sound ("announcer/robotic/6.wav");
1740 precache_sound ("announcer/robotic/7.wav");
1741 precache_sound ("announcer/robotic/8.wav");
1742 precache_sound ("announcer/robotic/9.wav");
1743 precache_sound ("announcer/robotic/10.wav");
1745 // common weapon precaches
1746 precache_sound ("weapons/weapon_switch.wav");
1747 precache_sound ("weapons/weaponpickup.wav");
1748 precache_sound ("weapons/unavailable.wav");
1749 if (g_grappling_hook)
1751 precache_sound ("weapons/hook_fire.wav"); // hook
1752 precache_sound ("weapons/hook_impact.wav"); // hook
1755 if (cvar("sv_precacheweapons") || g_nixnex)
1757 //precache weapon models/sounds
1760 while (wep <= WEP_LAST)
1762 weapon_action(wep, WR_PRECACHE);
1767 precache_model("models/elaser.mdl");
1768 precache_model("models/laser.mdl");
1769 precache_model("models/ebomb.mdl");
1772 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1774 if (!self.noise && self.music) // quake 3 uses the music field
1775 self.noise = self.music;
1777 // plays music for the level if there is any
1780 precache_sound (self.noise);
1781 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1786 // sorry, but using \ in macros breaks line numbers
1787 #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
1788 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1789 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1791 vector ExactTriggerHit_mins;
1792 vector ExactTriggerHit_maxs;
1793 float ExactTriggerHit_Recurse()
1799 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1802 if (trace_ent == self)
1807 se.solid = SOLID_NOT;
1808 f = ExactTriggerHit_Recurse();
1814 float ExactTriggerHit()
1818 if not(self.modelindex)
1822 self.solid = SOLID_BSP;
1823 ExactTriggerHit_mins = other.absmin;
1824 ExactTriggerHit_maxs = other.absmax;
1825 f = ExactTriggerHit_Recurse();
1831 // WARNING: this kills the trace globals
1832 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1833 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1835 #define INITPRIO_FIRST 0
1836 #define INITPRIO_GAMETYPE 0
1837 #define INITPRIO_GAMETYPE_FALLBACK 1
1838 #define INITPRIO_CVARS 5
1839 #define INITPRIO_FINDTARGET 10
1840 #define INITPRIO_DROPTOFLOOR 20
1841 #define INITPRIO_SETLOCATION 90
1842 #define INITPRIO_LINKDOORS 91
1843 #define INITPRIO_LAST 99
1845 .void(void) initialize_entity;
1846 .float initialize_entity_order;
1847 .entity initialize_entity_next;
1848 entity initialize_entity_first;
1850 void make_safe_for_remove(entity e)
1852 if (e.initialize_entity)
1855 for (ent = initialize_entity_first; ent; )
1857 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1859 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1860 // skip it in linked list
1863 prev.initialize_entity_next = ent.initialize_entity_next;
1864 ent = prev.initialize_entity_next;
1868 initialize_entity_first = ent.initialize_entity_next;
1869 ent = initialize_entity_first;
1875 ent = ent.initialize_entity_next;
1881 void objerror(string s)
1883 make_safe_for_remove(self);
1884 objerror_builtin(s);
1887 void remove_unsafely(entity e)
1892 void remove_safely(entity e)
1894 make_safe_for_remove(e);
1898 void InitializeEntity(entity e, void(void) func, float order)
1902 if (!e || e.initialize_entity)
1904 // make a proxy initializer entity
1908 e.classname = "initialize_entity";
1912 e.initialize_entity = func;
1913 e.initialize_entity_order = order;
1915 cur = initialize_entity_first;
1918 if (!cur || cur.initialize_entity_order > order)
1920 // insert between prev and cur
1922 prev.initialize_entity_next = e;
1924 initialize_entity_first = e;
1925 e.initialize_entity_next = cur;
1929 cur = cur.initialize_entity_next;
1932 void InitializeEntitiesRun()
1935 startoflist = initialize_entity_first;
1936 initialize_entity_first = world;
1937 for (self = startoflist; self; )
1940 var void(void) func;
1941 e = self.initialize_entity_next;
1942 func = self.initialize_entity;
1943 self.initialize_entity_order = 0;
1944 self.initialize_entity = func_null;
1945 self.initialize_entity_next = world;
1946 if (self.classname == "initialize_entity")
1950 remove_builtin(self);
1953 //dprint("Delayed initialization: ", self.classname, "\n");
1959 .float uncustomizeentityforclient_set;
1960 .void(void) uncustomizeentityforclient;
1961 void(void) SUB_Nullpointer = #0;
1962 void UncustomizeEntitiesRun()
1966 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1967 self.uncustomizeentityforclient();
1970 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1972 e.customizeentityforclient = customizer;
1973 e.uncustomizeentityforclient = uncustomizer;
1974 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1978 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1981 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1985 if (e.classname == "")
1986 e.classname = "net_linked";
1988 if (e.model == "" || self.modelindex == 0)
1992 setmodel(e, "null");
1996 e.SendEntity = sendfunc;
1997 e.SendFlags = 0xFFFFFF;
2000 e.effects |= EF_NODEPTHTEST;
2004 e.nextthink = time + dt;
2005 e.think = SUB_Remove;
2009 void adaptor_think2touch()
2018 void adaptor_think2use()
2030 // deferred dropping
2031 void DropToFloor_Handler()
2033 droptofloor_builtin();
2034 self.dropped_origin = self.origin;
2039 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
2044 float trace_hits_box_a0, trace_hits_box_a1;
2046 float trace_hits_box_1d(float end, float thmi, float thma)
2050 // just check if x is in range
2058 // do the trace with respect to x
2059 // 0 -> end has to stay in thmi -> thma
2060 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
2061 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
2062 if (trace_hits_box_a0 > trace_hits_box_a1)
2068 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
2073 // now it is a trace from 0 to end
2075 trace_hits_box_a0 = 0;
2076 trace_hits_box_a1 = 1;
2078 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
2080 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
2082 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
2088 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
2090 return trace_hits_box(start, end, thmi - ma, thma - mi);
2093 float SUB_NoImpactCheck()
2095 // zero hitcontents = this is not the real impact, but either the
2096 // mirror-impact of something hitting the projectile instead of the
2097 // projectile hitting the something, or a touchareagrid one. Neither of
2098 // these stop the projectile from moving, so...
2099 if(trace_dphitcontents == 0)
2101 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
2104 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2106 if (other == world && self.size != '0 0 0')
2109 tic = self.velocity * sys_frametime;
2110 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
2111 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
2112 if (trace_fraction >= 1)
2114 dprint("Odd... did not hit...?\n");
2116 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2118 dprint("Detected and prevented the sky-grapple bug.\n");
2126 #define SUB_OwnerCheck() (other && (other == self.owner))
2128 #define PROJECTILE_TOUCH do { if(SUB_OwnerCheck()) return; if(SUB_NoImpactCheck()) { remove(self); return; } if(trace_ent && trace_ent.solid > SOLID_TRIGGER) UpdateCSQCProjectileNextFrame(self); } while(0)
2130 float MAX_IPBAN_URIS = 16;
2132 float URI_GET_DISCARD = 0;
2133 float URI_GET_IPBAN = 1;
2134 float URI_GET_IPBAN_END = 16;
2136 void URI_Get_Callback(float id, float status, string data)
2138 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2140 dprint("\nEnd of data.\n");
2142 if (id == URI_GET_DISCARD)
2146 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2149 OnlineBanList_URI_Get_Callback(id, status, data);
2153 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2157 void print_to(entity e, string s)
2160 sprint(e, strcat(s, "\n"));
2179 for (i = 0; i < MapInfo_count; ++i)
2181 if (MapInfo_Get_ByID(i))
2183 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2186 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2187 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2195 for (i = 0; i < MapInfo_count; ++i)
2197 if (MapInfo_Get_ByID(i))
2199 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2202 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2203 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2211 for (i = 0; i < MapInfo_count; ++i)
2213 if (MapInfo_Get_ByID(i))
2215 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2218 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2219 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2225 MapInfo_ClearTemps();
2228 return "No records are available on this server.\n";
2230 return strcat("Records on this server:\n", s);
2233 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2236 vector start, org, delta, end, enddown, mstart;
2238 m = e.dphitcontentsmask;
2239 e.dphitcontentsmask = goodcontents | badcontents;
2242 delta = world.maxs - world.mins;
2244 for (i = 0; i < attempts; ++i)
2246 start_x = org_x + random() * delta_x;
2247 start_y = org_y + random() * delta_y;
2248 start_z = org_z + random() * delta_z;
2250 // rule 1: start inside world bounds, and outside
2251 // solid, and don't start from somewhere where you can
2252 // fall down to evil
2253 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2254 if (trace_fraction >= 1)
2256 if (trace_startsolid)
2258 if (trace_dphitcontents & badcontents)
2260 if (trace_dphitq3surfaceflags & badsurfaceflags)
2263 // rule 2: if we are too high, lower the point
2264 if (trace_fraction * delta_z > maxaboveground)
2265 start = trace_endpos + '0 0 1' * maxaboveground;
2266 enddown = trace_endpos;
2268 // rule 3: make sure we aren't outside the map. This only works
2269 // for somewhat well formed maps. A good rule of thumb is that
2270 // the map should have a convex outside hull.
2271 // these can be traceLINES as we already verified the starting box
2272 mstart = start + 0.5 * (e.mins + e.maxs);
2273 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2274 if (trace_fraction >= 1)
2276 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2277 if (trace_fraction >= 1)
2279 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2280 if (trace_fraction >= 1)
2282 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2283 if (trace_fraction >= 1)
2285 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2286 if (trace_fraction >= 1)
2289 // find a random vector to "look at"
2290 end_x = org_x + random() * delta_x;
2291 end_y = org_y + random() * delta_y;
2292 end_z = org_z + random() * delta_z;
2293 end = start + normalize(end - start) * vlen(delta);
2295 // rule 4: start TO end must not be too short
2296 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2297 if (trace_startsolid)
2299 if (trace_fraction < minviewdistance / vlen(delta))
2302 // rule 5: don't want to look at sky
2303 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2306 // rule 6: we must not end up in trigger_hurt
2307 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2309 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2316 e.dphitcontentsmask = m;
2320 setorigin(e, start);
2321 e.angles = vectoangles(end - start);
2322 dprint("Needed ", ftos(i + 1), " attempts\n");
2329 float zcurveparticles_effectno;
2330 vector zcurveparticles_start;
2331 float zcurveparticles_spd;
2333 void endzcurveparticles()
2335 if(zcurveparticles_effectno)
2338 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2340 zcurveparticles_effectno = 0;
2343 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2345 spd = bound(0, floor(spd / 16), 32767);
2346 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2348 endzcurveparticles();
2349 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2350 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2351 WriteShort(MSG_BROADCAST, effectno);
2352 WriteCoord(MSG_BROADCAST, start_x);
2353 WriteCoord(MSG_BROADCAST, start_y);
2354 WriteCoord(MSG_BROADCAST, start_z);
2355 zcurveparticles_effectno = effectno;
2356 zcurveparticles_start = start;
2359 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2360 WriteCoord(MSG_BROADCAST, end_x);
2361 WriteCoord(MSG_BROADCAST, end_y);
2362 WriteCoord(MSG_BROADCAST, end_z);
2363 WriteCoord(MSG_BROADCAST, end_dz);
2364 zcurveparticles_spd = spd;
2367 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2370 vector vecxy, velxy;
2372 vecxy = end - start;
2377 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2379 endzcurveparticles();
2380 trailparticles(world, effectno, start, end);
2384 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2385 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2388 string GetGametype(); // g_world.qc
2389 void write_recordmarker(entity pl, float tstart, float dt)
2391 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2393 // also write a marker into demo files for demotc-race-record-extractor to find
2396 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2397 " ", ftos(tstart), " ", ftos(dt), "\n"));
2400 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2402 switch(self.owner.cvar_cl_gunalign)
2413 if(allowcenter) // 2: allow center handedness
2426 if(allowcenter) // 2: allow center handedness
2442 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2447 if (cvar("g_shootfromeye"))
2451 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2459 else if (cvar("g_shootfromcenter"))
2463 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2471 else if (cvar("g_shootfromclient"))
2473 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2475 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2490 void attach_sameorigin(entity e, entity to, string tag)
2492 vector org, t_forward, t_left, t_up, e_forward, e_up;
2499 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2500 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2501 t_forward = v_forward * tagscale;
2502 t_left = v_right * -tagscale;
2503 t_up = v_up * tagscale;
2505 e.origin_x = org * t_forward;
2506 e.origin_y = org * t_left;
2507 e.origin_z = org * t_up;
2509 // current forward and up directions
2510 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2511 e.angles_x = -e.angles_x;
2512 fixedmakevectors(e.angles);
2514 // untransform forward, up!
2515 e_forward_x = v_forward * t_forward;
2516 e_forward_y = v_forward * t_left;
2517 e_forward_z = v_forward * t_up;
2518 e_up_x = v_up * t_forward;
2519 e_up_y = v_up * t_left;
2520 e_up_z = v_up * t_up;
2522 e.angles = fixedvectoangles2(e_forward, e_up);
2523 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2524 e.angles_x = -e.angles_x;
2526 setattachment(e, to, tag);
2527 setorigin(e, e.origin);
2530 void detach_sameorigin(entity e)
2533 org = gettaginfo(e, 0);
2534 e.angles = fixedvectoangles2(v_forward, v_up);
2535 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2536 e.angles_x = -e.angles_x;
2538 setattachment(e, world, "");
2539 setorigin(e, e.origin);
2542 void follow_sameorigin(entity e, entity to)
2544 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2545 e.aiment = to; // make the hole follow bmodel
2546 e.punchangle = to.angles; // the original angles of bmodel
2547 e.view_ofs = e.origin - to.origin; // relative origin
2548 e.v_angle = e.angles - to.angles; // relative angles
2551 void unfollow_sameorigin(entity e)
2553 e.movetype = MOVETYPE_NONE;
2556 entity gettaginfo_relative_ent;
2557 vector gettaginfo_relative(entity e, float tag)
2559 if (!gettaginfo_relative_ent)
2561 gettaginfo_relative_ent = spawn();
2562 gettaginfo_relative_ent.effects = EF_NODRAW;
2564 gettaginfo_relative_ent.model = e.model;
2565 gettaginfo_relative_ent.modelindex = e.modelindex;
2566 gettaginfo_relative_ent.frame = e.frame;
2567 return gettaginfo(gettaginfo_relative_ent, tag);
2570 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2574 if (pl.soundentity.cnt & p)
2576 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2577 pl.soundentity.cnt |= p;
2580 void SoundEntity_StopSound(entity pl, float chan)
2584 if (pl.soundentity.cnt & p)
2586 stopsoundto(MSG_ALL, pl.soundentity, chan);
2587 pl.soundentity.cnt &~= p;
2591 void SoundEntity_Attach(entity pl)
2593 pl.soundentity = spawn();
2594 pl.soundentity.classname = "soundentity";
2595 pl.soundentity.owner = pl;
2596 setattachment(pl.soundentity, pl, "");
2597 setmodel(pl.soundentity, "null");
2600 void SoundEntity_Detach(entity pl)
2603 for (i = 0; i <= 7; ++i)
2604 SoundEntity_StopSound(pl, i);
2608 float ParseCommandPlayerSlotTarget_firsttoken;
2609 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2617 ParseCommandPlayerSlotTarget_firsttoken = -1;
2621 if (substring(argv(idx), 0, 1) == "#")
2623 s = substring(argv(idx), 1, -1);
2631 ParseCommandPlayerSlotTarget_firsttoken = idx;
2632 if (s == ftos(stof(s)))
2634 e = edict_num(stof(s));
2635 if (e.flags & FL_CLIENT)
2641 // it must be a nick name
2644 ParseCommandPlayerSlotTarget_firsttoken = idx;
2647 FOR_EACH_CLIENT(head)
2648 if (head.netname == s)
2656 s = strdecolorize(s);
2658 FOR_EACH_CLIENT(head)
2659 if (strdecolorize(head.netname) == s)
2674 float modeleffect_SendEntity(entity to, float sf)
2677 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2680 if(self.velocity != '0 0 0')
2682 if(self.angles != '0 0 0')
2684 if(self.avelocity != '0 0 0')
2687 WriteByte(MSG_ENTITY, f);
2688 WriteShort(MSG_ENTITY, self.modelindex);
2689 WriteByte(MSG_ENTITY, self.skin);
2690 WriteByte(MSG_ENTITY, self.frame);
2691 WriteCoord(MSG_ENTITY, self.origin_x);
2692 WriteCoord(MSG_ENTITY, self.origin_y);
2693 WriteCoord(MSG_ENTITY, self.origin_z);
2696 WriteCoord(MSG_ENTITY, self.velocity_x);
2697 WriteCoord(MSG_ENTITY, self.velocity_y);
2698 WriteCoord(MSG_ENTITY, self.velocity_z);
2702 WriteCoord(MSG_ENTITY, self.angles_x);
2703 WriteCoord(MSG_ENTITY, self.angles_y);
2704 WriteCoord(MSG_ENTITY, self.angles_z);
2708 WriteCoord(MSG_ENTITY, self.avelocity_x);
2709 WriteCoord(MSG_ENTITY, self.avelocity_y);
2710 WriteCoord(MSG_ENTITY, self.avelocity_z);
2712 WriteShort(MSG_ENTITY, self.scale * 256.0);
2713 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2714 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2715 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2716 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2721 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)
2726 e.classname = "modeleffect";
2734 e.teleport_time = t1;
2738 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2742 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2745 sz = max(e.scale, e.scale2);
2746 setsize(e, e.mins * sz, e.maxs * sz);
2747 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2750 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2752 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2755 float randombit(float bits)
2757 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2766 for(f = 1; f <= bits; f *= 2)
2775 r = (r - 1) / (n - 1);
2782 float randombits(float bits, float k, float error_return)
2786 while(k > 0 && bits != r)
2788 r += randombit(bits - r);
2797 void randombit_test(float bits, float iter)
2801 print(ftos(randombit(bits)), "\n");
2806 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2808 if(halflifedist > 0)
2809 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2810 else if(halflifedist < 0)
2811 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2820 #define cvar_string_normal cvar_string_builtin
2821 #define cvar_normal cvar_builtin
2823 string cvar_string_normal(string n)
2825 if not(cvar_type(n) & 1)
2826 backtrace(strcat("Attempt to access undefined cvar: ", n));
2827 return cvar_string_builtin(n);
2830 float cvar_normal(string n)
2832 return stof(cvar_string_normal(n));
2835 #define cvar_set_normal cvar_set_builtin
2843 oself.think = SUB_Remove;
2844 oself.nextthink = time;
2850 Execute func() after time + fdelay.
2851 self when func is executed = self when defer is called
2853 void defer(float fdelay, void() func)
2860 e.think = defer_think;
2861 e.nextthink = time + fdelay;