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)
221 float spawnpoint_nag;
222 void relocate_spawnpoint()
224 // nudge off the floor
225 setorigin(self, self.origin + '0 0 1');
227 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
228 if (trace_startsolid)
234 if (!move_out_of_solid(self))
235 objerror("could not get out of solid at all!");
236 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
237 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
238 print(" ", ftos(self.origin_y - o_y));
239 print(" ", ftos(self.origin_z - o_z), "'\n");
240 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
243 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
249 self.mins = self.maxs = '0 0 0';
250 objerror("player spawn point in solid, mapper sucks!\n");
255 if (cvar("g_spawnpoints_autodrop"))
257 setsize(self, PL_MIN, PL_MAX);
261 self.use = spawnpoint_use;
262 self.team_saved = self.team;
266 if (have_team_spawns != 0)
268 have_team_spawns = 1;
270 if (cvar("r_showbboxes"))
272 // show where spawnpoints point at too
273 makevectors(self.angles);
276 e.classname = "info_player_foo";
277 setorigin(e, self.origin + v_forward * 24);
278 setsize(e, '-8 -8 -8', '8 8 8');
279 e.solid = SOLID_TRIGGER;
283 #define strstr strstrofs
285 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
286 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
287 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
288 // BE CONSTANT OR strzoneD!
289 float strstr(string haystack, string needle, float offset)
293 len = strlen(needle);
294 endpos = strlen(haystack) - len;
295 while(offset <= endpos)
297 found = substring(haystack, offset, len);
306 float NUM_NEAREST_ENTITIES = 4;
307 entity nearest_entity[NUM_NEAREST_ENTITIES];
308 float nearest_length[NUM_NEAREST_ENTITIES];
309 entity findnearest(vector point, .string field, string value, vector axismod)
320 localhead = find(world, field, value);
323 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
324 dist = localhead.oldorigin;
326 dist = localhead.origin;
328 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
331 for (i = 0; i < num_nearest; ++i)
333 if (len < nearest_length[i])
337 // now i tells us where to insert at
338 // INSERTION SORT! YOU'VE SEEN IT! RUN!
339 if (i < NUM_NEAREST_ENTITIES)
341 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
343 nearest_length[j + 1] = nearest_length[j];
344 nearest_entity[j + 1] = nearest_entity[j];
346 nearest_length[i] = len;
347 nearest_entity[i] = localhead;
348 if (num_nearest < NUM_NEAREST_ENTITIES)
349 num_nearest = num_nearest + 1;
352 localhead = find(localhead, field, value);
355 // now use the first one from our list that we can see
356 for (i = 0; i < num_nearest; ++i)
358 traceline(point, nearest_entity[i].origin, TRUE, world);
359 if (trace_fraction == 1)
363 dprint("Nearest point (");
364 dprint(nearest_entity[0].netname);
365 dprint(") is not visible, using a visible one.\n");
367 return nearest_entity[i];
371 if (num_nearest == 0)
374 dprint("Not seeing any location point, using nearest as fallback.\n");
376 dprint("Candidates were: ");
377 for(j = 0; j < num_nearest; ++j)
381 dprint(nearest_entity[j].netname);
386 return nearest_entity[0];
389 void spawnfunc_target_location()
391 self.classname = "target_location";
392 // location name in netname
393 // eventually support: count, teamgame selectors, line of sight?
396 void spawnfunc_info_location()
398 self.classname = "target_location";
399 self.message = self.netname;
402 string NearestLocation(vector p)
407 loc = findnearest(p, classname, "target_location", '1 1 1');
414 loc = findnearest(p, target, "###item###", '1 1 4');
421 string formatmessage(string msg)
432 break; // too many replacements
435 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
436 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
449 replacement = substring(msg, p, 2);
450 escape = substring(msg, p + 1, 1);
454 else if (escape == "\\")
456 else if (escape == "n")
458 else if (escape == "a")
459 replacement = ftos(floor(self.armorvalue));
460 else if (escape == "h")
461 replacement = ftos(floor(self.health));
462 else if (escape == "l")
463 replacement = NearestLocation(self.origin);
464 else if (escape == "y")
465 replacement = NearestLocation(self.cursor_trace_endpos);
466 else if (escape == "d")
467 replacement = NearestLocation(self.death_origin);
468 else if (escape == "w") {
472 wep = self.switchweapon;
475 replacement = W_Name(wep);
476 } else if (escape == "W") {
477 if (self.items & IT_SHELLS) replacement = "shells";
478 else if (self.items & IT_NAILS) replacement = "bullets";
479 else if (self.items & IT_ROCKETS) replacement = "rockets";
480 else if (self.items & IT_CELLS) replacement = "cells";
481 else replacement = "batteries"; // ;)
482 } else if (escape == "x") {
483 replacement = self.cursor_trace_ent.netname;
484 if (!replacement || !self.cursor_trace_ent)
485 replacement = "nothing";
486 } else if (escape == "p") {
487 if (self.last_selected_player)
488 replacement = self.last_selected_player.netname;
490 replacement = "(nobody)";
491 } else if (escape == "s")
492 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
493 else if (escape == "S")
494 replacement = ftos(vlen(self.velocity));
495 else if (escape == "v") {
499 if(self.classname == "spectator")
504 weapon_number = stats.weapon;
507 weapon_number = stats.switchweapon;
510 weapon_number = stats.cnt;
512 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
513 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
515 replacement = "~"; // or something to indicate NULL, not available
518 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
519 p = p + strlen(replacement);
524 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
525 return (value == 0) ? FALSE : TRUE;
534 >0: receives a cvar from name=argv(f) value=argv(f+1)
536 void GetCvars_handleString(string thisname, float f, .string field, string name)
541 strunzone(self.field);
542 self.field = string_null;
546 if (thisname == name)
549 strunzone(self.field);
550 self.field = strzone(argv(f + 1));
554 stuffcmd(self, strcat("sendcvar ", name, "\n"));
556 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
558 GetCvars_handleString(thisname, f, field, name);
559 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
560 if (thisname == name)
563 s = func(strcat1(self.field));
566 strunzone(self.field);
567 self.field = strzone(s);
571 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
578 if (thisname == name)
579 self.field = stof(argv(f + 1));
582 stuffcmd(self, strcat("sendcvar ", name, "\n"));
584 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
591 if (thisname == name)
595 self.field = stof(argv(f + 1));
604 stuffcmd(self, strcat("sendcvar ", name, "\n"));
607 string W_FixWeaponOrder_ForceComplete(string s);
608 string W_FixWeaponOrder_AllowIncomplete(string s);
609 float w_getbestweapon(entity e);
610 void GetCvars(float f)
614 s = strcat1(argv(f));
615 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
616 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
617 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
618 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
619 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
620 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
621 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
622 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
623 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
624 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
625 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
626 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
627 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
628 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
629 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
630 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
631 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
632 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
633 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
634 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
635 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
636 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
637 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
638 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
640 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
641 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
643 #ifdef ALLOW_FORCEMODELS
644 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
645 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
647 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
649 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
652 if (s == "cl_weaponpriority")
653 self.switchweapon = w_getbestweapon(self);
657 float fexists(string f)
660 fh = fopen(f, FILE_READ);
667 void backtrace(string msg)
670 dev = cvar("developer");
671 war = cvar("prvm_backtraceforwarnings");
672 cvar_set("developer", "1");
673 cvar_set("prvm_backtraceforwarnings", "1");
675 dprint("--- CUT HERE ---\nWARNING: ");
678 remove(world); // isn't there any better way to cause a backtrace?
679 dprint("\n--- CUT UNTIL HERE ---\n");
680 cvar_set("developer", ftos(dev));
681 cvar_set("prvm_backtraceforwarnings", ftos(war));
684 string Team_ColorCode(float teamid)
686 if (teamid == COLOR_TEAM1)
688 else if (teamid == COLOR_TEAM2)
690 else if (teamid == COLOR_TEAM3)
692 else if (teamid == COLOR_TEAM4)
698 string Team_ColorName(float t)
700 // fixme: Search for team entities and get their .netname's!
701 if (t == COLOR_TEAM1)
703 if (t == COLOR_TEAM2)
705 if (t == COLOR_TEAM3)
707 if (t == COLOR_TEAM4)
712 string Team_ColorNameLowerCase(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 float ColourToNumber(string team_colour)
728 if (team_colour == "red")
731 if (team_colour == "blue")
734 if (team_colour == "yellow")
737 if (team_colour == "pink")
740 if (team_colour == "auto")
746 float NumberToTeamNumber(float number)
763 #define CENTERPRIO_POINT 1
764 #define CENTERPRIO_SPAM 2
765 #define CENTERPRIO_VOTE 4
766 #define CENTERPRIO_NORMAL 5
767 #define CENTERPRIO_SHIELDING 7
768 #define CENTERPRIO_MAPVOTE 9
769 #define CENTERPRIO_IDLEKICK 50
770 #define CENTERPRIO_ADMIN 99
771 .float centerprint_priority;
772 .float centerprint_expires;
773 void centerprint_atprio(entity e, float prio, string s)
775 if (intermission_running)
776 if (prio < CENTERPRIO_MAPVOTE)
778 if (time > e.centerprint_expires)
779 e.centerprint_priority = 0;
780 if (prio >= e.centerprint_priority)
782 e.centerprint_priority = prio;
783 if (timeoutStatus == 2)
784 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
786 e.centerprint_expires = time + e.cvar_scr_centertime;
787 centerprint_builtin(e, s);
790 void centerprint_expire(entity e, float prio)
792 if (prio == e.centerprint_priority)
794 e.centerprint_priority = 0;
795 centerprint_builtin(e, "");
798 void centerprint(entity e, string s)
800 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
803 // decolorizes and team colors the player name when needed
804 string playername(entity p)
807 if (teams_matter && !intermission_running && p.classname == "player")
809 t = Team_ColorCode(p.team);
810 return strcat(t, strdecolorize(p.netname));
816 vector randompos(vector m1, vector m2)
820 v_x = m2_x * random() + m1_x;
821 v_y = m2_y * random() + m1_y;
822 v_z = m2_z * random() + m1_z;
826 float g_pickup_shells;
827 float g_pickup_shells_max;
828 float g_pickup_nails;
829 float g_pickup_nails_max;
830 float g_pickup_rockets;
831 float g_pickup_rockets_max;
832 float g_pickup_cells;
833 float g_pickup_cells_max;
835 float g_pickup_fuel_jetpack;
836 float g_pickup_fuel_max;
837 float g_pickup_armorsmall;
838 float g_pickup_armorsmall_max;
839 float g_pickup_armormedium;
840 float g_pickup_armormedium_max;
841 float g_pickup_armorbig;
842 float g_pickup_armorbig_max;
843 float g_pickup_armorlarge;
844 float g_pickup_armorlarge_max;
845 float g_pickup_healthsmall;
846 float g_pickup_healthsmall_max;
847 float g_pickup_healthmedium;
848 float g_pickup_healthmedium_max;
849 float g_pickup_healthlarge;
850 float g_pickup_healthlarge_max;
851 float g_pickup_healthmega;
852 float g_pickup_healthmega_max;
854 float g_weaponarena_random;
855 string g_weaponarena_list;
856 float g_weaponspeedfactor;
857 float g_weaponratefactor;
858 float g_weapondamagefactor;
859 float g_weaponforcefactor;
863 float start_ammo_shells;
864 float start_ammo_nails;
865 float start_ammo_rockets;
866 float start_ammo_cells;
867 float start_ammo_fuel;
869 float start_armorvalue;
870 float warmup_start_weapons;
871 float warmup_start_ammo_shells;
872 float warmup_start_ammo_nails;
873 float warmup_start_ammo_rockets;
874 float warmup_start_ammo_cells;
875 float warmup_start_ammo_fuel;
876 float warmup_start_health;
877 float warmup_start_armorvalue;
881 entity get_weaponinfo(float w);
883 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
885 var float i = weaponinfo.weapon;
890 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
892 if (t < 0) // "default" weapon selection
894 if (g_lms || g_ca || allguns)
895 t = (weaponinfo.spawnflags & WEPSPAWNFLAG_NORMAL);
898 else if (g_race || g_cts)
899 t = (i == WEP_LASER);
901 t = 0; // weapon is set a few lines later
903 t = (i == WEP_LASER || i == WEP_SHOTGUN);
904 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
905 t |= (i == WEP_HOOK);
908 // we cannot disable porto in Nexball, we must force it
909 if(g_nexball && i == WEP_PORTO)
915 float NixNex_CanChooseWeapon(float wpn);
916 void readplayerstartcvars()
922 // initialize starting values for players
925 start_ammo_shells = 0;
926 start_ammo_nails = 0;
927 start_ammo_rockets = 0;
928 start_ammo_cells = 0;
929 start_health = cvar("g_balance_health_start");
930 start_armorvalue = cvar("g_balance_armor_start");
933 s = cvar_string("g_weaponarena");
939 g_weaponarena_list = "All Weapons";
940 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
942 e = get_weaponinfo(j);
943 g_weaponarena |= e.weapons;
944 weapon_action(e.weapon, WR_PRECACHE);
947 else if (s == "most")
949 g_weaponarena_list = "Most Weapons";
950 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
952 e = get_weaponinfo(j);
953 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
955 g_weaponarena |= e.weapons;
956 weapon_action(e.weapon, WR_PRECACHE);
960 else if (s == "none")
962 g_weaponarena_list = "No Weapons";
963 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
967 t = tokenize_console(s);
968 g_weaponarena_list = "";
969 for (i = 0; i < t; ++i)
972 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
974 e = get_weaponinfo(j);
977 g_weaponarena |= e.weapons;
978 weapon_action(e.weapon, WR_PRECACHE);
979 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
985 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
988 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
992 g_weaponarena_random = cvar("g_weaponarena_random");
994 g_weaponarena_random = 0;
999 // will be done later
1000 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1001 if (NixNex_CanChooseWeapon(i))
1002 weapon_action(i, WR_PRECACHE);
1003 if(!cvar("g_use_ammunition"))
1004 start_items |= IT_UNLIMITED_AMMO;
1006 else if (g_weaponarena)
1008 start_weapons = g_weaponarena;
1009 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
1010 start_ammo_rockets = 999;
1011 if (g_weaponarena & WEPBIT_SHOTGUN)
1012 start_ammo_shells = 999;
1013 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
1014 start_ammo_cells = 999;
1015 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
1016 start_ammo_nails = 999;
1017 if (g_weaponarena & WEPBIT_HOOK)
1018 start_ammo_fuel = 999;
1019 start_items |= IT_UNLIMITED_AMMO;
1021 else if (g_minstagib)
1024 start_armorvalue = 0;
1025 start_weapons = WEPBIT_MINSTANEX;
1026 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
1027 start_ammo_cells = cvar("g_minstagib_ammo_start");
1028 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
1029 start_ammo_fuel = cvar("g_start_ammo_fuel");
1031 if (g_minstagib_invis_alpha <= 0)
1032 g_minstagib_invis_alpha = -1;
1038 start_ammo_shells = cvar("g_lms_start_ammo_shells");
1039 start_ammo_nails = cvar("g_lms_start_ammo_nails");
1040 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
1041 start_ammo_cells = cvar("g_lms_start_ammo_cells");
1042 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
1043 start_health = cvar("g_lms_start_health");
1044 start_armorvalue = cvar("g_lms_start_armor");
1046 else if (cvar("g_use_ammunition"))
1048 start_ammo_shells = cvar("g_start_ammo_shells");
1049 start_ammo_nails = cvar("g_start_ammo_nails");
1050 start_ammo_rockets = cvar("g_start_ammo_rockets");
1051 start_ammo_cells = cvar("g_start_ammo_cells");
1052 start_ammo_fuel = cvar("g_start_ammo_fuel");
1056 start_ammo_shells = cvar("g_pickup_shells_max");
1057 start_ammo_nails = cvar("g_pickup_nails_max");
1058 start_ammo_rockets = cvar("g_pickup_rockets_max");
1059 start_ammo_cells = cvar("g_pickup_cells_max");
1060 start_ammo_fuel = cvar("g_pickup_fuel_max");
1061 start_items |= IT_UNLIMITED_AMMO;
1064 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1066 e = get_weaponinfo(i);
1067 if(want_weapon("g_start_weapon_", e, FALSE))
1069 start_weapons |= e.weapons;
1070 weapon_action(e.weapon, WR_PRECACHE);
1077 warmup_start_ammo_shells = start_ammo_shells;
1078 warmup_start_ammo_nails = start_ammo_nails;
1079 warmup_start_ammo_rockets = start_ammo_rockets;
1080 warmup_start_ammo_cells = start_ammo_cells;
1081 warmup_start_ammo_fuel = start_ammo_fuel;
1082 warmup_start_health = start_health;
1083 warmup_start_armorvalue = start_armorvalue;
1084 warmup_start_weapons = start_weapons;
1086 if (!g_weaponarena && !g_nixnex && !g_minstagib && !g_ca)
1088 if (cvar("g_use_ammunition"))
1090 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1091 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1092 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1093 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1094 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1096 warmup_start_health = cvar("g_warmup_start_health");
1097 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1098 warmup_start_weapons = 0;
1099 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1101 e = get_weaponinfo(i);
1102 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
1104 warmup_start_weapons |= e.weapons;
1105 weapon_action(e.weapon, WR_PRECACHE);
1111 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1113 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1114 start_items |= IT_FUEL_REGEN;
1115 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1116 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1120 start_items |= IT_JETPACK;
1122 if (g_weapon_stay == 2)
1124 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1125 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1126 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1127 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1128 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1129 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1130 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1131 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1132 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1133 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1136 start_ammo_shells = max(0, start_ammo_shells);
1137 start_ammo_nails = max(0, start_ammo_nails);
1138 start_ammo_cells = max(0, start_ammo_cells);
1139 start_ammo_rockets = max(0, start_ammo_rockets);
1140 start_ammo_fuel = max(0, start_ammo_fuel);
1142 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1143 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1144 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1145 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1146 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1150 float g_bugrigs_planar_movement;
1151 float g_bugrigs_planar_movement_car_jumping;
1152 float g_bugrigs_reverse_spinning;
1153 float g_bugrigs_reverse_speeding;
1154 float g_bugrigs_reverse_stopping;
1155 float g_bugrigs_air_steering;
1156 float g_bugrigs_angle_smoothing;
1157 float g_bugrigs_friction_floor;
1158 float g_bugrigs_friction_brake;
1159 float g_bugrigs_friction_air;
1160 float g_bugrigs_accel;
1161 float g_bugrigs_speed_ref;
1162 float g_bugrigs_speed_pow;
1163 float g_bugrigs_steer;
1165 float g_touchexplode;
1166 float g_touchexplode_radius;
1167 float g_touchexplode_damage;
1168 float g_touchexplode_edgedamage;
1169 float g_touchexplode_force;
1176 float sv_pitch_fixyaw;
1178 float sv_accuracy_data_share;
1180 void readlevelcvars(void)
1182 g_bugrigs = cvar("g_bugrigs");
1183 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1184 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1185 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1186 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1187 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1188 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1189 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1190 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1191 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1192 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1193 g_bugrigs_accel = cvar("g_bugrigs_accel");
1194 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1195 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1196 g_bugrigs_steer = cvar("g_bugrigs_steer");
1198 g_touchexplode = cvar("g_touchexplode");
1199 g_touchexplode_radius = cvar("g_touchexplode_radius");
1200 g_touchexplode_damage = cvar("g_touchexplode_damage");
1201 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1202 g_touchexplode_force = cvar("g_touchexplode_force");
1204 #ifdef ALLOW_FORCEMODELS
1205 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1207 sv_loddistance1 = cvar("sv_loddistance1");
1208 sv_loddistance2 = cvar("sv_loddistance2");
1210 if(sv_loddistance2 <= sv_loddistance1)
1211 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1213 sv_clones = cvar("sv_clones");
1214 sv_cheats = cvar("sv_cheats");
1215 sv_gentle = cvar("sv_gentle");
1216 sv_foginterval = cvar("sv_foginterval");
1217 g_cloaked = cvar("g_cloaked");
1218 g_jump_grunt = cvar("g_jump_grunt");
1219 g_footsteps = cvar("g_footsteps");
1220 g_grappling_hook = cvar("g_grappling_hook");
1221 g_jetpack = cvar("g_jetpack");
1222 g_laserguided_missile = cvar("g_laserguided_missile");
1223 g_midair = cvar("g_midair");
1224 g_minstagib = cvar("g_minstagib");
1225 g_nixnex = cvar("g_nixnex");
1226 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1227 g_norecoil = cvar("g_norecoil");
1228 g_vampire = cvar("g_vampire");
1229 g_bloodloss = cvar("g_bloodloss");
1230 sv_maxidle = cvar("sv_maxidle");
1231 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1232 sv_pogostick = cvar("sv_pogostick");
1233 sv_doublejump = cvar("sv_doublejump");
1234 g_ctf_reverse = cvar("g_ctf_reverse");
1235 sv_autotaunt = cvar("sv_autotaunt");
1236 sv_taunt = cvar("sv_taunt");
1238 inWarmupStage = cvar("g_warmup");
1239 g_warmup_limit = cvar("g_warmup_limit");
1240 g_warmup_allguns = cvar("g_warmup_allguns");
1241 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1243 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1244 inWarmupStage = 0; // these modes cannot work together, sorry
1246 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1247 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1248 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1249 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1250 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1251 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1252 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1253 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1254 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1255 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1256 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1257 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1259 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1260 if (g_nixnex) g_weaponarena = 0;
1263 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1264 g_weaponratefactor = cvar("g_weaponratefactor");
1265 g_weapondamagefactor = cvar("g_weapondamagefactor");
1266 g_weaponforcefactor = cvar("g_weaponforcefactor");
1268 g_pickup_shells = cvar("g_pickup_shells");
1269 g_pickup_shells_max = cvar("g_pickup_shells_max");
1270 g_pickup_nails = cvar("g_pickup_nails");
1271 g_pickup_nails_max = cvar("g_pickup_nails_max");
1272 g_pickup_rockets = cvar("g_pickup_rockets");
1273 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1274 g_pickup_cells = cvar("g_pickup_cells");
1275 g_pickup_cells_max = cvar("g_pickup_cells_max");
1276 g_pickup_fuel = cvar("g_pickup_fuel");
1277 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1278 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1279 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1280 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1281 g_pickup_armormedium = cvar("g_pickup_armormedium");
1282 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1283 g_pickup_armorbig = cvar("g_pickup_armorbig");
1284 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1285 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1286 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1287 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1288 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1289 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1290 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1291 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1292 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1293 g_pickup_healthmega = cvar("g_pickup_healthmega");
1294 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1296 g_pinata = cvar("g_pinata");
1298 g_weapon_stay = cvar("g_weapon_stay");
1300 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1303 g_ghost_items = cvar("g_ghost_items");
1305 if(g_ghost_items >= 1)
1306 g_ghost_items = 0.13; // default alpha value
1308 if not(inWarmupStage && !g_ca)
1309 game_starttime = cvar("g_start_delay");
1311 sv_pitch_min = cvar("sv_pitch_min");
1312 sv_pitch_max = cvar("sv_pitch_max");
1313 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1315 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
1317 readplayerstartcvars();
1321 // TODO sound pack system
1324 string precache_sound_builtin (string s) = #19;
1325 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1326 string precache_sound(string s)
1328 return precache_sound_builtin(strcat(soundpack, s));
1330 void play2(entity e, string filename)
1332 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1334 void sound(entity e, float chan, string samp, float vol, float atten)
1336 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1341 string precache_sound (string s) = #19;
1342 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1343 float precache_sound_index (string s) = #19;
1345 #define SND_VOLUME 1
1346 #define SND_ATTENUATION 2
1347 #define SND_LARGEENTITY 8
1348 #define SND_LARGESOUND 16
1350 float sound_allowed(float dest, entity e)
1352 // sounds from world may always pass
1355 if (e.classname == "body")
1357 if (e.owner && e.owner != e)
1362 // sounds to self may always pass
1363 if (dest == MSG_ONE)
1364 if (e == msg_entity)
1366 // sounds by players can be removed
1367 if (cvar("bot_sound_monopoly"))
1368 if (clienttype(e) == CLIENTTYPE_REAL)
1370 // anything else may pass
1374 void sound(entity e, float chan, string samp, float vol, float atten)
1376 if (!sound_allowed(MSG_BROADCAST, e))
1378 sound_builtin(e, chan, samp, vol, atten);
1380 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1384 if (!sound_allowed(dest, e))
1387 entno = num_for_edict(e);
1388 idx = precache_sound_index(samp);
1393 atten = floor(atten * 64);
1394 vol = floor(vol * 255);
1397 sflags |= SND_VOLUME;
1399 sflags |= SND_ATTENUATION;
1401 sflags |= SND_LARGEENTITY;
1403 sflags |= SND_LARGESOUND;
1405 WriteByte(dest, SVC_SOUND);
1406 WriteByte(dest, sflags);
1407 if (sflags & SND_VOLUME)
1408 WriteByte(dest, vol);
1409 if (sflags & SND_ATTENUATION)
1410 WriteByte(dest, atten);
1411 if (sflags & SND_LARGEENTITY)
1413 WriteShort(dest, entno);
1414 WriteByte(dest, chan);
1418 WriteShort(dest, entno * 8 + chan);
1420 if (sflags & SND_LARGESOUND)
1421 WriteShort(dest, idx);
1423 WriteByte(dest, idx);
1425 WriteCoord(dest, o_x);
1426 WriteCoord(dest, o_y);
1427 WriteCoord(dest, o_z);
1429 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1433 if (!sound_allowed(dest, e))
1436 o = e.origin + 0.5 * (e.mins + e.maxs);
1437 soundtoat(dest, e, o, chan, samp, vol, atten);
1439 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1441 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1443 void stopsoundto(float dest, entity e, float chan)
1447 if (!sound_allowed(dest, e))
1450 entno = num_for_edict(e);
1455 idx = precache_sound_index("misc/null.wav");
1456 sflags = SND_LARGEENTITY;
1458 sflags |= SND_LARGESOUND;
1459 WriteByte(dest, SVC_SOUND);
1460 WriteByte(dest, sflags);
1461 WriteShort(dest, entno);
1462 WriteByte(dest, chan);
1463 if (sflags & SND_LARGESOUND)
1464 WriteShort(dest, idx);
1466 WriteByte(dest, idx);
1467 WriteCoord(dest, e.origin_x);
1468 WriteCoord(dest, e.origin_y);
1469 WriteCoord(dest, e.origin_z);
1473 WriteByte(dest, SVC_STOPSOUND);
1474 WriteShort(dest, entno * 8 + chan);
1477 void stopsound(entity e, float chan)
1479 if (!sound_allowed(MSG_BROADCAST, e))
1482 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1483 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1486 void play2(entity e, string filename)
1488 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1490 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1493 .float announcetime;
1494 float announce(entity player, string msg)
1496 if (time > player.announcetime)
1497 if (clienttype(player) == CLIENTTYPE_REAL)
1499 player.announcetime = time + 0.8;
1505 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1506 float spamsound(entity e, float chan, string samp, float vol, float atten)
1508 if (!sound_allowed(MSG_BROADCAST, e))
1511 if (time > e.announcetime)
1513 e.announcetime = time;
1514 sound(e, chan, samp, vol, atten);
1520 void play2team(float t, string filename)
1524 if (cvar("bot_sound_monopoly"))
1527 FOR_EACH_REALPLAYER(head)
1530 play2(head, filename);
1534 void play2all(string samp)
1536 if (cvar("bot_sound_monopoly"))
1539 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1542 void PrecachePlayerSounds(string f);
1543 void precache_all_models(string pattern)
1545 float globhandle, i, n;
1548 globhandle = search_begin(pattern, TRUE, FALSE);
1551 n = search_getsize(globhandle);
1552 for (i = 0; i < n; ++i)
1554 //print(search_getfilename(globhandle, i), "\n");
1555 f = search_getfilename(globhandle, i);
1558 if(substring(f, -9,5) == "_lod1")
1560 if(substring(f, -9,5) == "_lod2")
1562 if(!sv_loddistance1)
1564 PrecachePlayerSounds(strcat(f, ".sounds"));
1566 search_end(globhandle);
1571 // gamemode related things
1572 precache_model ("models/misc/chatbubble.spr");
1573 precache_model ("models/misc/teambubble.spr");
1576 precache_model ("models/runematch/curse.mdl");
1577 precache_model ("models/runematch/rune.mdl");
1580 #ifdef TTURRETS_ENABLED
1581 if (cvar("g_turrets"))
1585 // Precache all player models if desired
1586 if (cvar("sv_precacheplayermodels"))
1588 PrecachePlayerSounds("sound/player/default.sounds");
1589 precache_all_models("models/player/*.zym");
1590 precache_all_models("models/player/*.dpm");
1591 precache_all_models("models/player/*.md3");
1592 precache_all_models("models/player/*.psk");
1593 //precache_model("models/player/carni.zym");
1594 //precache_model("models/player/crash.zym");
1595 //precache_model("models/player/grunt.zym");
1596 //precache_model("models/player/headhunter.zym");
1597 //precache_model("models/player/insurrectionist.zym");
1598 //precache_model("models/player/jeandarc.zym");
1599 //precache_model("models/player/lurk.zym");
1600 //precache_model("models/player/lycanthrope.zym");
1601 //precache_model("models/player/marine.zym");
1602 //precache_model("models/player/nexus.zym");
1603 //precache_model("models/player/pyria.zym");
1604 //precache_model("models/player/shock.zym");
1605 //precache_model("models/player/skadi.zym");
1606 //precache_model("models/player/specop.zym");
1607 //precache_model("models/player/visitant.zym");
1610 if (cvar("sv_defaultcharacter"))
1613 s = cvar_string("sv_defaultplayermodel_red");
1617 PrecachePlayerSounds(strcat(s, ".sounds"));
1619 s = cvar_string("sv_defaultplayermodel_blue");
1623 PrecachePlayerSounds(strcat(s, ".sounds"));
1625 s = cvar_string("sv_defaultplayermodel_yellow");
1629 PrecachePlayerSounds(strcat(s, ".sounds"));
1631 s = cvar_string("sv_defaultplayermodel_pink");
1635 PrecachePlayerSounds(strcat(s, ".sounds"));
1637 s = cvar_string("sv_defaultplayermodel");
1641 PrecachePlayerSounds(strcat(s, ".sounds"));
1647 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1648 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1651 // gore and miscellaneous sounds
1652 //precache_sound ("misc/h2ohit.wav");
1653 precache_model ("models/hook.md3");
1654 precache_sound ("misc/armorimpact.wav");
1655 precache_sound ("misc/bodyimpact1.wav");
1656 precache_sound ("misc/bodyimpact2.wav");
1657 precache_sound ("misc/gib.wav");
1658 precache_sound ("misc/gib_splat01.wav");
1659 precache_sound ("misc/gib_splat02.wav");
1660 precache_sound ("misc/gib_splat03.wav");
1661 precache_sound ("misc/gib_splat04.wav");
1662 precache_sound ("misc/hit.wav");
1663 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1664 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1665 precache_sound ("misc/null.wav");
1666 precache_sound ("misc/spawn.wav");
1667 precache_sound ("misc/talk.wav");
1668 precache_sound ("misc/teleport.wav");
1669 precache_sound ("misc/poweroff.wav");
1670 precache_sound ("player/lava.wav");
1671 precache_sound ("player/slime.wav");
1674 precache_sound ("misc/jetpack_fly.wav");
1676 // announcer sounds - male
1677 precache_sound ("announcer/male/electrobitch.wav");
1678 precache_sound ("announcer/male/airshot.wav");
1679 precache_sound ("announcer/male/03kills.wav");
1680 precache_sound ("announcer/male/05kills.wav");
1681 precache_sound ("announcer/male/10kills.wav");
1682 precache_sound ("announcer/male/15kills.wav");
1683 precache_sound ("announcer/male/20kills.wav");
1684 precache_sound ("announcer/male/25kills.wav");
1685 precache_sound ("announcer/male/30kills.wav");
1686 precache_sound ("announcer/male/botlike.wav");
1687 precache_sound ("announcer/male/yoda.wav");
1688 precache_sound ("announcer/male/amazing.wav");
1689 precache_sound ("announcer/male/awesome.wav");
1690 precache_sound ("announcer/male/headshot.wav");
1691 precache_sound ("announcer/male/impressive.wav");
1693 // announcer sounds - robotic
1694 precache_sound ("announcer/robotic/prepareforbattle.wav");
1695 precache_sound ("announcer/robotic/begin.wav");
1696 precache_sound ("announcer/robotic/timeoutcalled.wav");
1697 precache_sound ("announcer/robotic/1fragleft.wav");
1698 precache_sound ("announcer/robotic/2fragsleft.wav");
1699 precache_sound ("announcer/robotic/3fragsleft.wav");
1700 precache_sound ("announcer/robotic/terminated.wav");
1703 precache_sound ("announcer/robotic/lastsecond.wav");
1704 precache_sound ("announcer/robotic/narrowly.wav");
1707 precache_model ("models/sprites/0.spr32");
1708 precache_model ("models/sprites/1.spr32");
1709 precache_model ("models/sprites/2.spr32");
1710 precache_model ("models/sprites/3.spr32");
1711 precache_model ("models/sprites/4.spr32");
1712 precache_model ("models/sprites/5.spr32");
1713 precache_model ("models/sprites/6.spr32");
1714 precache_model ("models/sprites/7.spr32");
1715 precache_model ("models/sprites/8.spr32");
1716 precache_model ("models/sprites/9.spr32");
1717 precache_model ("models/sprites/10.spr32");
1718 precache_sound ("announcer/robotic/1.wav");
1719 precache_sound ("announcer/robotic/2.wav");
1720 precache_sound ("announcer/robotic/3.wav");
1721 precache_sound ("announcer/robotic/4.wav");
1722 precache_sound ("announcer/robotic/5.wav");
1723 precache_sound ("announcer/robotic/6.wav");
1724 precache_sound ("announcer/robotic/7.wav");
1725 precache_sound ("announcer/robotic/8.wav");
1726 precache_sound ("announcer/robotic/9.wav");
1727 precache_sound ("announcer/robotic/10.wav");
1729 // common weapon precaches
1730 precache_sound ("weapons/weapon_switch.wav");
1731 precache_sound ("weapons/weaponpickup.wav");
1732 precache_sound ("weapons/unavailable.wav");
1733 if (g_grappling_hook)
1735 precache_sound ("weapons/hook_fire.wav"); // hook
1736 precache_sound ("weapons/hook_impact.wav"); // hook
1739 if (cvar("sv_precacheweapons") || g_nixnex)
1741 //precache weapon models/sounds
1744 while (wep <= WEP_LAST)
1746 weapon_action(wep, WR_PRECACHE);
1751 precache_model("models/elaser.mdl");
1752 precache_model("models/laser.mdl");
1753 precache_model("models/ebomb.mdl");
1756 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1758 if (!self.noise && self.music) // quake 3 uses the music field
1759 self.noise = self.music;
1761 // plays music for the level if there is any
1764 precache_sound (self.noise);
1765 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1770 // sorry, but using \ in macros breaks line numbers
1771 #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
1772 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1773 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1775 vector ExactTriggerHit_mins;
1776 vector ExactTriggerHit_maxs;
1777 float ExactTriggerHit_Recurse()
1783 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1786 if (trace_ent == self)
1791 se.solid = SOLID_NOT;
1792 f = ExactTriggerHit_Recurse();
1798 float ExactTriggerHit()
1802 if not(self.modelindex)
1806 self.solid = SOLID_BSP;
1807 ExactTriggerHit_mins = other.absmin;
1808 ExactTriggerHit_maxs = other.absmax;
1809 f = ExactTriggerHit_Recurse();
1815 // WARNING: this kills the trace globals
1816 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1817 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1819 #define INITPRIO_FIRST 0
1820 #define INITPRIO_GAMETYPE 0
1821 #define INITPRIO_GAMETYPE_FALLBACK 1
1822 #define INITPRIO_CVARS 5
1823 #define INITPRIO_FINDTARGET 10
1824 #define INITPRIO_DROPTOFLOOR 20
1825 #define INITPRIO_SETLOCATION 90
1826 #define INITPRIO_LINKDOORS 91
1827 #define INITPRIO_LAST 99
1829 .void(void) initialize_entity;
1830 .float initialize_entity_order;
1831 .entity initialize_entity_next;
1832 entity initialize_entity_first;
1834 void make_safe_for_remove(entity e)
1836 if (e.initialize_entity)
1839 for (ent = initialize_entity_first; ent; )
1841 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1843 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1844 // skip it in linked list
1847 prev.initialize_entity_next = ent.initialize_entity_next;
1848 ent = prev.initialize_entity_next;
1852 initialize_entity_first = ent.initialize_entity_next;
1853 ent = initialize_entity_first;
1859 ent = ent.initialize_entity_next;
1865 void objerror(string s)
1867 make_safe_for_remove(self);
1868 objerror_builtin(s);
1871 void remove_unsafely(entity e)
1876 void remove_safely(entity e)
1878 make_safe_for_remove(e);
1882 void InitializeEntity(entity e, void(void) func, float order)
1886 if (!e || e.initialize_entity)
1888 // make a proxy initializer entity
1892 e.classname = "initialize_entity";
1896 e.initialize_entity = func;
1897 e.initialize_entity_order = order;
1899 cur = initialize_entity_first;
1902 if (!cur || cur.initialize_entity_order > order)
1904 // insert between prev and cur
1906 prev.initialize_entity_next = e;
1908 initialize_entity_first = e;
1909 e.initialize_entity_next = cur;
1913 cur = cur.initialize_entity_next;
1916 void InitializeEntitiesRun()
1919 startoflist = initialize_entity_first;
1920 initialize_entity_first = world;
1921 for (self = startoflist; self; )
1924 var void(void) func;
1925 e = self.initialize_entity_next;
1926 func = self.initialize_entity;
1927 self.initialize_entity_order = 0;
1928 self.initialize_entity = func_null;
1929 self.initialize_entity_next = world;
1930 if (self.classname == "initialize_entity")
1934 remove_builtin(self);
1937 //dprint("Delayed initialization: ", self.classname, "\n");
1943 .float uncustomizeentityforclient_set;
1944 .void(void) uncustomizeentityforclient;
1945 void(void) SUB_Nullpointer = #0;
1946 void UncustomizeEntitiesRun()
1950 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1951 self.uncustomizeentityforclient();
1954 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1956 e.customizeentityforclient = customizer;
1957 e.uncustomizeentityforclient = uncustomizer;
1958 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1962 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1965 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1969 if (e.classname == "")
1970 e.classname = "net_linked";
1972 if (e.model == "" || self.modelindex == 0)
1976 setmodel(e, "null");
1980 e.SendEntity = sendfunc;
1981 e.SendFlags = 0xFFFFFF;
1984 e.effects |= EF_NODEPTHTEST;
1988 e.nextthink = time + dt;
1989 e.think = SUB_Remove;
1993 void adaptor_think2touch()
2002 void adaptor_think2use()
2014 // deferred dropping
2015 void DropToFloor_Handler()
2017 droptofloor_builtin();
2018 self.dropped_origin = self.origin;
2023 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
2028 float trace_hits_box_a0, trace_hits_box_a1;
2030 float trace_hits_box_1d(float end, float thmi, float thma)
2034 // just check if x is in range
2042 // do the trace with respect to x
2043 // 0 -> end has to stay in thmi -> thma
2044 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
2045 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
2046 if (trace_hits_box_a0 > trace_hits_box_a1)
2052 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
2057 // now it is a trace from 0 to end
2059 trace_hits_box_a0 = 0;
2060 trace_hits_box_a1 = 1;
2062 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
2064 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
2066 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
2072 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
2074 return trace_hits_box(start, end, thmi - ma, thma - mi);
2077 float SUB_NoImpactCheck()
2079 // zero hitcontents = this is not the real impact, but either the
2080 // mirror-impact of something hitting the projectile instead of the
2081 // projectile hitting the something, or a touchareagrid one. Neither of
2082 // these stop the projectile from moving, so...
2083 if(trace_dphitcontents == 0)
2085 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
2088 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2090 if (other == world && self.size != '0 0 0')
2093 tic = self.velocity * sys_ticrate;
2094 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
2095 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
2096 if (trace_fraction >= 1)
2098 dprint("Odd... did not hit...?\n");
2100 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2102 dprint("Detected and prevented the sky-grapple bug.\n");
2110 #define SUB_OwnerCheck() (other && (other == self.owner))
2112 #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)
2114 float MAX_IPBAN_URIS = 16;
2116 float URI_GET_DISCARD = 0;
2117 float URI_GET_IPBAN = 1;
2118 float URI_GET_IPBAN_END = 16;
2120 void URI_Get_Callback(float id, float status, string data)
2122 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2124 dprint("\nEnd of data.\n");
2126 if (id == URI_GET_DISCARD)
2130 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2133 OnlineBanList_URI_Get_Callback(id, status, data);
2137 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2141 void print_to(entity e, string s)
2144 sprint(e, strcat(s, "\n"));
2163 for (i = 0; i < MapInfo_count; ++i)
2165 if (MapInfo_Get_ByID(i))
2167 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2170 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2171 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\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, RACE_RECORD, "time")));
2186 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2187 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", 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, CTS_RECORD, "time")));
2202 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2203 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2209 MapInfo_ClearTemps();
2212 return "No records are available on this server.\n";
2214 return strcat("Records on this server:\n", s);
2217 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2220 vector start, org, delta, end, enddown, mstart;
2222 m = e.dphitcontentsmask;
2223 e.dphitcontentsmask = goodcontents | badcontents;
2226 delta = world.maxs - world.mins;
2228 for (i = 0; i < attempts; ++i)
2230 start_x = org_x + random() * delta_x;
2231 start_y = org_y + random() * delta_y;
2232 start_z = org_z + random() * delta_z;
2234 // rule 1: start inside world bounds, and outside
2235 // solid, and don't start from somewhere where you can
2236 // fall down to evil
2237 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2238 if (trace_fraction >= 1)
2240 if (trace_startsolid)
2242 if (trace_dphitcontents & badcontents)
2244 if (trace_dphitq3surfaceflags & badsurfaceflags)
2247 // rule 2: if we are too high, lower the point
2248 if (trace_fraction * delta_z > maxaboveground)
2249 start = trace_endpos + '0 0 1' * maxaboveground;
2250 enddown = trace_endpos;
2252 // rule 3: make sure we aren't outside the map. This only works
2253 // for somewhat well formed maps. A good rule of thumb is that
2254 // the map should have a convex outside hull.
2255 // these can be traceLINES as we already verified the starting box
2256 mstart = start + 0.5 * (e.mins + e.maxs);
2257 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2258 if (trace_fraction >= 1)
2260 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2261 if (trace_fraction >= 1)
2263 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2264 if (trace_fraction >= 1)
2266 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2267 if (trace_fraction >= 1)
2269 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2270 if (trace_fraction >= 1)
2273 // find a random vector to "look at"
2274 end_x = org_x + random() * delta_x;
2275 end_y = org_y + random() * delta_y;
2276 end_z = org_z + random() * delta_z;
2277 end = start + normalize(end - start) * vlen(delta);
2279 // rule 4: start TO end must not be too short
2280 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2281 if (trace_startsolid)
2283 if (trace_fraction < minviewdistance / vlen(delta))
2286 // rule 5: don't want to look at sky
2287 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2290 // rule 6: we must not end up in trigger_hurt
2291 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2293 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2300 e.dphitcontentsmask = m;
2304 setorigin(e, start);
2305 e.angles = vectoangles(end - start);
2306 dprint("Needed ", ftos(i + 1), " attempts\n");
2313 float zcurveparticles_effectno;
2314 vector zcurveparticles_start;
2315 float zcurveparticles_spd;
2317 void endzcurveparticles()
2319 if(zcurveparticles_effectno)
2322 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2324 zcurveparticles_effectno = 0;
2327 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2329 spd = bound(0, floor(spd / 16), 32767);
2330 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2332 endzcurveparticles();
2333 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2334 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2335 WriteShort(MSG_BROADCAST, effectno);
2336 WriteCoord(MSG_BROADCAST, start_x);
2337 WriteCoord(MSG_BROADCAST, start_y);
2338 WriteCoord(MSG_BROADCAST, start_z);
2339 zcurveparticles_effectno = effectno;
2340 zcurveparticles_start = start;
2343 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2344 WriteCoord(MSG_BROADCAST, end_x);
2345 WriteCoord(MSG_BROADCAST, end_y);
2346 WriteCoord(MSG_BROADCAST, end_z);
2347 WriteCoord(MSG_BROADCAST, end_dz);
2348 zcurveparticles_spd = spd;
2351 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2354 vector vecxy, velxy;
2356 vecxy = end - start;
2361 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2363 endzcurveparticles();
2364 trailparticles(world, effectno, start, end);
2368 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2369 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2372 string GetGametype(); // g_world.qc
2373 void write_recordmarker(entity pl, float tstart, float dt)
2375 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2377 // also write a marker into demo files for demotc-race-record-extractor to find
2380 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2381 " ", ftos(tstart), " ", ftos(dt), "\n"));
2384 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2386 switch(self.owner.cvar_cl_gunalign)
2397 if(allowcenter) // 2: allow center handedness
2410 if(allowcenter) // 2: allow center handedness
2426 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2431 if (cvar("g_shootfromeye"))
2435 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2443 else if (cvar("g_shootfromcenter"))
2447 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2455 else if (cvar("g_shootfromclient"))
2457 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2459 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2474 void attach_sameorigin(entity e, entity to, string tag)
2476 vector org, t_forward, t_left, t_up, e_forward, e_up;
2483 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2484 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2485 t_forward = v_forward * tagscale;
2486 t_left = v_right * -tagscale;
2487 t_up = v_up * tagscale;
2489 e.origin_x = org * t_forward;
2490 e.origin_y = org * t_left;
2491 e.origin_z = org * t_up;
2493 // current forward and up directions
2494 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2495 e.angles_x = -e.angles_x;
2496 fixedmakevectors(e.angles);
2498 // untransform forward, up!
2499 e_forward_x = v_forward * t_forward;
2500 e_forward_y = v_forward * t_left;
2501 e_forward_z = v_forward * t_up;
2502 e_up_x = v_up * t_forward;
2503 e_up_y = v_up * t_left;
2504 e_up_z = v_up * t_up;
2506 e.angles = fixedvectoangles2(e_forward, e_up);
2507 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2508 e.angles_x = -e.angles_x;
2510 setattachment(e, to, tag);
2511 setorigin(e, e.origin);
2514 void detach_sameorigin(entity e)
2517 org = gettaginfo(e, 0);
2518 e.angles = fixedvectoangles2(v_forward, v_up);
2519 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2520 e.angles_x = -e.angles_x;
2522 setattachment(e, world, "");
2523 setorigin(e, e.origin);
2526 void follow_sameorigin(entity e, entity to)
2528 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2529 e.aiment = to; // make the hole follow bmodel
2530 e.punchangle = to.angles; // the original angles of bmodel
2531 e.view_ofs = e.origin - to.origin; // relative origin
2532 e.v_angle = e.angles - to.angles; // relative angles
2535 void unfollow_sameorigin(entity e)
2537 e.movetype = MOVETYPE_NONE;
2540 entity gettaginfo_relative_ent;
2541 vector gettaginfo_relative(entity e, float tag)
2543 if (!gettaginfo_relative_ent)
2545 gettaginfo_relative_ent = spawn();
2546 gettaginfo_relative_ent.effects = EF_NODRAW;
2548 gettaginfo_relative_ent.model = e.model;
2549 gettaginfo_relative_ent.modelindex = e.modelindex;
2550 gettaginfo_relative_ent.frame = e.frame;
2551 return gettaginfo(gettaginfo_relative_ent, tag);
2554 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2558 if (pl.soundentity.cnt & p)
2560 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2561 pl.soundentity.cnt |= p;
2564 void SoundEntity_StopSound(entity pl, float chan)
2568 if (pl.soundentity.cnt & p)
2570 stopsoundto(MSG_ALL, pl.soundentity, chan);
2571 pl.soundentity.cnt &~= p;
2575 void SoundEntity_Attach(entity pl)
2577 pl.soundentity = spawn();
2578 pl.soundentity.classname = "soundentity";
2579 pl.soundentity.owner = pl;
2580 setattachment(pl.soundentity, pl, "");
2581 setmodel(pl.soundentity, "null");
2584 void SoundEntity_Detach(entity pl)
2587 for (i = 0; i <= 7; ++i)
2588 SoundEntity_StopSound(pl, i);
2592 float ParseCommandPlayerSlotTarget_firsttoken;
2593 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2601 ParseCommandPlayerSlotTarget_firsttoken = -1;
2605 if (substring(argv(idx), 0, 1) == "#")
2607 s = substring(argv(idx), 1, -1);
2615 ParseCommandPlayerSlotTarget_firsttoken = idx;
2616 if (s == ftos(stof(s)))
2618 e = edict_num(stof(s));
2619 if (e.flags & FL_CLIENT)
2625 // it must be a nick name
2628 ParseCommandPlayerSlotTarget_firsttoken = idx;
2631 FOR_EACH_CLIENT(head)
2632 if (head.netname == s)
2640 s = strdecolorize(s);
2642 FOR_EACH_CLIENT(head)
2643 if (strdecolorize(head.netname) == s)
2658 float modeleffect_SendEntity(entity to, float sf)
2661 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2664 if(self.velocity != '0 0 0')
2666 if(self.angles != '0 0 0')
2668 if(self.avelocity != '0 0 0')
2671 WriteByte(MSG_ENTITY, f);
2672 WriteShort(MSG_ENTITY, self.modelindex);
2673 WriteByte(MSG_ENTITY, self.skin);
2674 WriteByte(MSG_ENTITY, self.frame);
2675 WriteCoord(MSG_ENTITY, self.origin_x);
2676 WriteCoord(MSG_ENTITY, self.origin_y);
2677 WriteCoord(MSG_ENTITY, self.origin_z);
2680 WriteCoord(MSG_ENTITY, self.velocity_x);
2681 WriteCoord(MSG_ENTITY, self.velocity_y);
2682 WriteCoord(MSG_ENTITY, self.velocity_z);
2686 WriteCoord(MSG_ENTITY, self.angles_x);
2687 WriteCoord(MSG_ENTITY, self.angles_y);
2688 WriteCoord(MSG_ENTITY, self.angles_z);
2692 WriteCoord(MSG_ENTITY, self.avelocity_x);
2693 WriteCoord(MSG_ENTITY, self.avelocity_y);
2694 WriteCoord(MSG_ENTITY, self.avelocity_z);
2696 WriteShort(MSG_ENTITY, self.scale * 256.0);
2697 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2698 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2699 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2700 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2705 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)
2710 e.classname = "modeleffect";
2718 e.teleport_time = t1;
2722 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2726 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2729 sz = max(e.scale, e.scale2);
2730 setsize(e, e.mins * sz, e.maxs * sz);
2731 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2734 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2736 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2739 float randombit(float bits)
2741 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2750 for(f = 1; f <= bits; f *= 2)
2759 r = (r - 1) / (n - 1);
2766 float randombits(float bits, float k, float error_return)
2770 while(k > 0 && bits != r)
2772 r += randombit(bits - r);
2781 void randombit_test(float bits, float iter)
2785 print(ftos(randombit(bits)), "\n");
2790 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2792 if(halflifedist > 0)
2793 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2794 else if(halflifedist < 0)
2795 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2804 #define cvar_string_normal cvar_string_builtin
2805 #define cvar_normal cvar_builtin
2807 string cvar_string_normal(string n)
2809 if not(cvar_type(n) & 1)
2810 error(strcat("Attempt to access undefined cvar: ", n));
2811 return cvar_string_builtin(n);
2814 float cvar_normal(string n)
2816 return stof(cvar_string_normal(n));
2819 #define cvar_set_normal cvar_set_builtin