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 float race_GetTime(float pos);
9 string race_GetName(float pos);
10 string race_PlaceName(float pos);
12 string ColoredTeamName(float t);
14 string admin_name(void)
16 if(cvar_string("sv_adminnick") != "")
17 return cvar_string("sv_adminnick");
19 return "SERVER ADMIN";
22 float DistributeEvenly_amount;
23 float DistributeEvenly_totalweight;
24 void DistributeEvenly_Init(float amount, float totalweight)
26 if (DistributeEvenly_amount)
28 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
29 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
32 DistributeEvenly_amount = 0;
34 DistributeEvenly_amount = amount;
35 DistributeEvenly_totalweight = totalweight;
37 float DistributeEvenly_Get(float weight)
42 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
43 DistributeEvenly_totalweight -= weight;
44 DistributeEvenly_amount -= f;
48 void move_out_of_solid_expand(entity e, vector by)
51 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
54 if (trace_fraction < 1)
57 // adjust origin in the other direction...
58 setorigin(e,e.origin - by * (1 - trace_fraction));
62 float move_out_of_solid(entity e)
67 traceline(o, o, MOVE_WORLDONLY, e);
71 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
72 if (!trace_startsolid)
79 move_out_of_solid_expand(e, '1 0 0' * m0_x);
81 move_out_of_solid_expand(e, '1 0 0' * m1_x);
83 move_out_of_solid_expand(e, '0 1 0' * m0_y);
85 move_out_of_solid_expand(e, '0 1 0' * m1_y);
87 move_out_of_solid_expand(e, '0 0 1' * m0_z);
89 move_out_of_solid_expand(e, '0 0 1' * m1_z);
91 setorigin(e, e.origin);
93 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
103 string STR_PLAYER = "player";
104 string STR_SPECTATOR = "spectator";
105 string STR_OBSERVER = "observer";
108 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
109 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
110 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
111 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
113 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
114 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
115 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
116 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
117 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
120 // copies a string to a tempstring (so one can strunzone it)
121 string strcat1(string s) = #115; // FRIK_FILE
126 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
128 local float nPlayerHealth = rint(enPlayer.health);
129 local float nPlayerArmor = rint(enPlayer.armorvalue);
130 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
131 local float nPlayerPing = rint(enPlayer.ping);
132 local string strPlayerPingColor;
133 local string strMessage;
134 if(nPlayerPing >= 150)
135 strPlayerPingColor = "^1";
137 strPlayerPingColor = "^2";
139 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
140 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
142 if(cvar("sv_fragmessage_information_ping")) {
143 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
144 strMessage = strcat(strMessage, "\n^7(^2Bot");
146 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
147 if(cvar("sv_fragmessage_information_handicap"))
148 if(cvar("sv_fragmessage_information_handicap") == 2)
149 if(nPlayerHandicap <= 1)
150 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
152 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
153 else if not(nPlayerHandicap <= 1)
154 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
156 strMessage = strcat(strMessage, "^7)");
157 } else if(cvar("sv_fragmessage_information_handicap")) {
158 if(cvar("sv_fragmessage_information_handicap") == 2)
159 if(nPlayerHandicap <= 1)
160 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
162 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
163 else if(nPlayerHandicap > 1)
164 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
168 void bcenterprint(string s)
170 // TODO replace by MSG_ALL (would show it to spectators too, though)?
172 FOR_EACH_PLAYER(head)
173 if (clienttype(head) == CLIENTTYPE_REAL)
174 centerprint(head, s);
177 void GameLogEcho(string s)
182 if (cvar("sv_eventlog_files"))
187 matches = cvar("sv_eventlog_files_counter") + 1;
188 cvar_set("sv_eventlog_files_counter", ftos(matches));
191 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
192 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
193 logfile = fopen(fn, FILE_APPEND);
194 fputs(logfile, ":logversion:3\n");
198 if (cvar("sv_eventlog_files_timestamps"))
199 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
201 fputs(logfile, strcat(s, "\n"));
204 if (cvar("sv_eventlog_console"))
213 // will be opened later
218 if (logfile_open && logfile >= 0)
228 vector PL_CROUCH_VIEW_OFS;
229 vector PL_CROUCH_MIN;
230 vector PL_CROUCH_MAX;
232 float spawnpoint_nag;
233 void relocate_spawnpoint()
235 PL_VIEW_OFS = stov(cvar_string("sv_player_viewoffset"));
236 PL_MIN = stov(cvar_string("sv_player_mins"));
237 PL_MAX = stov(cvar_string("sv_player_maxs"));
238 PL_CROUCH_VIEW_OFS = stov(cvar_string("sv_player_crouch_viewoffset"));
239 PL_CROUCH_MIN = stov(cvar_string("sv_player_crouch_mins"));
240 PL_CROUCH_MAX = stov(cvar_string("sv_player_crouch_maxs"));
242 // nudge off the floor
243 setorigin(self, self.origin + '0 0 1');
245 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
246 if (trace_startsolid)
252 if (!move_out_of_solid(self))
253 objerror("could not get out of solid at all!");
254 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
255 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
256 print(" ", ftos(self.origin_y - o_y));
257 print(" ", ftos(self.origin_z - o_z), "'\n");
258 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
261 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
267 self.mins = self.maxs = '0 0 0';
268 objerror("player spawn point in solid, mapper sucks!\n");
273 if (cvar("g_spawnpoints_autodrop"))
275 setsize(self, PL_MIN, PL_MAX);
279 self.use = spawnpoint_use;
280 self.team_saved = self.team;
284 if (have_team_spawns != 0)
286 have_team_spawns = 1;
288 if (cvar("r_showbboxes"))
290 // show where spawnpoints point at too
291 makevectors(self.angles);
294 e.classname = "info_player_foo";
295 setorigin(e, self.origin + v_forward * 24);
296 setsize(e, '-8 -8 -8', '8 8 8');
297 e.solid = SOLID_TRIGGER;
301 #define strstr strstrofs
303 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
304 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
305 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
306 // BE CONSTANT OR strzoneD!
307 float strstr(string haystack, string needle, float offset)
311 len = strlen(needle);
312 endpos = strlen(haystack) - len;
313 while(offset <= endpos)
315 found = substring(haystack, offset, len);
324 float NUM_NEAREST_ENTITIES = 4;
325 entity nearest_entity[NUM_NEAREST_ENTITIES];
326 float nearest_length[NUM_NEAREST_ENTITIES];
327 entity findnearest(vector point, .string field, string value, vector axismod)
338 localhead = find(world, field, value);
341 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
342 dist = localhead.oldorigin;
344 dist = localhead.origin;
346 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
349 for (i = 0; i < num_nearest; ++i)
351 if (len < nearest_length[i])
355 // now i tells us where to insert at
356 // INSERTION SORT! YOU'VE SEEN IT! RUN!
357 if (i < NUM_NEAREST_ENTITIES)
359 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
361 nearest_length[j + 1] = nearest_length[j];
362 nearest_entity[j + 1] = nearest_entity[j];
364 nearest_length[i] = len;
365 nearest_entity[i] = localhead;
366 if (num_nearest < NUM_NEAREST_ENTITIES)
367 num_nearest = num_nearest + 1;
370 localhead = find(localhead, field, value);
373 // now use the first one from our list that we can see
374 for (i = 0; i < num_nearest; ++i)
376 traceline(point, nearest_entity[i].origin, TRUE, world);
377 if (trace_fraction == 1)
381 dprint("Nearest point (");
382 dprint(nearest_entity[0].netname);
383 dprint(") is not visible, using a visible one.\n");
385 return nearest_entity[i];
389 if (num_nearest == 0)
392 dprint("Not seeing any location point, using nearest as fallback.\n");
394 dprint("Candidates were: ");
395 for(j = 0; j < num_nearest; ++j)
399 dprint(nearest_entity[j].netname);
404 return nearest_entity[0];
407 void spawnfunc_target_location()
409 self.classname = "target_location";
410 // location name in netname
411 // eventually support: count, teamgame selectors, line of sight?
414 void spawnfunc_info_location()
416 self.classname = "target_location";
417 self.message = self.netname;
420 string NearestLocation(vector p)
425 loc = findnearest(p, classname, "target_location", '1 1 1');
432 loc = findnearest(p, target, "###item###", '1 1 4');
439 string formatmessage(string msg)
450 break; // too many replacements
453 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
454 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
467 replacement = substring(msg, p, 2);
468 escape = substring(msg, p + 1, 1);
472 else if (escape == "\\")
474 else if (escape == "n")
476 else if (escape == "a")
477 replacement = ftos(floor(self.armorvalue));
478 else if (escape == "h")
479 replacement = ftos(floor(self.health));
480 else if (escape == "l")
481 replacement = NearestLocation(self.origin);
482 else if (escape == "y")
483 replacement = NearestLocation(self.cursor_trace_endpos);
484 else if (escape == "d")
485 replacement = NearestLocation(self.death_origin);
486 else if (escape == "w") {
490 wep = self.switchweapon;
493 replacement = W_Name(wep);
494 } else if (escape == "W") {
495 if (self.items & IT_SHELLS) replacement = "shells";
496 else if (self.items & IT_NAILS) replacement = "bullets";
497 else if (self.items & IT_ROCKETS) replacement = "rockets";
498 else if (self.items & IT_CELLS) replacement = "cells";
499 else replacement = "batteries"; // ;)
500 } else if (escape == "x") {
501 replacement = self.cursor_trace_ent.netname;
502 if (!replacement || !self.cursor_trace_ent)
503 replacement = "nothing";
504 } else if (escape == "p") {
505 if (self.last_selected_player)
506 replacement = self.last_selected_player.netname;
508 replacement = "(nobody)";
509 } else if (escape == "s")
510 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
511 else if (escape == "S")
512 replacement = ftos(vlen(self.velocity));
513 else if (escape == "v") {
517 if(self.classname == "spectator")
522 weapon_number = stats.weapon;
525 weapon_number = stats.switchweapon;
528 weapon_number = stats.cnt;
530 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
531 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
533 replacement = "~"; // or something to indicate NULL, not available
536 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
537 p = p + strlen(replacement);
542 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
543 return (value == 0) ? FALSE : TRUE;
552 >0: receives a cvar from name=argv(f) value=argv(f+1)
554 void GetCvars_handleString(string thisname, float f, .string field, string name)
559 strunzone(self.field);
560 self.field = string_null;
564 if (thisname == name)
567 strunzone(self.field);
568 self.field = strzone(argv(f + 1));
572 stuffcmd(self, strcat("sendcvar ", name, "\n"));
574 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
576 GetCvars_handleString(thisname, f, field, name);
577 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
578 if (thisname == name)
581 s = func(strcat1(self.field));
584 strunzone(self.field);
585 self.field = strzone(s);
589 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
596 if (thisname == name)
597 self.field = stof(argv(f + 1));
600 stuffcmd(self, strcat("sendcvar ", name, "\n"));
602 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
609 if (thisname == name)
613 self.field = stof(argv(f + 1));
622 stuffcmd(self, strcat("sendcvar ", name, "\n"));
625 string W_FixWeaponOrder_ForceComplete(string s);
626 string W_FixWeaponOrder_AllowIncomplete(string s);
627 float w_getbestweapon(entity e);
628 void GetCvars(float f)
632 s = strcat1(argv(f));
633 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
634 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
635 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
636 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
637 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
638 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
639 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
640 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
641 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
642 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
643 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
644 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
645 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
646 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
647 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
648 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
649 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
650 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
651 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
652 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
653 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
654 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
655 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
656 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
658 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
659 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
661 #ifdef ALLOW_FORCEMODELS
662 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
663 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
665 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
667 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
670 if (s == "cl_weaponpriority")
671 self.switchweapon = w_getbestweapon(self);
675 float fexists(string f)
678 fh = fopen(f, FILE_READ);
685 void backtrace(string msg)
688 dev = cvar("developer");
689 war = cvar("prvm_backtraceforwarnings");
690 cvar_set("developer", "1");
691 cvar_set("prvm_backtraceforwarnings", "1");
693 print("--- CUT HERE ---\nWARNING: ");
696 remove(world); // isn't there any better way to cause a backtrace?
697 print("\n--- CUT UNTIL HERE ---\n");
698 cvar_set("developer", ftos(dev));
699 cvar_set("prvm_backtraceforwarnings", ftos(war));
702 string Team_ColorCode(float teamid)
704 if (teamid == COLOR_TEAM1)
706 else if (teamid == COLOR_TEAM2)
708 else if (teamid == COLOR_TEAM3)
710 else if (teamid == COLOR_TEAM4)
716 string Team_ColorName(float t)
718 // fixme: Search for team entities and get their .netname's!
719 if (t == COLOR_TEAM1)
721 if (t == COLOR_TEAM2)
723 if (t == COLOR_TEAM3)
725 if (t == COLOR_TEAM4)
730 string Team_ColorNameLowerCase(float t)
732 // fixme: Search for team entities and get their .netname's!
733 if (t == COLOR_TEAM1)
735 if (t == COLOR_TEAM2)
737 if (t == COLOR_TEAM3)
739 if (t == COLOR_TEAM4)
744 float ColourToNumber(string team_colour)
746 if (team_colour == "red")
749 if (team_colour == "blue")
752 if (team_colour == "yellow")
755 if (team_colour == "pink")
758 if (team_colour == "auto")
764 float NumberToTeamNumber(float number)
781 #define CENTERPRIO_POINT 1
782 #define CENTERPRIO_SPAM 2
783 #define CENTERPRIO_VOTE 4
784 #define CENTERPRIO_NORMAL 5
785 #define CENTERPRIO_SHIELDING 7
786 #define CENTERPRIO_MAPVOTE 9
787 #define CENTERPRIO_IDLEKICK 50
788 #define CENTERPRIO_ADMIN 99
789 .float centerprint_priority;
790 .float centerprint_expires;
791 void centerprint_atprio(entity e, float prio, string s)
793 if (intermission_running)
794 if (prio < CENTERPRIO_MAPVOTE)
796 if (time > e.centerprint_expires)
797 e.centerprint_priority = 0;
798 if (prio >= e.centerprint_priority)
800 e.centerprint_priority = prio;
801 if (timeoutStatus == 2)
802 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
804 e.centerprint_expires = time + e.cvar_scr_centertime;
805 centerprint_builtin(e, s);
808 void centerprint_expire(entity e, float prio)
810 if (prio == e.centerprint_priority)
812 e.centerprint_priority = 0;
813 centerprint_builtin(e, "");
816 void centerprint(entity e, string s)
818 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
821 // decolorizes and team colors the player name when needed
822 string playername(entity p)
825 if (teams_matter && !intermission_running && p.classname == "player")
827 t = Team_ColorCode(p.team);
828 return strcat(t, strdecolorize(p.netname));
834 vector randompos(vector m1, vector m2)
838 v_x = m2_x * random() + m1_x;
839 v_y = m2_y * random() + m1_y;
840 v_z = m2_z * random() + m1_z;
844 float g_pickup_shells;
845 float g_pickup_shells_max;
846 float g_pickup_nails;
847 float g_pickup_nails_max;
848 float g_pickup_rockets;
849 float g_pickup_rockets_max;
850 float g_pickup_cells;
851 float g_pickup_cells_max;
853 float g_pickup_fuel_jetpack;
854 float g_pickup_fuel_max;
855 float g_pickup_armorsmall;
856 float g_pickup_armorsmall_max;
857 float g_pickup_armormedium;
858 float g_pickup_armormedium_max;
859 float g_pickup_armorbig;
860 float g_pickup_armorbig_max;
861 float g_pickup_armorlarge;
862 float g_pickup_armorlarge_max;
863 float g_pickup_healthsmall;
864 float g_pickup_healthsmall_max;
865 float g_pickup_healthmedium;
866 float g_pickup_healthmedium_max;
867 float g_pickup_healthlarge;
868 float g_pickup_healthlarge_max;
869 float g_pickup_healthmega;
870 float g_pickup_healthmega_max;
872 float g_weaponarena_random;
873 string g_weaponarena_list;
874 float g_weaponspeedfactor;
875 float g_weaponratefactor;
876 float g_weapondamagefactor;
877 float g_weaponforcefactor;
878 float g_weaponspreadfactor;
882 float start_ammo_shells;
883 float start_ammo_nails;
884 float start_ammo_rockets;
885 float start_ammo_cells;
886 float start_ammo_fuel;
888 float start_armorvalue;
889 float warmup_start_weapons;
890 float warmup_start_ammo_shells;
891 float warmup_start_ammo_nails;
892 float warmup_start_ammo_rockets;
893 float warmup_start_ammo_cells;
894 float warmup_start_ammo_fuel;
895 float warmup_start_health;
896 float warmup_start_armorvalue;
900 entity get_weaponinfo(float w);
902 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
904 var float i = weaponinfo.weapon;
909 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
911 if (t < 0) // "default" weapon selection
913 if (g_lms || g_ca || allguns)
914 t = (weaponinfo.spawnflags & WEP_FLAG_NORMAL);
917 else if (g_race || g_cts)
918 t = (i == WEP_LASER);
920 t = 0; // weapon is set a few lines later
922 t = (i == WEP_LASER || i == WEP_SHOTGUN);
923 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
924 t |= (i == WEP_HOOK);
927 // we cannot disable porto in Nexball, we must force it
928 if(g_nexball && i == WEP_PORTO)
934 float NixNex_CanChooseWeapon(float wpn);
935 void readplayerstartcvars()
941 // initialize starting values for players
944 start_ammo_shells = 0;
945 start_ammo_nails = 0;
946 start_ammo_rockets = 0;
947 start_ammo_cells = 0;
948 start_health = cvar("g_balance_health_start");
949 start_armorvalue = cvar("g_balance_armor_start");
952 s = cvar_string("g_weaponarena");
958 g_weaponarena_list = "All Weapons";
959 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
961 e = get_weaponinfo(j);
962 g_weaponarena |= e.weapons;
963 weapon_action(e.weapon, WR_PRECACHE);
966 else if (s == "most")
968 g_weaponarena_list = "Most Weapons";
969 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
971 e = get_weaponinfo(j);
972 if (e.spawnflags & WEP_FLAG_NORMAL)
974 g_weaponarena |= e.weapons;
975 weapon_action(e.weapon, WR_PRECACHE);
979 else if (s == "none")
981 g_weaponarena_list = "No Weapons";
982 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
986 t = tokenize_console(s);
987 g_weaponarena_list = "";
988 for (i = 0; i < t; ++i)
991 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
993 e = get_weaponinfo(j);
996 g_weaponarena |= e.weapons;
997 weapon_action(e.weapon, WR_PRECACHE);
998 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
1004 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
1007 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
1011 g_weaponarena_random = cvar("g_weaponarena_random");
1013 g_weaponarena_random = 0;
1018 // will be done later
1019 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1020 if (NixNex_CanChooseWeapon(i))
1021 weapon_action(i, WR_PRECACHE);
1022 if(!cvar("g_use_ammunition"))
1023 start_items |= IT_UNLIMITED_AMMO;
1025 else if (g_weaponarena)
1027 start_weapons = g_weaponarena;
1028 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
1029 start_ammo_rockets = 999;
1030 if (g_weaponarena & WEPBIT_SHOTGUN)
1031 start_ammo_shells = 999;
1032 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
1033 start_ammo_cells = 999;
1034 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
1035 start_ammo_nails = 999;
1036 if (g_weaponarena & WEPBIT_HOOK)
1037 start_ammo_fuel = 999;
1038 start_items |= IT_UNLIMITED_AMMO;
1040 else if (g_minstagib)
1043 start_armorvalue = 0;
1044 start_weapons = WEPBIT_MINSTANEX;
1045 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
1046 start_ammo_cells = cvar("g_minstagib_ammo_start");
1047 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
1048 start_ammo_fuel = cvar("g_start_ammo_fuel");
1050 if (g_minstagib_invis_alpha <= 0)
1051 g_minstagib_invis_alpha = -1;
1057 start_ammo_shells = cvar("g_lms_start_ammo_shells");
1058 start_ammo_nails = cvar("g_lms_start_ammo_nails");
1059 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
1060 start_ammo_cells = cvar("g_lms_start_ammo_cells");
1061 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
1062 start_health = cvar("g_lms_start_health");
1063 start_armorvalue = cvar("g_lms_start_armor");
1065 else if (cvar("g_use_ammunition"))
1067 start_ammo_shells = cvar("g_start_ammo_shells");
1068 start_ammo_nails = cvar("g_start_ammo_nails");
1069 start_ammo_rockets = cvar("g_start_ammo_rockets");
1070 start_ammo_cells = cvar("g_start_ammo_cells");
1071 start_ammo_fuel = cvar("g_start_ammo_fuel");
1075 start_ammo_shells = cvar("g_pickup_shells_max");
1076 start_ammo_nails = cvar("g_pickup_nails_max");
1077 start_ammo_rockets = cvar("g_pickup_rockets_max");
1078 start_ammo_cells = cvar("g_pickup_cells_max");
1079 start_ammo_fuel = cvar("g_pickup_fuel_max");
1080 start_items |= IT_UNLIMITED_AMMO;
1083 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1085 e = get_weaponinfo(i);
1086 if(want_weapon("g_start_weapon_", e, FALSE))
1088 start_weapons |= e.weapons;
1089 weapon_action(e.weapon, WR_PRECACHE);
1096 warmup_start_ammo_shells = start_ammo_shells;
1097 warmup_start_ammo_nails = start_ammo_nails;
1098 warmup_start_ammo_rockets = start_ammo_rockets;
1099 warmup_start_ammo_cells = start_ammo_cells;
1100 warmup_start_ammo_fuel = start_ammo_fuel;
1101 warmup_start_health = start_health;
1102 warmup_start_armorvalue = start_armorvalue;
1103 warmup_start_weapons = start_weapons;
1105 if (!g_weaponarena && !g_nixnex && !g_minstagib && !g_ca)
1107 if (cvar("g_use_ammunition"))
1109 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1110 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1111 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1112 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1113 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1115 warmup_start_health = cvar("g_warmup_start_health");
1116 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1117 warmup_start_weapons = 0;
1118 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1120 e = get_weaponinfo(i);
1121 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
1123 warmup_start_weapons |= e.weapons;
1124 weapon_action(e.weapon, WR_PRECACHE);
1130 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1132 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1133 start_items |= IT_FUEL_REGEN;
1134 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1135 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1139 start_items |= IT_JETPACK;
1141 if (g_weapon_stay == 2)
1143 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1144 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1145 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1146 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1147 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1148 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1149 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1150 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1151 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1152 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1155 start_ammo_shells = max(0, start_ammo_shells);
1156 start_ammo_nails = max(0, start_ammo_nails);
1157 start_ammo_cells = max(0, start_ammo_cells);
1158 start_ammo_rockets = max(0, start_ammo_rockets);
1159 start_ammo_fuel = max(0, start_ammo_fuel);
1161 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1162 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1163 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1164 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1165 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1169 float g_bugrigs_planar_movement;
1170 float g_bugrigs_planar_movement_car_jumping;
1171 float g_bugrigs_reverse_spinning;
1172 float g_bugrigs_reverse_speeding;
1173 float g_bugrigs_reverse_stopping;
1174 float g_bugrigs_air_steering;
1175 float g_bugrigs_angle_smoothing;
1176 float g_bugrigs_friction_floor;
1177 float g_bugrigs_friction_brake;
1178 float g_bugrigs_friction_air;
1179 float g_bugrigs_accel;
1180 float g_bugrigs_speed_ref;
1181 float g_bugrigs_speed_pow;
1182 float g_bugrigs_steer;
1184 float g_touchexplode;
1185 float g_touchexplode_radius;
1186 float g_touchexplode_damage;
1187 float g_touchexplode_edgedamage;
1188 float g_touchexplode_force;
1195 float sv_pitch_fixyaw;
1197 float sv_accuracy_data_share;
1199 void readlevelcvars(void)
1201 g_bugrigs = cvar("g_bugrigs");
1202 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1203 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1204 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1205 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1206 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1207 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1208 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1209 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1210 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1211 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1212 g_bugrigs_accel = cvar("g_bugrigs_accel");
1213 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1214 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1215 g_bugrigs_steer = cvar("g_bugrigs_steer");
1217 g_touchexplode = cvar("g_touchexplode");
1218 g_touchexplode_radius = cvar("g_touchexplode_radius");
1219 g_touchexplode_damage = cvar("g_touchexplode_damage");
1220 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1221 g_touchexplode_force = cvar("g_touchexplode_force");
1223 #ifdef ALLOW_FORCEMODELS
1224 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1226 sv_loddistance1 = cvar("sv_loddistance1");
1227 sv_loddistance2 = cvar("sv_loddistance2");
1229 if(sv_loddistance2 <= sv_loddistance1)
1230 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1232 sv_clones = cvar("sv_clones");
1233 sv_gentle = cvar("sv_gentle");
1234 sv_foginterval = cvar("sv_foginterval");
1235 g_cloaked = cvar("g_cloaked");
1236 g_jump_grunt = cvar("g_jump_grunt");
1237 g_footsteps = cvar("g_footsteps");
1238 g_grappling_hook = cvar("g_grappling_hook");
1239 g_jetpack = cvar("g_jetpack");
1240 g_laserguided_missile = cvar("g_laserguided_missile");
1241 g_midair = cvar("g_midair");
1242 g_minstagib = cvar("g_minstagib");
1243 g_nixnex = cvar("g_nixnex");
1244 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1245 g_norecoil = cvar("g_norecoil");
1246 g_vampire = cvar("g_vampire");
1247 g_bloodloss = cvar("g_bloodloss");
1248 sv_maxidle = cvar("sv_maxidle");
1249 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1250 sv_pogostick = cvar("sv_pogostick");
1251 sv_doublejump = cvar("sv_doublejump");
1252 g_ctf_reverse = cvar("g_ctf_reverse");
1253 sv_autotaunt = cvar("sv_autotaunt");
1254 sv_taunt = cvar("sv_taunt");
1256 inWarmupStage = cvar("g_warmup");
1257 g_warmup_limit = cvar("g_warmup_limit");
1258 g_warmup_allguns = cvar("g_warmup_allguns");
1259 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1261 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1262 inWarmupStage = 0; // these modes cannot work together, sorry
1264 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1265 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1266 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1267 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1268 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1269 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1270 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1271 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1272 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1273 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1274 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1275 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1277 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1278 if (g_nixnex) g_weaponarena = 0;
1281 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1282 g_weaponratefactor = cvar("g_weaponratefactor");
1283 g_weapondamagefactor = cvar("g_weapondamagefactor");
1284 g_weaponforcefactor = cvar("g_weaponforcefactor");
1285 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1287 g_pickup_shells = cvar("g_pickup_shells");
1288 g_pickup_shells_max = cvar("g_pickup_shells_max");
1289 g_pickup_nails = cvar("g_pickup_nails");
1290 g_pickup_nails_max = cvar("g_pickup_nails_max");
1291 g_pickup_rockets = cvar("g_pickup_rockets");
1292 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1293 g_pickup_cells = cvar("g_pickup_cells");
1294 g_pickup_cells_max = cvar("g_pickup_cells_max");
1295 g_pickup_fuel = cvar("g_pickup_fuel");
1296 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1297 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1298 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1299 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1300 g_pickup_armormedium = cvar("g_pickup_armormedium");
1301 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1302 g_pickup_armorbig = cvar("g_pickup_armorbig");
1303 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1304 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1305 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1306 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1307 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1308 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1309 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1310 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1311 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1312 g_pickup_healthmega = cvar("g_pickup_healthmega");
1313 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1315 g_pinata = cvar("g_pinata");
1317 g_weapon_stay = cvar("g_weapon_stay");
1319 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1322 g_ghost_items = cvar("g_ghost_items");
1324 if(g_ghost_items >= 1)
1325 g_ghost_items = 0.13; // default alpha value
1327 if not(inWarmupStage && !g_ca)
1328 game_starttime = cvar("g_start_delay");
1330 sv_pitch_min = cvar("sv_pitch_min");
1331 sv_pitch_max = cvar("sv_pitch_max");
1332 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1334 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
1336 readplayerstartcvars();
1340 // TODO sound pack system
1343 string precache_sound_builtin (string s) = #19;
1344 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1345 string precache_sound(string s)
1347 return precache_sound_builtin(strcat(soundpack, s));
1349 void play2(entity e, string filename)
1351 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1353 void sound(entity e, float chan, string samp, float vol, float atten)
1355 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1360 string precache_sound (string s) = #19;
1361 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1362 float precache_sound_index (string s) = #19;
1364 #define SND_VOLUME 1
1365 #define SND_ATTENUATION 2
1366 #define SND_LARGEENTITY 8
1367 #define SND_LARGESOUND 16
1369 float sound_allowed(float dest, entity e)
1371 // sounds from world may always pass
1374 if (e.classname == "body")
1376 if (e.owner && e.owner != e)
1381 // sounds to self may always pass
1382 if (dest == MSG_ONE)
1383 if (e == msg_entity)
1385 // sounds by players can be removed
1386 if (cvar("bot_sound_monopoly"))
1387 if (clienttype(e) == CLIENTTYPE_REAL)
1389 // anything else may pass
1393 void sound(entity e, float chan, string samp, float vol, float atten)
1395 if (!sound_allowed(MSG_BROADCAST, e))
1397 sound_builtin(e, chan, samp, vol, atten);
1399 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1403 if (!sound_allowed(dest, e))
1406 entno = num_for_edict(e);
1407 idx = precache_sound_index(samp);
1412 atten = floor(atten * 64);
1413 vol = floor(vol * 255);
1416 sflags |= SND_VOLUME;
1418 sflags |= SND_ATTENUATION;
1420 sflags |= SND_LARGEENTITY;
1422 sflags |= SND_LARGESOUND;
1424 WriteByte(dest, SVC_SOUND);
1425 WriteByte(dest, sflags);
1426 if (sflags & SND_VOLUME)
1427 WriteByte(dest, vol);
1428 if (sflags & SND_ATTENUATION)
1429 WriteByte(dest, atten);
1430 if (sflags & SND_LARGEENTITY)
1432 WriteShort(dest, entno);
1433 WriteByte(dest, chan);
1437 WriteShort(dest, entno * 8 + chan);
1439 if (sflags & SND_LARGESOUND)
1440 WriteShort(dest, idx);
1442 WriteByte(dest, idx);
1444 WriteCoord(dest, o_x);
1445 WriteCoord(dest, o_y);
1446 WriteCoord(dest, o_z);
1448 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1452 if (!sound_allowed(dest, e))
1455 o = e.origin + 0.5 * (e.mins + e.maxs);
1456 soundtoat(dest, e, o, chan, samp, vol, atten);
1458 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1460 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1462 void stopsoundto(float dest, entity e, float chan)
1466 if (!sound_allowed(dest, e))
1469 entno = num_for_edict(e);
1474 idx = precache_sound_index("misc/null.wav");
1475 sflags = SND_LARGEENTITY;
1477 sflags |= SND_LARGESOUND;
1478 WriteByte(dest, SVC_SOUND);
1479 WriteByte(dest, sflags);
1480 WriteShort(dest, entno);
1481 WriteByte(dest, chan);
1482 if (sflags & SND_LARGESOUND)
1483 WriteShort(dest, idx);
1485 WriteByte(dest, idx);
1486 WriteCoord(dest, e.origin_x);
1487 WriteCoord(dest, e.origin_y);
1488 WriteCoord(dest, e.origin_z);
1492 WriteByte(dest, SVC_STOPSOUND);
1493 WriteShort(dest, entno * 8 + chan);
1496 void stopsound(entity e, float chan)
1498 if (!sound_allowed(MSG_BROADCAST, e))
1501 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1502 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1505 void play2(entity e, string filename)
1507 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1509 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1512 .float announcetime;
1513 float announce(entity player, string msg)
1515 if (time > player.announcetime)
1516 if (clienttype(player) == CLIENTTYPE_REAL)
1518 player.announcetime = time + 0.8;
1524 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1525 float spamsound(entity e, float chan, string samp, float vol, float atten)
1527 if (!sound_allowed(MSG_BROADCAST, e))
1530 if (time > e.announcetime)
1532 e.announcetime = time;
1533 sound(e, chan, samp, vol, atten);
1539 void play2team(float t, string filename)
1543 if (cvar("bot_sound_monopoly"))
1546 FOR_EACH_REALPLAYER(head)
1549 play2(head, filename);
1553 void play2all(string samp)
1555 if (cvar("bot_sound_monopoly"))
1558 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1561 void PrecachePlayerSounds(string f);
1562 void precache_all_models(string pattern)
1564 float globhandle, i, n;
1567 globhandle = search_begin(pattern, TRUE, FALSE);
1570 n = search_getsize(globhandle);
1571 for (i = 0; i < n; ++i)
1573 //print(search_getfilename(globhandle, i), "\n");
1574 f = search_getfilename(globhandle, i);
1577 if(substring(f, -9,5) == "_lod1")
1579 if(substring(f, -9,5) == "_lod2")
1581 if(!sv_loddistance1)
1583 PrecachePlayerSounds(strcat(f, ".sounds"));
1585 search_end(globhandle);
1590 // gamemode related things
1591 precache_model ("models/misc/chatbubble.spr");
1592 precache_model ("models/misc/teambubble.spr");
1595 precache_model ("models/runematch/curse.mdl");
1596 precache_model ("models/runematch/rune.mdl");
1599 #ifdef TTURRETS_ENABLED
1600 if (cvar("g_turrets"))
1604 // Precache all player models if desired
1605 if (cvar("sv_precacheplayermodels"))
1607 PrecachePlayerSounds("sound/player/default.sounds");
1608 precache_all_models("models/player/*.zym");
1609 precache_all_models("models/player/*.dpm");
1610 precache_all_models("models/player/*.md3");
1611 precache_all_models("models/player/*.psk");
1612 //precache_model("models/player/carni.zym");
1613 //precache_model("models/player/crash.zym");
1614 //precache_model("models/player/grunt.zym");
1615 //precache_model("models/player/headhunter.zym");
1616 //precache_model("models/player/insurrectionist.zym");
1617 //precache_model("models/player/jeandarc.zym");
1618 //precache_model("models/player/lurk.zym");
1619 //precache_model("models/player/lycanthrope.zym");
1620 //precache_model("models/player/marine.zym");
1621 //precache_model("models/player/nexus.zym");
1622 //precache_model("models/player/pyria.zym");
1623 //precache_model("models/player/shock.zym");
1624 //precache_model("models/player/skadi.zym");
1625 //precache_model("models/player/specop.zym");
1626 //precache_model("models/player/visitant.zym");
1629 if (cvar("sv_defaultcharacter"))
1632 s = cvar_string("sv_defaultplayermodel_red");
1636 PrecachePlayerSounds(strcat(s, ".sounds"));
1638 s = cvar_string("sv_defaultplayermodel_blue");
1642 PrecachePlayerSounds(strcat(s, ".sounds"));
1644 s = cvar_string("sv_defaultplayermodel_yellow");
1648 PrecachePlayerSounds(strcat(s, ".sounds"));
1650 s = cvar_string("sv_defaultplayermodel_pink");
1654 PrecachePlayerSounds(strcat(s, ".sounds"));
1656 s = cvar_string("sv_defaultplayermodel");
1660 PrecachePlayerSounds(strcat(s, ".sounds"));
1666 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1667 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1670 // gore and miscellaneous sounds
1671 //precache_sound ("misc/h2ohit.wav");
1672 precache_model ("models/hook.md3");
1673 precache_sound ("misc/armorimpact.wav");
1674 precache_sound ("misc/bodyimpact1.wav");
1675 precache_sound ("misc/bodyimpact2.wav");
1676 precache_sound ("misc/gib.wav");
1677 precache_sound ("misc/gib_splat01.wav");
1678 precache_sound ("misc/gib_splat02.wav");
1679 precache_sound ("misc/gib_splat03.wav");
1680 precache_sound ("misc/gib_splat04.wav");
1681 precache_sound ("misc/hit.wav");
1682 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1683 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1684 precache_sound ("misc/null.wav");
1685 precache_sound ("misc/spawn.wav");
1686 precache_sound ("misc/talk.wav");
1687 precache_sound ("misc/teleport.wav");
1688 precache_sound ("misc/poweroff.wav");
1689 precache_sound ("player/lava.wav");
1690 precache_sound ("player/slime.wav");
1693 precache_sound ("misc/jetpack_fly.wav");
1695 // announcer sounds - male
1696 precache_sound ("announcer/male/electrobitch.wav");
1697 precache_sound ("announcer/male/airshot.wav");
1698 precache_sound ("announcer/male/03kills.wav");
1699 precache_sound ("announcer/male/05kills.wav");
1700 precache_sound ("announcer/male/10kills.wav");
1701 precache_sound ("announcer/male/15kills.wav");
1702 precache_sound ("announcer/male/20kills.wav");
1703 precache_sound ("announcer/male/25kills.wav");
1704 precache_sound ("announcer/male/30kills.wav");
1705 precache_sound ("announcer/male/botlike.wav");
1706 precache_sound ("announcer/male/yoda.wav");
1707 precache_sound ("announcer/male/amazing.wav");
1708 precache_sound ("announcer/male/awesome.wav");
1709 precache_sound ("announcer/male/headshot.wav");
1710 precache_sound ("announcer/male/impressive.wav");
1712 // announcer sounds - robotic
1713 precache_sound ("announcer/robotic/prepareforbattle.wav");
1714 precache_sound ("announcer/robotic/begin.wav");
1715 precache_sound ("announcer/robotic/timeoutcalled.wav");
1716 precache_sound ("announcer/robotic/1fragleft.wav");
1717 precache_sound ("announcer/robotic/2fragsleft.wav");
1718 precache_sound ("announcer/robotic/3fragsleft.wav");
1719 precache_sound ("announcer/robotic/terminated.wav");
1722 precache_sound ("announcer/robotic/lastsecond.wav");
1723 precache_sound ("announcer/robotic/narrowly.wav");
1726 precache_model ("models/sprites/0.spr32");
1727 precache_model ("models/sprites/1.spr32");
1728 precache_model ("models/sprites/2.spr32");
1729 precache_model ("models/sprites/3.spr32");
1730 precache_model ("models/sprites/4.spr32");
1731 precache_model ("models/sprites/5.spr32");
1732 precache_model ("models/sprites/6.spr32");
1733 precache_model ("models/sprites/7.spr32");
1734 precache_model ("models/sprites/8.spr32");
1735 precache_model ("models/sprites/9.spr32");
1736 precache_model ("models/sprites/10.spr32");
1737 precache_sound ("announcer/robotic/1.wav");
1738 precache_sound ("announcer/robotic/2.wav");
1739 precache_sound ("announcer/robotic/3.wav");
1740 precache_sound ("announcer/robotic/4.wav");
1741 precache_sound ("announcer/robotic/5.wav");
1742 precache_sound ("announcer/robotic/6.wav");
1743 precache_sound ("announcer/robotic/7.wav");
1744 precache_sound ("announcer/robotic/8.wav");
1745 precache_sound ("announcer/robotic/9.wav");
1746 precache_sound ("announcer/robotic/10.wav");
1748 // common weapon precaches
1749 precache_sound ("weapons/weapon_switch.wav");
1750 precache_sound ("weapons/weaponpickup.wav");
1751 precache_sound ("weapons/unavailable.wav");
1752 if (g_grappling_hook)
1754 precache_sound ("weapons/hook_fire.wav"); // hook
1755 precache_sound ("weapons/hook_impact.wav"); // hook
1758 if (cvar("sv_precacheweapons") || g_nixnex)
1760 //precache weapon models/sounds
1763 while (wep <= WEP_LAST)
1765 weapon_action(wep, WR_PRECACHE);
1770 precache_model("models/elaser.mdl");
1771 precache_model("models/laser.mdl");
1772 precache_model("models/ebomb.mdl");
1775 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1777 if (!self.noise && self.music) // quake 3 uses the music field
1778 self.noise = self.music;
1780 // plays music for the level if there is any
1783 precache_sound (self.noise);
1784 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1789 // sorry, but using \ in macros breaks line numbers
1790 #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
1791 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1792 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1794 vector ExactTriggerHit_mins;
1795 vector ExactTriggerHit_maxs;
1796 float ExactTriggerHit_Recurse()
1802 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1805 if (trace_ent == self)
1810 se.solid = SOLID_NOT;
1811 f = ExactTriggerHit_Recurse();
1817 float ExactTriggerHit()
1821 if not(self.modelindex)
1825 self.solid = SOLID_BSP;
1826 ExactTriggerHit_mins = other.absmin;
1827 ExactTriggerHit_maxs = other.absmax;
1828 f = ExactTriggerHit_Recurse();
1834 // WARNING: this kills the trace globals
1835 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1836 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1838 #define INITPRIO_FIRST 0
1839 #define INITPRIO_GAMETYPE 0
1840 #define INITPRIO_GAMETYPE_FALLBACK 1
1841 #define INITPRIO_CVARS 5
1842 #define INITPRIO_FINDTARGET 10
1843 #define INITPRIO_DROPTOFLOOR 20
1844 #define INITPRIO_SETLOCATION 90
1845 #define INITPRIO_LINKDOORS 91
1846 #define INITPRIO_LAST 99
1848 .void(void) initialize_entity;
1849 .float initialize_entity_order;
1850 .entity initialize_entity_next;
1851 entity initialize_entity_first;
1853 void make_safe_for_remove(entity e)
1855 if (e.initialize_entity)
1858 for (ent = initialize_entity_first; ent; )
1860 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1862 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1863 // skip it in linked list
1866 prev.initialize_entity_next = ent.initialize_entity_next;
1867 ent = prev.initialize_entity_next;
1871 initialize_entity_first = ent.initialize_entity_next;
1872 ent = initialize_entity_first;
1878 ent = ent.initialize_entity_next;
1884 void objerror(string s)
1886 make_safe_for_remove(self);
1887 objerror_builtin(s);
1890 void remove_unsafely(entity e)
1895 void remove_safely(entity e)
1897 make_safe_for_remove(e);
1901 void InitializeEntity(entity e, void(void) func, float order)
1905 if (!e || e.initialize_entity)
1907 // make a proxy initializer entity
1911 e.classname = "initialize_entity";
1915 e.initialize_entity = func;
1916 e.initialize_entity_order = order;
1918 cur = initialize_entity_first;
1921 if (!cur || cur.initialize_entity_order > order)
1923 // insert between prev and cur
1925 prev.initialize_entity_next = e;
1927 initialize_entity_first = e;
1928 e.initialize_entity_next = cur;
1932 cur = cur.initialize_entity_next;
1935 void InitializeEntitiesRun()
1938 startoflist = initialize_entity_first;
1939 initialize_entity_first = world;
1940 for (self = startoflist; self; )
1943 var void(void) func;
1944 e = self.initialize_entity_next;
1945 func = self.initialize_entity;
1946 self.initialize_entity_order = 0;
1947 self.initialize_entity = func_null;
1948 self.initialize_entity_next = world;
1949 if (self.classname == "initialize_entity")
1953 remove_builtin(self);
1956 //dprint("Delayed initialization: ", self.classname, "\n");
1962 .float uncustomizeentityforclient_set;
1963 .void(void) uncustomizeentityforclient;
1964 void(void) SUB_Nullpointer = #0;
1965 void UncustomizeEntitiesRun()
1969 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1970 self.uncustomizeentityforclient();
1973 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1975 e.customizeentityforclient = customizer;
1976 e.uncustomizeentityforclient = uncustomizer;
1977 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1981 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1984 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1988 if (e.classname == "")
1989 e.classname = "net_linked";
1991 if (e.model == "" || self.modelindex == 0)
1995 setmodel(e, "null");
1999 e.SendEntity = sendfunc;
2000 e.SendFlags = 0xFFFFFF;
2003 e.effects |= EF_NODEPTHTEST;
2007 e.nextthink = time + dt;
2008 e.think = SUB_Remove;
2012 void adaptor_think2touch()
2021 void adaptor_think2use()
2033 // deferred dropping
2034 void DropToFloor_Handler()
2036 droptofloor_builtin();
2037 self.dropped_origin = self.origin;
2042 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
2047 float trace_hits_box_a0, trace_hits_box_a1;
2049 float trace_hits_box_1d(float end, float thmi, float thma)
2053 // just check if x is in range
2061 // do the trace with respect to x
2062 // 0 -> end has to stay in thmi -> thma
2063 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
2064 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
2065 if (trace_hits_box_a0 > trace_hits_box_a1)
2071 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
2076 // now it is a trace from 0 to end
2078 trace_hits_box_a0 = 0;
2079 trace_hits_box_a1 = 1;
2081 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
2083 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
2085 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
2091 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
2093 return trace_hits_box(start, end, thmi - ma, thma - mi);
2096 float SUB_NoImpactCheck()
2098 // zero hitcontents = this is not the real impact, but either the
2099 // mirror-impact of something hitting the projectile instead of the
2100 // projectile hitting the something, or a touchareagrid one. Neither of
2101 // these stop the projectile from moving, so...
2102 if(trace_dphitcontents == 0)
2104 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
2107 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2109 if (other == world && self.size != '0 0 0')
2112 tic = self.velocity * sys_frametime;
2113 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
2114 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
2115 if (trace_fraction >= 1)
2117 dprint("Odd... did not hit...?\n");
2119 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2121 dprint("Detected and prevented the sky-grapple bug.\n");
2129 #define SUB_OwnerCheck() (other && (other == self.owner))
2131 #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)
2133 float MAX_IPBAN_URIS = 16;
2135 float URI_GET_DISCARD = 0;
2136 float URI_GET_IPBAN = 1;
2137 float URI_GET_IPBAN_END = 16;
2139 void URI_Get_Callback(float id, float status, string data)
2141 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2143 dprint("\nEnd of data.\n");
2145 if (id == URI_GET_DISCARD)
2149 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2152 OnlineBanList_URI_Get_Callback(id, status, data);
2156 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2160 void print_to(entity e, string s)
2163 sprint(e, strcat(s, "\n"));
2182 for (i = 0; i < MapInfo_count; ++i)
2184 if (MapInfo_Get_ByID(i))
2186 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2189 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2190 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2198 for (i = 0; i < MapInfo_count; ++i)
2200 if (MapInfo_Get_ByID(i))
2202 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2205 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2206 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2214 for (i = 0; i < MapInfo_count; ++i)
2216 if (MapInfo_Get_ByID(i))
2218 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2221 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2222 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2228 MapInfo_ClearTemps();
2231 return "No records are available on this server.\n";
2233 return strcat("Records on this server:\n", s);
2236 string getrankings()
2249 for (i = 1; i <= RANKINGS_CNT; ++i)
2251 t = race_GetTime(i);
2254 n = race_GetName(i);
2255 p = race_PlaceName(i);
2256 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
2259 MapInfo_ClearTemps();
2262 return strcat("No records are available for the map: ", map, "\n");
2264 return strcat("Records for ", map, ":\n", s);
2267 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2270 vector start, org, delta, end, enddown, mstart;
2272 m = e.dphitcontentsmask;
2273 e.dphitcontentsmask = goodcontents | badcontents;
2276 delta = world.maxs - world.mins;
2278 for (i = 0; i < attempts; ++i)
2280 start_x = org_x + random() * delta_x;
2281 start_y = org_y + random() * delta_y;
2282 start_z = org_z + random() * delta_z;
2284 // rule 1: start inside world bounds, and outside
2285 // solid, and don't start from somewhere where you can
2286 // fall down to evil
2287 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2288 if (trace_fraction >= 1)
2290 if (trace_startsolid)
2292 if (trace_dphitcontents & badcontents)
2294 if (trace_dphitq3surfaceflags & badsurfaceflags)
2297 // rule 2: if we are too high, lower the point
2298 if (trace_fraction * delta_z > maxaboveground)
2299 start = trace_endpos + '0 0 1' * maxaboveground;
2300 enddown = trace_endpos;
2302 // rule 3: make sure we aren't outside the map. This only works
2303 // for somewhat well formed maps. A good rule of thumb is that
2304 // the map should have a convex outside hull.
2305 // these can be traceLINES as we already verified the starting box
2306 mstart = start + 0.5 * (e.mins + e.maxs);
2307 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2308 if (trace_fraction >= 1)
2310 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2311 if (trace_fraction >= 1)
2313 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2314 if (trace_fraction >= 1)
2316 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2317 if (trace_fraction >= 1)
2319 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2320 if (trace_fraction >= 1)
2323 // find a random vector to "look at"
2324 end_x = org_x + random() * delta_x;
2325 end_y = org_y + random() * delta_y;
2326 end_z = org_z + random() * delta_z;
2327 end = start + normalize(end - start) * vlen(delta);
2329 // rule 4: start TO end must not be too short
2330 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2331 if (trace_startsolid)
2333 if (trace_fraction < minviewdistance / vlen(delta))
2336 // rule 5: don't want to look at sky
2337 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2340 // rule 6: we must not end up in trigger_hurt
2341 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2343 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2350 e.dphitcontentsmask = m;
2354 setorigin(e, start);
2355 e.angles = vectoangles(end - start);
2356 dprint("Needed ", ftos(i + 1), " attempts\n");
2363 float zcurveparticles_effectno;
2364 vector zcurveparticles_start;
2365 float zcurveparticles_spd;
2367 void endzcurveparticles()
2369 if(zcurveparticles_effectno)
2372 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2374 zcurveparticles_effectno = 0;
2377 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2379 spd = bound(0, floor(spd / 16), 32767);
2380 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2382 endzcurveparticles();
2383 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2384 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2385 WriteShort(MSG_BROADCAST, effectno);
2386 WriteCoord(MSG_BROADCAST, start_x);
2387 WriteCoord(MSG_BROADCAST, start_y);
2388 WriteCoord(MSG_BROADCAST, start_z);
2389 zcurveparticles_effectno = effectno;
2390 zcurveparticles_start = start;
2393 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2394 WriteCoord(MSG_BROADCAST, end_x);
2395 WriteCoord(MSG_BROADCAST, end_y);
2396 WriteCoord(MSG_BROADCAST, end_z);
2397 WriteCoord(MSG_BROADCAST, end_dz);
2398 zcurveparticles_spd = spd;
2401 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2404 vector vecxy, velxy;
2406 vecxy = end - start;
2411 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2413 endzcurveparticles();
2414 trailparticles(world, effectno, start, end);
2418 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2419 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2422 string GetGametype(); // g_world.qc
2423 void write_recordmarker(entity pl, float tstart, float dt)
2425 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2427 // also write a marker into demo files for demotc-race-record-extractor to find
2430 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2431 " ", ftos(tstart), " ", ftos(dt), "\n"));
2434 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2436 switch(self.owner.cvar_cl_gunalign)
2447 if(allowcenter) // 2: allow center handedness
2460 if(allowcenter) // 2: allow center handedness
2476 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2481 if (cvar("g_shootfromeye"))
2485 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2493 else if (cvar("g_shootfromcenter"))
2497 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2505 else if (cvar("g_shootfromclient"))
2507 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2509 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2524 void attach_sameorigin(entity e, entity to, string tag)
2526 vector org, t_forward, t_left, t_up, e_forward, e_up;
2533 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2534 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2535 t_forward = v_forward * tagscale;
2536 t_left = v_right * -tagscale;
2537 t_up = v_up * tagscale;
2539 e.origin_x = org * t_forward;
2540 e.origin_y = org * t_left;
2541 e.origin_z = org * t_up;
2543 // current forward and up directions
2544 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2545 e.angles_x = -e.angles_x;
2546 fixedmakevectors(e.angles);
2548 // untransform forward, up!
2549 e_forward_x = v_forward * t_forward;
2550 e_forward_y = v_forward * t_left;
2551 e_forward_z = v_forward * t_up;
2552 e_up_x = v_up * t_forward;
2553 e_up_y = v_up * t_left;
2554 e_up_z = v_up * t_up;
2556 e.angles = fixedvectoangles2(e_forward, e_up);
2557 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2558 e.angles_x = -e.angles_x;
2560 setattachment(e, to, tag);
2561 setorigin(e, e.origin);
2564 void detach_sameorigin(entity e)
2567 org = gettaginfo(e, 0);
2568 e.angles = fixedvectoangles2(v_forward, v_up);
2569 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2570 e.angles_x = -e.angles_x;
2572 setattachment(e, world, "");
2573 setorigin(e, e.origin);
2576 void follow_sameorigin(entity e, entity to)
2578 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2579 e.aiment = to; // make the hole follow bmodel
2580 e.punchangle = to.angles; // the original angles of bmodel
2581 e.view_ofs = e.origin - to.origin; // relative origin
2582 e.v_angle = e.angles - to.angles; // relative angles
2585 void unfollow_sameorigin(entity e)
2587 e.movetype = MOVETYPE_NONE;
2590 entity gettaginfo_relative_ent;
2591 vector gettaginfo_relative(entity e, float tag)
2593 if (!gettaginfo_relative_ent)
2595 gettaginfo_relative_ent = spawn();
2596 gettaginfo_relative_ent.effects = EF_NODRAW;
2598 gettaginfo_relative_ent.model = e.model;
2599 gettaginfo_relative_ent.modelindex = e.modelindex;
2600 gettaginfo_relative_ent.frame = e.frame;
2601 return gettaginfo(gettaginfo_relative_ent, tag);
2604 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2608 if (pl.soundentity.cnt & p)
2610 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2611 pl.soundentity.cnt |= p;
2614 void SoundEntity_StopSound(entity pl, float chan)
2618 if (pl.soundentity.cnt & p)
2620 stopsoundto(MSG_ALL, pl.soundentity, chan);
2621 pl.soundentity.cnt &~= p;
2625 void SoundEntity_Attach(entity pl)
2627 pl.soundentity = spawn();
2628 pl.soundentity.classname = "soundentity";
2629 pl.soundentity.owner = pl;
2630 setattachment(pl.soundentity, pl, "");
2631 setmodel(pl.soundentity, "null");
2634 void SoundEntity_Detach(entity pl)
2637 for (i = 0; i <= 7; ++i)
2638 SoundEntity_StopSound(pl, i);
2642 float ParseCommandPlayerSlotTarget_firsttoken;
2643 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2651 ParseCommandPlayerSlotTarget_firsttoken = -1;
2655 if (substring(argv(idx), 0, 1) == "#")
2657 s = substring(argv(idx), 1, -1);
2665 ParseCommandPlayerSlotTarget_firsttoken = idx;
2666 if (s == ftos(stof(s)))
2668 e = edict_num(stof(s));
2669 if (e.flags & FL_CLIENT)
2675 // it must be a nick name
2678 ParseCommandPlayerSlotTarget_firsttoken = idx;
2681 FOR_EACH_CLIENT(head)
2682 if (head.netname == s)
2690 s = strdecolorize(s);
2692 FOR_EACH_CLIENT(head)
2693 if (strdecolorize(head.netname) == s)
2708 float modeleffect_SendEntity(entity to, float sf)
2711 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2714 if(self.velocity != '0 0 0')
2716 if(self.angles != '0 0 0')
2718 if(self.avelocity != '0 0 0')
2721 WriteByte(MSG_ENTITY, f);
2722 WriteShort(MSG_ENTITY, self.modelindex);
2723 WriteByte(MSG_ENTITY, self.skin);
2724 WriteByte(MSG_ENTITY, self.frame);
2725 WriteCoord(MSG_ENTITY, self.origin_x);
2726 WriteCoord(MSG_ENTITY, self.origin_y);
2727 WriteCoord(MSG_ENTITY, self.origin_z);
2730 WriteCoord(MSG_ENTITY, self.velocity_x);
2731 WriteCoord(MSG_ENTITY, self.velocity_y);
2732 WriteCoord(MSG_ENTITY, self.velocity_z);
2736 WriteCoord(MSG_ENTITY, self.angles_x);
2737 WriteCoord(MSG_ENTITY, self.angles_y);
2738 WriteCoord(MSG_ENTITY, self.angles_z);
2742 WriteCoord(MSG_ENTITY, self.avelocity_x);
2743 WriteCoord(MSG_ENTITY, self.avelocity_y);
2744 WriteCoord(MSG_ENTITY, self.avelocity_z);
2746 WriteShort(MSG_ENTITY, self.scale * 256.0);
2747 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2748 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2749 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2750 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2755 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)
2760 e.classname = "modeleffect";
2768 e.teleport_time = t1;
2772 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2776 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2779 sz = max(e.scale, e.scale2);
2780 setsize(e, e.mins * sz, e.maxs * sz);
2781 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2784 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2786 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2789 float randombit(float bits)
2791 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2800 for(f = 1; f <= bits; f *= 2)
2809 r = (r - 1) / (n - 1);
2816 float randombits(float bits, float k, float error_return)
2820 while(k > 0 && bits != r)
2822 r += randombit(bits - r);
2831 void randombit_test(float bits, float iter)
2835 print(ftos(randombit(bits)), "\n");
2840 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2842 if(halflifedist > 0)
2843 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2844 else if(halflifedist < 0)
2845 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2854 #define cvar_string_normal cvar_string_builtin
2855 #define cvar_normal cvar_builtin
2857 string cvar_string_normal(string n)
2859 if not(cvar_type(n) & 1)
2860 backtrace(strcat("Attempt to access undefined cvar: ", n));
2861 return cvar_string_builtin(n);
2864 float cvar_normal(string n)
2866 return stof(cvar_string_normal(n));
2869 #define cvar_set_normal cvar_set_builtin
2877 oself.think = SUB_Remove;
2878 oself.nextthink = time;
2884 Execute func() after time + fdelay.
2885 self when func is executed = self when defer is called
2887 void defer(float fdelay, void() func)
2894 e.think = defer_think;
2895 e.nextthink = time + fdelay;